From 159b6e9f144c7afdf3ad95c29d1fede9626fa8b1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 3 Feb 2013 20:21:00 +0100 Subject: hw: move char backends to backends/ Braille and msmouse support is in hw/, but it is not hardware. Move it to the backends/ directory. Signed-off-by: Paolo Bonzini --- backends/Makefile.objs | 4 + backends/baum.c | 627 +++++++++++++++++++++++++++++++++++++++++++++++++ backends/msmouse.c | 78 ++++++ hw/Makefile.objs | 4 +- hw/baum.c | 627 ------------------------------------------------- hw/baum.h | 30 --- hw/msmouse.c | 78 ------ hw/msmouse.h | 7 - include/char/baum.h | 30 +++ include/char/msmouse.h | 7 + qemu-char.c | 4 +- vl.c | 2 +- 12 files changed, 750 insertions(+), 748 deletions(-) create mode 100644 backends/baum.c create mode 100644 backends/msmouse.c delete mode 100644 hw/baum.c delete mode 100644 hw/baum.h delete mode 100644 hw/msmouse.c delete mode 100644 hw/msmouse.h create mode 100644 include/char/baum.h create mode 100644 include/char/msmouse.h diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 883676106b..464bc3e220 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -1,2 +1,6 @@ common-obj-y += rng.o rng-egd.o common-obj-$(CONFIG_POSIX) += rng-random.o + +common-obj-y += msmouse.o +common-obj-$(CONFIG_BRLAPI) += baum.o +$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) diff --git a/backends/baum.c b/backends/baum.c new file mode 100644 index 0000000000..37ccca8211 --- /dev/null +++ b/backends/baum.c @@ -0,0 +1,627 @@ +/* + * QEMU Baum Braille Device + * + * Copyright (c) 2008 Samuel Thibault + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "char/char.h" +#include "qemu/timer.h" +#include "hw/usb.h" +#include "char/baum.h" +#include +#include +#include +#ifdef CONFIG_SDL +#include +#endif + +#if 0 +#define DPRINTF(fmt, ...) \ + printf(fmt, ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) +#endif + +#define ESC 0x1B + +#define BAUM_REQ_DisplayData 0x01 +#define BAUM_REQ_GetVersionNumber 0x05 +#define BAUM_REQ_GetKeys 0x08 +#define BAUM_REQ_SetMode 0x12 +#define BAUM_REQ_SetProtocol 0x15 +#define BAUM_REQ_GetDeviceIdentity 0x84 +#define BAUM_REQ_GetSerialNumber 0x8A + +#define BAUM_RSP_CellCount 0x01 +#define BAUM_RSP_VersionNumber 0x05 +#define BAUM_RSP_ModeSetting 0x11 +#define BAUM_RSP_CommunicationChannel 0x16 +#define BAUM_RSP_PowerdownSignal 0x17 +#define BAUM_RSP_HorizontalSensors 0x20 +#define BAUM_RSP_VerticalSensors 0x21 +#define BAUM_RSP_RoutingKeys 0x22 +#define BAUM_RSP_Switches 0x23 +#define BAUM_RSP_TopKeys 0x24 +#define BAUM_RSP_HorizontalSensor 0x25 +#define BAUM_RSP_VerticalSensor 0x26 +#define BAUM_RSP_RoutingKey 0x27 +#define BAUM_RSP_FrontKeys6 0x28 +#define BAUM_RSP_BackKeys6 0x29 +#define BAUM_RSP_CommandKeys 0x2B +#define BAUM_RSP_FrontKeys10 0x2C +#define BAUM_RSP_BackKeys10 0x2D +#define BAUM_RSP_EntryKeys 0x33 +#define BAUM_RSP_JoyStick 0x34 +#define BAUM_RSP_ErrorCode 0x40 +#define BAUM_RSP_InfoBlock 0x42 +#define BAUM_RSP_DeviceIdentity 0x84 +#define BAUM_RSP_SerialNumber 0x8A +#define BAUM_RSP_BluetoothName 0x8C + +#define BAUM_TL1 0x01 +#define BAUM_TL2 0x02 +#define BAUM_TL3 0x04 +#define BAUM_TR1 0x08 +#define BAUM_TR2 0x10 +#define BAUM_TR3 0x20 + +#define BUF_SIZE 256 + +typedef struct { + CharDriverState *chr; + + brlapi_handle_t *brlapi; + int brlapi_fd; + unsigned int x, y; + + uint8_t in_buf[BUF_SIZE]; + uint8_t in_buf_used; + uint8_t out_buf[BUF_SIZE]; + uint8_t out_buf_used, out_buf_ptr; + + QEMUTimer *cellCount_timer; +} BaumDriverState; + +/* Let's assume NABCC by default */ +static const uint8_t nabcc_translation[256] = { + [0] = ' ', +#ifndef BRLAPI_DOTS +#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \ + ((d1?BRLAPI_DOT1:0)|\ + (d2?BRLAPI_DOT2:0)|\ + (d3?BRLAPI_DOT3:0)|\ + (d4?BRLAPI_DOT4:0)|\ + (d5?BRLAPI_DOT5:0)|\ + (d6?BRLAPI_DOT6:0)|\ + (d7?BRLAPI_DOT7:0)|\ + (d8?BRLAPI_DOT8:0)) +#endif + [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a', + [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b', + [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c', + [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd', + [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e', + [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f', + [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g', + [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h', + [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i', + [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j', + [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k', + [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l', + [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm', + [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n', + [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o', + [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p', + [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q', + [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r', + [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's', + [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't', + [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u', + [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v', + [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w', + [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x', + [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y', + [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z', + + [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A', + [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B', + [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C', + [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D', + [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E', + [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F', + [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G', + [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H', + [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I', + [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J', + [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K', + [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L', + [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M', + [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N', + [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O', + [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P', + [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q', + [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R', + [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S', + [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T', + [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U', + [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V', + [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W', + [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X', + [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y', + [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z', + + [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0', + [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1', + [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2', + [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3', + [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4', + [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5', + [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6', + [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7', + [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8', + [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9', + + [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.', + [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+', + [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-', + [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*', + [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/', + [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(', + [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')', + + [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&', + [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#', + + [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',', + [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';', + [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':', + [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!', + [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?', + [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"', + [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'', + [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`', + [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^', + [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~', + [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[', + [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']', + [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{', + [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}', + [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=', + [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<', + [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>', + [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$', + [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%', + [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@', + [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|', + [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\', + [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_', +}; + +/* The serial port can receive more of our data */ +static void baum_accept_input(struct CharDriverState *chr) +{ + BaumDriverState *baum = chr->opaque; + int room, first; + + if (!baum->out_buf_used) + return; + room = qemu_chr_be_can_write(chr); + if (!room) + return; + if (room > baum->out_buf_used) + room = baum->out_buf_used; + + first = BUF_SIZE - baum->out_buf_ptr; + if (room > first) { + qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first); + baum->out_buf_ptr = 0; + baum->out_buf_used -= first; + room -= first; + } + qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room); + baum->out_buf_ptr += room; + baum->out_buf_used -= room; +} + +/* We want to send a packet */ +static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len) +{ + uint8_t io_buf[1 + 2 * len], *cur = io_buf; + int room; + *cur++ = ESC; + while (len--) + if ((*cur++ = *buf++) == ESC) + *cur++ = ESC; + room = qemu_chr_be_can_write(baum->chr); + len = cur - io_buf; + if (len <= room) { + /* Fits */ + qemu_chr_be_write(baum->chr, io_buf, len); + } else { + int first; + uint8_t out; + /* Can't fit all, send what can be, and store the rest. */ + qemu_chr_be_write(baum->chr, io_buf, room); + len -= room; + cur = io_buf + room; + if (len > BUF_SIZE - baum->out_buf_used) { + /* Can't even store it, drop the previous data... */ + assert(len <= BUF_SIZE); + baum->out_buf_used = 0; + baum->out_buf_ptr = 0; + } + out = baum->out_buf_ptr; + baum->out_buf_used += len; + first = BUF_SIZE - baum->out_buf_ptr; + if (len > first) { + memcpy(baum->out_buf + out, cur, first); + out = 0; + len -= first; + cur += first; + } + memcpy(baum->out_buf + out, cur, len); + } +} + +/* Called when the other end seems to have a wrong idea of our display size */ +static void baum_cellCount_timer_cb(void *opaque) +{ + BaumDriverState *baum = opaque; + uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y }; + DPRINTF("Timeout waiting for DisplayData, sending cell count\n"); + baum_write_packet(baum, cell_count, sizeof(cell_count)); +} + +/* Try to interpret a whole incoming packet */ +static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) +{ + const uint8_t *cur = buf; + uint8_t req = 0; + + if (!len--) + return 0; + if (*cur++ != ESC) { + while (*cur != ESC) { + if (!len--) + return 0; + cur++; + } + DPRINTF("Dropped %d bytes!\n", cur - buf); + } + +#define EAT(c) do {\ + if (!len--) \ + return 0; \ + if ((c = *cur++) == ESC) { \ + if (!len--) \ + return 0; \ + if (*cur++ != ESC) { \ + DPRINTF("Broken packet %#2x, tossing\n", req); \ + if (qemu_timer_pending(baum->cellCount_timer)) { \ + qemu_del_timer(baum->cellCount_timer); \ + baum_cellCount_timer_cb(baum); \ + } \ + return (cur - 2 - buf); \ + } \ + } \ +} while (0) + + EAT(req); + switch (req) { + case BAUM_REQ_DisplayData: + { + uint8_t cells[baum->x * baum->y], c; + uint8_t text[baum->x * baum->y]; + uint8_t zero[baum->x * baum->y]; + int cursor = BRLAPI_CURSOR_OFF; + int i; + + /* Allow 100ms to complete the DisplayData packet */ + qemu_mod_timer(baum->cellCount_timer, qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec() / 10); + for (i = 0; i < baum->x * baum->y ; i++) { + EAT(c); + cells[i] = c; + if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) + == (BRLAPI_DOT7|BRLAPI_DOT8)) { + cursor = i + 1; + c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); + } + if (!(c = nabcc_translation[c])) + c = '?'; + text[i] = c; + } + qemu_del_timer(baum->cellCount_timer); + + memset(zero, 0, sizeof(zero)); + + brlapi_writeArguments_t wa = { + .displayNumber = BRLAPI_DISPLAY_DEFAULT, + .regionBegin = 1, + .regionSize = baum->x * baum->y, + .text = (char *)text, + .textSize = baum->x * baum->y, + .andMask = zero, + .orMask = cells, + .cursor = cursor, + .charset = (char *)"ISO-8859-1", + }; + + if (brlapi__write(baum->brlapi, &wa) == -1) + brlapi_perror("baum brlapi_write"); + break; + } + case BAUM_REQ_SetMode: + { + uint8_t mode, setting; + DPRINTF("SetMode\n"); + EAT(mode); + EAT(setting); + /* ignore */ + break; + } + case BAUM_REQ_SetProtocol: + { + uint8_t protocol; + DPRINTF("SetProtocol\n"); + EAT(protocol); + /* ignore */ + break; + } + case BAUM_REQ_GetDeviceIdentity: + { + uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, + 'B','a','u','m',' ','V','a','r','i','o' }; + DPRINTF("GetDeviceIdentity\n"); + identity[11] = '0' + baum->x / 10; + identity[12] = '0' + baum->x % 10; + baum_write_packet(baum, identity, sizeof(identity)); + break; + } + case BAUM_REQ_GetVersionNumber: + { + uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ + DPRINTF("GetVersionNumber\n"); + baum_write_packet(baum, version, sizeof(version)); + break; + } + case BAUM_REQ_GetSerialNumber: + { + uint8_t serial[] = { BAUM_RSP_SerialNumber, + '0','0','0','0','0','0','0','0' }; + DPRINTF("GetSerialNumber\n"); + baum_write_packet(baum, serial, sizeof(serial)); + break; + } + case BAUM_REQ_GetKeys: + { + DPRINTF("Get%0#2x\n", req); + /* ignore */ + break; + } + default: + DPRINTF("unrecognized request %0#2x\n", req); + do + if (!len--) + return 0; + while (*cur++ != ESC); + cur--; + break; + } + return cur - buf; +} + +/* The other end is writing some data. Store it and try to interpret */ +static int baum_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + BaumDriverState *baum = chr->opaque; + int tocopy, cur, eaten, orig_len = len; + + if (!len) + return 0; + if (!baum->brlapi) + return len; + + while (len) { + /* Complete our buffer as much as possible */ + tocopy = len; + if (tocopy > BUF_SIZE - baum->in_buf_used) + tocopy = BUF_SIZE - baum->in_buf_used; + + memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); + baum->in_buf_used += tocopy; + buf += tocopy; + len -= tocopy; + + /* Interpret it as much as possible */ + cur = 0; + while (cur < baum->in_buf_used && + (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) + cur += eaten; + + /* Shift the remainder */ + if (cur) { + memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); + baum->in_buf_used -= cur; + } + + /* And continue if any data left */ + } + return orig_len; +} + +/* Send the key code to the other end */ +static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) { + uint8_t packet[] = { type, value }; + DPRINTF("writing key %x %x\n", type, value); + baum_write_packet(baum, packet, sizeof(packet)); +} + +/* We got some data on the BrlAPI socket */ +static void baum_chr_read(void *opaque) +{ + BaumDriverState *baum = opaque; + brlapi_keyCode_t code; + int ret; + if (!baum->brlapi) + return; + while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) { + DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code); + /* Emulate */ + switch (code & BRLAPI_KEY_TYPE_MASK) { + case BRLAPI_KEY_TYPE_CMD: + switch (code & BRLAPI_KEY_CMD_BLK_MASK) { + case BRLAPI_KEY_CMD_ROUTE: + baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1); + baum_send_key(baum, BAUM_RSP_RoutingKey, 0); + break; + case 0: + switch (code & BRLAPI_KEY_CMD_ARG_MASK) { + case BRLAPI_KEY_CMD_FWINLT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_FWINRT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_LNUP: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_LNDN: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_TOP: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_BOT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_TOP_LEFT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_BOT_LEFT: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_HOME: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + case BRLAPI_KEY_CMD_PREFMENU: + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1); + baum_send_key(baum, BAUM_RSP_TopKeys, 0); + break; + } + } + break; + case BRLAPI_KEY_TYPE_SYM: + break; + } + } + if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) { + brlapi_perror("baum: brlapi_readKey"); + brlapi__closeConnection(baum->brlapi); + g_free(baum->brlapi); + baum->brlapi = NULL; + } +} + +static void baum_close(struct CharDriverState *chr) +{ + BaumDriverState *baum = chr->opaque; + + qemu_free_timer(baum->cellCount_timer); + if (baum->brlapi) { + brlapi__closeConnection(baum->brlapi); + g_free(baum->brlapi); + } + g_free(baum); +} + +CharDriverState *chr_baum_init(QemuOpts *opts) +{ + BaumDriverState *baum; + CharDriverState *chr; + brlapi_handle_t *handle; +#ifdef CONFIG_SDL + SDL_SysWMinfo info; +#endif + int tty; + + baum = g_malloc0(sizeof(BaumDriverState)); + baum->chr = chr = g_malloc0(sizeof(CharDriverState)); + + chr->opaque = baum; + chr->chr_write = baum_write; + chr->chr_accept_input = baum_accept_input; + chr->chr_close = baum_close; + + handle = g_malloc0(brlapi_getHandleSize()); + baum->brlapi = handle; + + baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); + if (baum->brlapi_fd == -1) { + brlapi_perror("baum_init: brlapi_openConnection"); + goto fail_handle; + } + + baum->cellCount_timer = qemu_new_timer_ns(vm_clock, baum_cellCount_timer_cb, baum); + + if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) { + brlapi_perror("baum_init: brlapi_getDisplaySize"); + goto fail; + } + +#ifdef CONFIG_SDL + memset(&info, 0, sizeof(info)); + SDL_VERSION(&info.version); + if (SDL_GetWMInfo(&info)) + tty = info.info.x11.wmwindow; + else +#endif + tty = BRLAPI_TTY_DEFAULT; + + if (brlapi__enterTtyMode(handle, tty, NULL) == -1) { + brlapi_perror("baum_init: brlapi_enterTtyMode"); + goto fail; + } + + qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); + + qemu_chr_generic_open(chr); + + return chr; + +fail: + qemu_free_timer(baum->cellCount_timer); + brlapi__closeConnection(handle); +fail_handle: + g_free(handle); + g_free(chr); + g_free(baum); + return NULL; +} diff --git a/backends/msmouse.c b/backends/msmouse.c new file mode 100644 index 0000000000..bf2ff2aca8 --- /dev/null +++ b/backends/msmouse.c @@ -0,0 +1,78 @@ +/* + * QEMU Microsoft serial mouse emulation + * + * Copyright (c) 2008 Lubomir Rintel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include "qemu-common.h" +#include "char/char.h" +#include "ui/console.h" +#include "char/msmouse.h" + +#define MSMOUSE_LO6(n) ((n) & 0x3f) +#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) + +static void msmouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) +{ + CharDriverState *chr = (CharDriverState *)opaque; + + unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 }; + + /* Movement deltas */ + bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx); + bytes[1] |= MSMOUSE_LO6(dx); + bytes[2] |= MSMOUSE_LO6(dy); + + /* Buttons */ + bytes[0] |= (buttons_state & 0x01 ? 0x20 : 0x00); + bytes[0] |= (buttons_state & 0x02 ? 0x10 : 0x00); + bytes[3] |= (buttons_state & 0x04 ? 0x20 : 0x00); + + /* We always send the packet of, so that we do not have to keep track + of previous state of the middle button. This can potentially confuse + some very old drivers for two button mice though. */ + qemu_chr_be_write(chr, bytes, 4); +} + +static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len) +{ + /* Ignore writes to mouse port */ + return len; +} + +static void msmouse_chr_close (struct CharDriverState *chr) +{ + g_free (chr); +} + +CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) +{ + CharDriverState *chr; + + chr = g_malloc0(sizeof(CharDriverState)); + chr->chr_write = msmouse_chr_write; + chr->chr_close = msmouse_chr_close; + + qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse"); + + return chr; +} diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 40ebe466ad..5750332f54 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -190,10 +190,9 @@ common-obj-$(CONFIG_SSI_SD) += ssi-sd.o common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o -common-obj-y += msmouse.o ps2.o +common-obj-y += ps2.o common-obj-y += qdev-monitor.o common-obj-y += qdev-properties-system.o -common-obj-$(CONFIG_BRLAPI) += baum.o # xen backend driver support common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o @@ -218,5 +217,4 @@ obj-$(CONFIG_KVM) += ivshmem.o obj-$(CONFIG_LINUX) += vfio_pci.o endif -$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) endif diff --git a/hw/baum.c b/hw/baum.c deleted file mode 100644 index 09dcb9cc74..0000000000 --- a/hw/baum.c +++ /dev/null @@ -1,627 +0,0 @@ -/* - * QEMU Baum Braille Device - * - * Copyright (c) 2008 Samuel Thibault - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu-common.h" -#include "char/char.h" -#include "qemu/timer.h" -#include "usb.h" -#include "baum.h" -#include -#include -#include -#ifdef CONFIG_SDL -#include -#endif - -#if 0 -#define DPRINTF(fmt, ...) \ - printf(fmt, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) -#endif - -#define ESC 0x1B - -#define BAUM_REQ_DisplayData 0x01 -#define BAUM_REQ_GetVersionNumber 0x05 -#define BAUM_REQ_GetKeys 0x08 -#define BAUM_REQ_SetMode 0x12 -#define BAUM_REQ_SetProtocol 0x15 -#define BAUM_REQ_GetDeviceIdentity 0x84 -#define BAUM_REQ_GetSerialNumber 0x8A - -#define BAUM_RSP_CellCount 0x01 -#define BAUM_RSP_VersionNumber 0x05 -#define BAUM_RSP_ModeSetting 0x11 -#define BAUM_RSP_CommunicationChannel 0x16 -#define BAUM_RSP_PowerdownSignal 0x17 -#define BAUM_RSP_HorizontalSensors 0x20 -#define BAUM_RSP_VerticalSensors 0x21 -#define BAUM_RSP_RoutingKeys 0x22 -#define BAUM_RSP_Switches 0x23 -#define BAUM_RSP_TopKeys 0x24 -#define BAUM_RSP_HorizontalSensor 0x25 -#define BAUM_RSP_VerticalSensor 0x26 -#define BAUM_RSP_RoutingKey 0x27 -#define BAUM_RSP_FrontKeys6 0x28 -#define BAUM_RSP_BackKeys6 0x29 -#define BAUM_RSP_CommandKeys 0x2B -#define BAUM_RSP_FrontKeys10 0x2C -#define BAUM_RSP_BackKeys10 0x2D -#define BAUM_RSP_EntryKeys 0x33 -#define BAUM_RSP_JoyStick 0x34 -#define BAUM_RSP_ErrorCode 0x40 -#define BAUM_RSP_InfoBlock 0x42 -#define BAUM_RSP_DeviceIdentity 0x84 -#define BAUM_RSP_SerialNumber 0x8A -#define BAUM_RSP_BluetoothName 0x8C - -#define BAUM_TL1 0x01 -#define BAUM_TL2 0x02 -#define BAUM_TL3 0x04 -#define BAUM_TR1 0x08 -#define BAUM_TR2 0x10 -#define BAUM_TR3 0x20 - -#define BUF_SIZE 256 - -typedef struct { - CharDriverState *chr; - - brlapi_handle_t *brlapi; - int brlapi_fd; - unsigned int x, y; - - uint8_t in_buf[BUF_SIZE]; - uint8_t in_buf_used; - uint8_t out_buf[BUF_SIZE]; - uint8_t out_buf_used, out_buf_ptr; - - QEMUTimer *cellCount_timer; -} BaumDriverState; - -/* Let's assume NABCC by default */ -static const uint8_t nabcc_translation[256] = { - [0] = ' ', -#ifndef BRLAPI_DOTS -#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \ - ((d1?BRLAPI_DOT1:0)|\ - (d2?BRLAPI_DOT2:0)|\ - (d3?BRLAPI_DOT3:0)|\ - (d4?BRLAPI_DOT4:0)|\ - (d5?BRLAPI_DOT5:0)|\ - (d6?BRLAPI_DOT6:0)|\ - (d7?BRLAPI_DOT7:0)|\ - (d8?BRLAPI_DOT8:0)) -#endif - [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a', - [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b', - [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c', - [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd', - [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e', - [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f', - [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g', - [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h', - [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i', - [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j', - [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k', - [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l', - [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm', - [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n', - [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o', - [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p', - [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q', - [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r', - [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's', - [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't', - [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u', - [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v', - [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w', - [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x', - [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y', - [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z', - - [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A', - [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B', - [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C', - [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D', - [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E', - [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F', - [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G', - [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H', - [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I', - [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J', - [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K', - [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L', - [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M', - [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N', - [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O', - [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P', - [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q', - [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R', - [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S', - [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T', - [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U', - [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V', - [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W', - [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X', - [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y', - [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z', - - [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0', - [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1', - [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2', - [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3', - [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4', - [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5', - [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6', - [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7', - [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8', - [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9', - - [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.', - [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+', - [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-', - [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*', - [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/', - [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(', - [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')', - - [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&', - [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#', - - [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',', - [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';', - [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':', - [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!', - [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?', - [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"', - [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'', - [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`', - [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^', - [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~', - [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[', - [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']', - [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{', - [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}', - [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=', - [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<', - [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>', - [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$', - [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%', - [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@', - [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|', - [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\', - [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_', -}; - -/* The serial port can receive more of our data */ -static void baum_accept_input(struct CharDriverState *chr) -{ - BaumDriverState *baum = chr->opaque; - int room, first; - - if (!baum->out_buf_used) - return; - room = qemu_chr_be_can_write(chr); - if (!room) - return; - if (room > baum->out_buf_used) - room = baum->out_buf_used; - - first = BUF_SIZE - baum->out_buf_ptr; - if (room > first) { - qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first); - baum->out_buf_ptr = 0; - baum->out_buf_used -= first; - room -= first; - } - qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room); - baum->out_buf_ptr += room; - baum->out_buf_used -= room; -} - -/* We want to send a packet */ -static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len) -{ - uint8_t io_buf[1 + 2 * len], *cur = io_buf; - int room; - *cur++ = ESC; - while (len--) - if ((*cur++ = *buf++) == ESC) - *cur++ = ESC; - room = qemu_chr_be_can_write(baum->chr); - len = cur - io_buf; - if (len <= room) { - /* Fits */ - qemu_chr_be_write(baum->chr, io_buf, len); - } else { - int first; - uint8_t out; - /* Can't fit all, send what can be, and store the rest. */ - qemu_chr_be_write(baum->chr, io_buf, room); - len -= room; - cur = io_buf + room; - if (len > BUF_SIZE - baum->out_buf_used) { - /* Can't even store it, drop the previous data... */ - assert(len <= BUF_SIZE); - baum->out_buf_used = 0; - baum->out_buf_ptr = 0; - } - out = baum->out_buf_ptr; - baum->out_buf_used += len; - first = BUF_SIZE - baum->out_buf_ptr; - if (len > first) { - memcpy(baum->out_buf + out, cur, first); - out = 0; - len -= first; - cur += first; - } - memcpy(baum->out_buf + out, cur, len); - } -} - -/* Called when the other end seems to have a wrong idea of our display size */ -static void baum_cellCount_timer_cb(void *opaque) -{ - BaumDriverState *baum = opaque; - uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y }; - DPRINTF("Timeout waiting for DisplayData, sending cell count\n"); - baum_write_packet(baum, cell_count, sizeof(cell_count)); -} - -/* Try to interpret a whole incoming packet */ -static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) -{ - const uint8_t *cur = buf; - uint8_t req = 0; - - if (!len--) - return 0; - if (*cur++ != ESC) { - while (*cur != ESC) { - if (!len--) - return 0; - cur++; - } - DPRINTF("Dropped %d bytes!\n", cur - buf); - } - -#define EAT(c) do {\ - if (!len--) \ - return 0; \ - if ((c = *cur++) == ESC) { \ - if (!len--) \ - return 0; \ - if (*cur++ != ESC) { \ - DPRINTF("Broken packet %#2x, tossing\n", req); \ - if (qemu_timer_pending(baum->cellCount_timer)) { \ - qemu_del_timer(baum->cellCount_timer); \ - baum_cellCount_timer_cb(baum); \ - } \ - return (cur - 2 - buf); \ - } \ - } \ -} while (0) - - EAT(req); - switch (req) { - case BAUM_REQ_DisplayData: - { - uint8_t cells[baum->x * baum->y], c; - uint8_t text[baum->x * baum->y]; - uint8_t zero[baum->x * baum->y]; - int cursor = BRLAPI_CURSOR_OFF; - int i; - - /* Allow 100ms to complete the DisplayData packet */ - qemu_mod_timer(baum->cellCount_timer, qemu_get_clock_ns(vm_clock) + - get_ticks_per_sec() / 10); - for (i = 0; i < baum->x * baum->y ; i++) { - EAT(c); - cells[i] = c; - if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) - == (BRLAPI_DOT7|BRLAPI_DOT8)) { - cursor = i + 1; - c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); - } - if (!(c = nabcc_translation[c])) - c = '?'; - text[i] = c; - } - qemu_del_timer(baum->cellCount_timer); - - memset(zero, 0, sizeof(zero)); - - brlapi_writeArguments_t wa = { - .displayNumber = BRLAPI_DISPLAY_DEFAULT, - .regionBegin = 1, - .regionSize = baum->x * baum->y, - .text = (char *)text, - .textSize = baum->x * baum->y, - .andMask = zero, - .orMask = cells, - .cursor = cursor, - .charset = (char *)"ISO-8859-1", - }; - - if (brlapi__write(baum->brlapi, &wa) == -1) - brlapi_perror("baum brlapi_write"); - break; - } - case BAUM_REQ_SetMode: - { - uint8_t mode, setting; - DPRINTF("SetMode\n"); - EAT(mode); - EAT(setting); - /* ignore */ - break; - } - case BAUM_REQ_SetProtocol: - { - uint8_t protocol; - DPRINTF("SetProtocol\n"); - EAT(protocol); - /* ignore */ - break; - } - case BAUM_REQ_GetDeviceIdentity: - { - uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, - 'B','a','u','m',' ','V','a','r','i','o' }; - DPRINTF("GetDeviceIdentity\n"); - identity[11] = '0' + baum->x / 10; - identity[12] = '0' + baum->x % 10; - baum_write_packet(baum, identity, sizeof(identity)); - break; - } - case BAUM_REQ_GetVersionNumber: - { - uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ - DPRINTF("GetVersionNumber\n"); - baum_write_packet(baum, version, sizeof(version)); - break; - } - case BAUM_REQ_GetSerialNumber: - { - uint8_t serial[] = { BAUM_RSP_SerialNumber, - '0','0','0','0','0','0','0','0' }; - DPRINTF("GetSerialNumber\n"); - baum_write_packet(baum, serial, sizeof(serial)); - break; - } - case BAUM_REQ_GetKeys: - { - DPRINTF("Get%0#2x\n", req); - /* ignore */ - break; - } - default: - DPRINTF("unrecognized request %0#2x\n", req); - do - if (!len--) - return 0; - while (*cur++ != ESC); - cur--; - break; - } - return cur - buf; -} - -/* The other end is writing some data. Store it and try to interpret */ -static int baum_write(CharDriverState *chr, const uint8_t *buf, int len) -{ - BaumDriverState *baum = chr->opaque; - int tocopy, cur, eaten, orig_len = len; - - if (!len) - return 0; - if (!baum->brlapi) - return len; - - while (len) { - /* Complete our buffer as much as possible */ - tocopy = len; - if (tocopy > BUF_SIZE - baum->in_buf_used) - tocopy = BUF_SIZE - baum->in_buf_used; - - memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); - baum->in_buf_used += tocopy; - buf += tocopy; - len -= tocopy; - - /* Interpret it as much as possible */ - cur = 0; - while (cur < baum->in_buf_used && - (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) - cur += eaten; - - /* Shift the remainder */ - if (cur) { - memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); - baum->in_buf_used -= cur; - } - - /* And continue if any data left */ - } - return orig_len; -} - -/* Send the key code to the other end */ -static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) { - uint8_t packet[] = { type, value }; - DPRINTF("writing key %x %x\n", type, value); - baum_write_packet(baum, packet, sizeof(packet)); -} - -/* We got some data on the BrlAPI socket */ -static void baum_chr_read(void *opaque) -{ - BaumDriverState *baum = opaque; - brlapi_keyCode_t code; - int ret; - if (!baum->brlapi) - return; - while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) { - DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code); - /* Emulate */ - switch (code & BRLAPI_KEY_TYPE_MASK) { - case BRLAPI_KEY_TYPE_CMD: - switch (code & BRLAPI_KEY_CMD_BLK_MASK) { - case BRLAPI_KEY_CMD_ROUTE: - baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1); - baum_send_key(baum, BAUM_RSP_RoutingKey, 0); - break; - case 0: - switch (code & BRLAPI_KEY_CMD_ARG_MASK) { - case BRLAPI_KEY_CMD_FWINLT: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_FWINRT: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_LNUP: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_LNDN: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_TOP: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_BOT: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_TOP_LEFT: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_BOT_LEFT: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_HOME: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - case BRLAPI_KEY_CMD_PREFMENU: - baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1); - baum_send_key(baum, BAUM_RSP_TopKeys, 0); - break; - } - } - break; - case BRLAPI_KEY_TYPE_SYM: - break; - } - } - if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) { - brlapi_perror("baum: brlapi_readKey"); - brlapi__closeConnection(baum->brlapi); - g_free(baum->brlapi); - baum->brlapi = NULL; - } -} - -static void baum_close(struct CharDriverState *chr) -{ - BaumDriverState *baum = chr->opaque; - - qemu_free_timer(baum->cellCount_timer); - if (baum->brlapi) { - brlapi__closeConnection(baum->brlapi); - g_free(baum->brlapi); - } - g_free(baum); -} - -CharDriverState *chr_baum_init(QemuOpts *opts) -{ - BaumDriverState *baum; - CharDriverState *chr; - brlapi_handle_t *handle; -#ifdef CONFIG_SDL - SDL_SysWMinfo info; -#endif - int tty; - - baum = g_malloc0(sizeof(BaumDriverState)); - baum->chr = chr = g_malloc0(sizeof(CharDriverState)); - - chr->opaque = baum; - chr->chr_write = baum_write; - chr->chr_accept_input = baum_accept_input; - chr->chr_close = baum_close; - - handle = g_malloc0(brlapi_getHandleSize()); - baum->brlapi = handle; - - baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); - if (baum->brlapi_fd == -1) { - brlapi_perror("baum_init: brlapi_openConnection"); - goto fail_handle; - } - - baum->cellCount_timer = qemu_new_timer_ns(vm_clock, baum_cellCount_timer_cb, baum); - - if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) { - brlapi_perror("baum_init: brlapi_getDisplaySize"); - goto fail; - } - -#ifdef CONFIG_SDL - memset(&info, 0, sizeof(info)); - SDL_VERSION(&info.version); - if (SDL_GetWMInfo(&info)) - tty = info.info.x11.wmwindow; - else -#endif - tty = BRLAPI_TTY_DEFAULT; - - if (brlapi__enterTtyMode(handle, tty, NULL) == -1) { - brlapi_perror("baum_init: brlapi_enterTtyMode"); - goto fail; - } - - qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); - - qemu_chr_generic_open(chr); - - return chr; - -fail: - qemu_free_timer(baum->cellCount_timer); - brlapi__closeConnection(handle); -fail_handle: - g_free(handle); - g_free(chr); - g_free(baum); - return NULL; -} diff --git a/hw/baum.h b/hw/baum.h deleted file mode 100644 index 763588422a..0000000000 --- a/hw/baum.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * QEMU Baum - * - * Copyright (c) 2008 Samuel Thibault - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef HW_BAUM_H -#define HW_BAUM_H 1 - -/* char device */ -CharDriverState *chr_baum_init(QemuOpts *opts); - -#endif diff --git a/hw/msmouse.c b/hw/msmouse.c deleted file mode 100644 index ef47aed4e9..0000000000 --- a/hw/msmouse.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * QEMU Microsoft serial mouse emulation - * - * Copyright (c) 2008 Lubomir Rintel - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include "qemu-common.h" -#include "char/char.h" -#include "ui/console.h" -#include "msmouse.h" - -#define MSMOUSE_LO6(n) ((n) & 0x3f) -#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) - -static void msmouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) -{ - CharDriverState *chr = (CharDriverState *)opaque; - - unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 }; - - /* Movement deltas */ - bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx); - bytes[1] |= MSMOUSE_LO6(dx); - bytes[2] |= MSMOUSE_LO6(dy); - - /* Buttons */ - bytes[0] |= (buttons_state & 0x01 ? 0x20 : 0x00); - bytes[0] |= (buttons_state & 0x02 ? 0x10 : 0x00); - bytes[3] |= (buttons_state & 0x04 ? 0x20 : 0x00); - - /* We always send the packet of, so that we do not have to keep track - of previous state of the middle button. This can potentially confuse - some very old drivers for two button mice though. */ - qemu_chr_be_write(chr, bytes, 4); -} - -static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len) -{ - /* Ignore writes to mouse port */ - return len; -} - -static void msmouse_chr_close (struct CharDriverState *chr) -{ - g_free (chr); -} - -CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) -{ - CharDriverState *chr; - - chr = g_malloc0(sizeof(CharDriverState)); - chr->chr_write = msmouse_chr_write; - chr->chr_close = msmouse_chr_close; - - qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse"); - - return chr; -} diff --git a/hw/msmouse.h b/hw/msmouse.h deleted file mode 100644 index 8cff3a71c3..0000000000 --- a/hw/msmouse.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef HW_MSMOUSE_H -#define HW_MSMOUSE_H 1 - -/* msmouse.c */ -CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts); - -#endif diff --git a/include/char/baum.h b/include/char/baum.h new file mode 100644 index 0000000000..763588422a --- /dev/null +++ b/include/char/baum.h @@ -0,0 +1,30 @@ +/* + * QEMU Baum + * + * Copyright (c) 2008 Samuel Thibault + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef HW_BAUM_H +#define HW_BAUM_H 1 + +/* char device */ +CharDriverState *chr_baum_init(QemuOpts *opts); + +#endif diff --git a/include/char/msmouse.h b/include/char/msmouse.h new file mode 100644 index 0000000000..8cff3a71c3 --- /dev/null +++ b/include/char/msmouse.h @@ -0,0 +1,7 @@ +#ifndef HW_MSMOUSE_H +#define HW_MSMOUSE_H 1 + +/* msmouse.c */ +CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts); + +#endif diff --git a/qemu-char.c b/qemu-char.c index 160decc2f0..6dc1474546 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -28,8 +28,8 @@ #include "qemu/timer.h" #include "char/char.h" #include "hw/usb.h" -#include "hw/baum.h" -#include "hw/msmouse.h" +#include "char/baum.h" +#include "char/msmouse.h" #include "qmp-commands.h" #include diff --git a/vl.c b/vl.c index c03edf1bfb..e0a8eeb24b 100644 --- a/vl.c +++ b/vl.c @@ -119,7 +119,7 @@ int main(int argc, char **argv) #include "hw/pcmcia.h" #include "hw/pc.h" #include "hw/isa.h" -#include "hw/baum.h" +#include "char/baum.h" #include "hw/bt.h" #include "hw/watchdog.h" #include "hw/smbios.h" -- cgit v1.2.3 From fd7f0d66177ec1058a2a256856ff38fc9ceae5af Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 10:57:50 +0100 Subject: hw: move fifo.[ch] to libqemuutil fifo.c is generic code that can be easily unit tested. So it belongs in libqemuutil. Signed-off-by: Paolo Bonzini --- hw/Makefile.objs | 1 - hw/fifo.c | 78 ----------------------------------- hw/fifo.h | 99 --------------------------------------------- hw/xilinx_spi.c | 2 +- hw/xilinx_spips.c | 2 +- include/migration/vmstate.h | 2 + include/qemu/fifo8.h | 99 +++++++++++++++++++++++++++++++++++++++++++++ util/Makefile.objs | 1 + util/fifo8.c | 79 ++++++++++++++++++++++++++++++++++++ 9 files changed, 183 insertions(+), 180 deletions(-) delete mode 100644 hw/fifo.c delete mode 100644 hw/fifo.h create mode 100644 include/qemu/fifo8.h create mode 100644 util/fifo8.c diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 5750332f54..6e2275b842 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -44,7 +44,6 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o endif common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-$(CONFIG_SDHCI) += sdhci.o -common-obj-y += fifo.o common-obj-y += pam.o # PPC devices diff --git a/hw/fifo.c b/hw/fifo.c deleted file mode 100644 index 68a955a77b..0000000000 --- a/hw/fifo.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Generic FIFO component, implemented as a circular buffer. - * - * Copyright (c) 2012 Peter A. G. Crosthwaite - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "fifo.h" - -void fifo8_create(Fifo8 *fifo, uint32_t capacity) -{ - fifo->data = g_new(uint8_t, capacity); - fifo->capacity = capacity; - fifo->head = 0; - fifo->num = 0; -} - -void fifo8_destroy(Fifo8 *fifo) -{ - g_free(fifo->data); -} - -void fifo8_push(Fifo8 *fifo, uint8_t data) -{ - if (fifo->num == fifo->capacity) { - abort(); - } - fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; - fifo->num++; -} - -uint8_t fifo8_pop(Fifo8 *fifo) -{ - uint8_t ret; - - if (fifo->num == 0) { - abort(); - } - ret = fifo->data[fifo->head++]; - fifo->head %= fifo->capacity; - fifo->num--; - return ret; -} - -void fifo8_reset(Fifo8 *fifo) -{ - fifo->num = 0; -} - -bool fifo8_is_empty(Fifo8 *fifo) -{ - return (fifo->num == 0); -} - -bool fifo8_is_full(Fifo8 *fifo) -{ - return (fifo->num == fifo->capacity); -} - -const VMStateDescription vmstate_fifo8 = { - .name = "Fifo8", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, 0, capacity), - VMSTATE_UINT32(head, Fifo8), - VMSTATE_UINT32(num, Fifo8), - VMSTATE_END_OF_LIST() - } -}; diff --git a/hw/fifo.h b/hw/fifo.h deleted file mode 100644 index f23890abf4..0000000000 --- a/hw/fifo.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef FIFO_H -#define FIFO_H - -#include "hw.h" - -typedef struct { - /* All fields are private */ - uint8_t *data; - uint32_t capacity; - uint32_t head; - uint32_t num; -} Fifo8; - -/** - * fifo8_create: - * @fifo: struct Fifo8 to initialise with new FIFO - * @capacity: capacity of the newly created FIFO - * - * Create a FIFO of the specified size. Clients should call fifo8_destroy() - * when finished using the fifo. The FIFO is initially empty. - */ - -void fifo8_create(Fifo8 *fifo, uint32_t capacity); - -/** - * fifo8_destroy: - * @fifo: FIFO to cleanup - * - * Cleanup a FIFO created with fifo8_create(). Frees memory created for FIFO - *storage. The FIFO is no longer usable after this has been called. - */ - -void fifo8_destroy(Fifo8 *fifo); - -/** - * fifo8_push: - * @fifo: FIFO to push to - * @data: data byte to push - * - * Push a data byte to the FIFO. Behaviour is undefined if the FIFO is full. - * Clients are responsible for checking for fullness using fifo8_is_full(). - */ - -void fifo8_push(Fifo8 *fifo, uint8_t data); - -/** - * fifo8_pop: - * @fifo: fifo to pop from - * - * Pop a data byte from the FIFO. Behaviour is undefined if the FIFO is empty. - * Clients are responsible for checking for emptyness using fifo8_is_empty(). - * - * Returns: The popped data byte. - */ - -uint8_t fifo8_pop(Fifo8 *fifo); - -/** - * fifo8_reset: - * @fifo: FIFO to reset - * - * Reset a FIFO. All data is discarded and the FIFO is emptied. - */ - -void fifo8_reset(Fifo8 *fifo); - -/** - * fifo8_is_empty: - * @fifo: FIFO to check - * - * Check if a FIFO is empty. - * - * Returns: True if the fifo is empty, false otherwise. - */ - -bool fifo8_is_empty(Fifo8 *fifo); - -/** - * fifo8_is_full: - * @fifo: FIFO to check - * - * Check if a FIFO is full. - * - * Returns: True if the fifo is full, false otherwise. - */ - -bool fifo8_is_full(Fifo8 *fifo); - -extern const VMStateDescription vmstate_fifo8; - -#define VMSTATE_FIFO8(_field, _state) { \ - .name = (stringify(_field)), \ - .size = sizeof(Fifo8), \ - .vmsd = &vmstate_fifo8, \ - .flags = VMS_STRUCT, \ - .offset = vmstate_offset_value(_state, _field, Fifo8), \ -} - -#endif /* FIFO_H */ diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c index be581c2ac5..e73c9bd79b 100644 --- a/hw/xilinx_spi.c +++ b/hw/xilinx_spi.c @@ -27,7 +27,7 @@ #include "sysbus.h" #include "sysemu/sysemu.h" #include "qemu/log.h" -#include "fifo.h" +#include "qemu/fifo8.h" #include "ssi.h" diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 42e019dc05..915eb96a48 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -26,7 +26,7 @@ #include "sysemu/sysemu.h" #include "ptimer.h" #include "qemu/log.h" -#include "fifo.h" +#include "qemu/fifo8.h" #include "ssi.h" #include "qemu/bitops.h" diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index f27276c2d8..94a409b708 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -26,6 +26,8 @@ #ifndef QEMU_VMSTATE_H #define QEMU_VMSTATE_H 1 +#include + typedef void SaveStateHandler(QEMUFile *f, void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); diff --git a/include/qemu/fifo8.h b/include/qemu/fifo8.h new file mode 100644 index 0000000000..d318f71e11 --- /dev/null +++ b/include/qemu/fifo8.h @@ -0,0 +1,99 @@ +#ifndef FIFO_H +#define FIFO_H + +#include "migration/vmstate.h" + +typedef struct { + /* All fields are private */ + uint8_t *data; + uint32_t capacity; + uint32_t head; + uint32_t num; +} Fifo8; + +/** + * fifo8_create: + * @fifo: struct Fifo8 to initialise with new FIFO + * @capacity: capacity of the newly created FIFO + * + * Create a FIFO of the specified size. Clients should call fifo8_destroy() + * when finished using the fifo. The FIFO is initially empty. + */ + +void fifo8_create(Fifo8 *fifo, uint32_t capacity); + +/** + * fifo8_destroy: + * @fifo: FIFO to cleanup + * + * Cleanup a FIFO created with fifo8_create(). Frees memory created for FIFO + *storage. The FIFO is no longer usable after this has been called. + */ + +void fifo8_destroy(Fifo8 *fifo); + +/** + * fifo8_push: + * @fifo: FIFO to push to + * @data: data byte to push + * + * Push a data byte to the FIFO. Behaviour is undefined if the FIFO is full. + * Clients are responsible for checking for fullness using fifo8_is_full(). + */ + +void fifo8_push(Fifo8 *fifo, uint8_t data); + +/** + * fifo8_pop: + * @fifo: fifo to pop from + * + * Pop a data byte from the FIFO. Behaviour is undefined if the FIFO is empty. + * Clients are responsible for checking for emptyness using fifo8_is_empty(). + * + * Returns: The popped data byte. + */ + +uint8_t fifo8_pop(Fifo8 *fifo); + +/** + * fifo8_reset: + * @fifo: FIFO to reset + * + * Reset a FIFO. All data is discarded and the FIFO is emptied. + */ + +void fifo8_reset(Fifo8 *fifo); + +/** + * fifo8_is_empty: + * @fifo: FIFO to check + * + * Check if a FIFO is empty. + * + * Returns: True if the fifo is empty, false otherwise. + */ + +bool fifo8_is_empty(Fifo8 *fifo); + +/** + * fifo8_is_full: + * @fifo: FIFO to check + * + * Check if a FIFO is full. + * + * Returns: True if the fifo is full, false otherwise. + */ + +bool fifo8_is_full(Fifo8 *fifo); + +extern const VMStateDescription vmstate_fifo8; + +#define VMSTATE_FIFO8(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(Fifo8), \ + .vmsd = &vmstate_fifo8, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, Fifo8), \ +} + +#endif /* FIFO_H */ diff --git a/util/Makefile.objs b/util/Makefile.objs index 495a178557..cad5ce87db 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -3,6 +3,7 @@ util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o util-obj-y += bitmap.o bitops.o hbitmap.o +util-obj-y += fifo8.o util-obj-y += acl.o util-obj-y += error.o qemu-error.o util-obj-$(CONFIG_POSIX) += compatfd.o diff --git a/util/fifo8.c b/util/fifo8.c new file mode 100644 index 0000000000..013e903c6e --- /dev/null +++ b/util/fifo8.c @@ -0,0 +1,79 @@ +/* + * Generic FIFO component, implemented as a circular buffer. + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu-common.h" +#include "qemu/fifo8.h" + +void fifo8_create(Fifo8 *fifo, uint32_t capacity) +{ + fifo->data = g_new(uint8_t, capacity); + fifo->capacity = capacity; + fifo->head = 0; + fifo->num = 0; +} + +void fifo8_destroy(Fifo8 *fifo) +{ + g_free(fifo->data); +} + +void fifo8_push(Fifo8 *fifo, uint8_t data) +{ + if (fifo->num == fifo->capacity) { + abort(); + } + fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; + fifo->num++; +} + +uint8_t fifo8_pop(Fifo8 *fifo) +{ + uint8_t ret; + + if (fifo->num == 0) { + abort(); + } + ret = fifo->data[fifo->head++]; + fifo->head %= fifo->capacity; + fifo->num--; + return ret; +} + +void fifo8_reset(Fifo8 *fifo) +{ + fifo->num = 0; +} + +bool fifo8_is_empty(Fifo8 *fifo) +{ + return (fifo->num == 0); +} + +bool fifo8_is_full(Fifo8 *fifo) +{ + return (fifo->num == fifo->capacity); +} + +const VMStateDescription vmstate_fifo8 = { + .name = "Fifo8", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, 0, capacity), + VMSTATE_UINT32(head, Fifo8), + VMSTATE_UINT32(num, Fifo8), + VMSTATE_END_OF_LIST() + } +}; -- cgit v1.2.3 From b4a42f81383d60900aae09513f42eb857a5a7c7c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 11:37:52 +0100 Subject: hw: move qdev-monitor.o to toplevel directory qdev-monitor.c is the only "core qdev" file that is not used in user-mode emulation, and it does not define anything that is used by hardware models. Remove it from the hw/ directory and remove hw/qdev-monitor.h from hw/qdev.h too; this requires some files to have some new explicitly includes. Signed-off-by: Paolo Bonzini --- Makefile.objs | 1 + hw/9pfs/virtio-9p-proxy.c | 1 + hw/Makefile.objs | 1 - hw/dataplane/virtio-blk.c | 2 + hw/dataplane/vring.c | 1 + hw/pc87312.c | 1 + hw/pc_sysfw.c | 1 + hw/pci/shpc.c | 3 +- hw/pci/slotid_cap.c | 1 + hw/qdev-addr.c | 1 + hw/qdev-monitor.c | 683 --------------------------------------------- hw/qdev-monitor.h | 16 -- hw/qdev.c | 1 + hw/qdev.h | 1 - hw/s390x/sclpconsole.c | 1 + hw/usb/dev-network.c | 1 + hw/virtio-rng.c | 1 + hw/virtio-scsi.c | 1 + hw/xilinx.h | 3 +- hw/xilinx_axienet.c | 1 + include/monitor/qdev.h | 15 + monitor.c | 2 +- qdev-monitor.c | 684 ++++++++++++++++++++++++++++++++++++++++++++++ util/qemu-config.c | 1 + vl.c | 1 + 25 files changed, 721 insertions(+), 704 deletions(-) delete mode 100644 hw/qdev-monitor.c delete mode 100644 hw/qdev-monitor.h create mode 100644 include/monitor/qdev.h create mode 100644 qdev-monitor.c diff --git a/Makefile.objs b/Makefile.objs index a68cdac7ce..2a8174dd15 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -51,6 +51,7 @@ ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ common-obj-y += readline.o +common-obj-y += qdev-monitor.o common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index 54e98759f0..730027900e 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -13,6 +13,7 @@ #include #include "hw/virtio.h" #include "virtio-9p.h" +#include "qemu/error-report.h" #include "fsdev/qemu-fsdev.h" #include "virtio-9p-proxy.h" diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 6e2275b842..f7ee133627 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -190,7 +190,6 @@ common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += ps2.o -common-obj-y += qdev-monitor.o common-obj-y += qdev-properties-system.o # xen backend driver support diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 3f2da22669..8588f93114 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -16,9 +16,11 @@ #include "qemu/iov.h" #include "event-poll.h" #include "qemu/thread.h" +#include "qemu/error-report.h" #include "vring.h" #include "ioq.h" #include "migration/migration.h" +#include "block/block.h" #include "hw/virtio-blk.h" #include "hw/dataplane/virtio-blk.h" diff --git a/hw/dataplane/vring.c b/hw/dataplane/vring.c index d5d4ef45d1..eff5ad8831 100644 --- a/hw/dataplane/vring.c +++ b/hw/dataplane/vring.c @@ -16,6 +16,7 @@ #include "trace.h" #include "hw/dataplane/vring.h" +#include "qemu/error-report.h" /* Map the guest's vring to host memory */ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) diff --git a/hw/pc87312.c b/hw/pc87312.c index 38af4c1d10..0e9760e6b2 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -24,6 +24,7 @@ */ #include "pc87312.h" +#include "qemu/error-report.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" #include "char/char.h" diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index 7f6c12c8a8..8b65a7a4d8 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -24,6 +24,7 @@ */ #include "sysemu/blockdev.h" +#include "qemu/error-report.h" #include "sysbus.h" #include "hw.h" #include "pc.h" diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index f07266da66..d35c2ee965 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -1,7 +1,8 @@ +#include "qemu-common.h" #include #include #include "qemu/range.h" -#include "qemu/range.h" +#include "qemu/error-report.h" #include "hw/pci/shpc.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c index 99a30f429d..62f7bae2f1 100644 --- a/hw/pci/slotid_cap.c +++ b/hw/pci/slotid_cap.c @@ -1,5 +1,6 @@ #include "hw/pci/slotid_cap.h" #include "hw/pci/pci.h" +#include "qemu/error-report.h" #define SLOTID_CAP_LENGTH 4 #define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index b4388f6a66..fc2c437911 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -1,6 +1,7 @@ #include "qdev.h" #include "qdev-addr.h" #include "exec/hwaddr.h" +#include "qapi/qmp/qerror.h" #include "qapi/visitor.h" /* --- target physical address --- */ diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c deleted file mode 100644 index 4f9a6eb39a..0000000000 --- a/hw/qdev-monitor.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Dynamic device configuration and creation. - * - * Copyright (c) 2009 CodeSourcery - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qdev.h" -#include "monitor/monitor.h" -#include "qmp-commands.h" -#include "sysemu/arch_init.h" -#include "qemu/config-file.h" - -/* - * Aliases were a bad idea from the start. Let's keep them - * from spreading further. - */ -typedef struct QDevAlias -{ - const char *typename; - const char *alias; - uint32_t arch_mask; -} QDevAlias; - -static const QDevAlias qdev_alias_table[] = { - { "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, - { "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, - { "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, - { "virtio-balloon-pci", "virtio-balloon", - QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, - { "virtio-blk-s390", "virtio-blk", QEMU_ARCH_S390X }, - { "virtio-net-s390", "virtio-net", QEMU_ARCH_S390X }, - { "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X }, - { "lsi53c895a", "lsi" }, - { "ich9-ahci", "ahci" }, - { "kvm-pci-assign", "pci-assign" }, - { } -}; - -static const char *qdev_class_get_alias(DeviceClass *dc) -{ - const char *typename = object_class_get_name(OBJECT_CLASS(dc)); - int i; - - for (i = 0; qdev_alias_table[i].typename; i++) { - if (qdev_alias_table[i].arch_mask && - !(qdev_alias_table[i].arch_mask & arch_type)) { - continue; - } - - if (strcmp(qdev_alias_table[i].typename, typename) == 0) { - return qdev_alias_table[i].alias; - } - } - - return NULL; -} - -static bool qdev_class_has_alias(DeviceClass *dc) -{ - return (qdev_class_get_alias(dc) != NULL); -} - -static void qdev_print_devinfo(ObjectClass *klass, void *opaque) -{ - DeviceClass *dc; - bool *show_no_user = opaque; - - dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); - - if (!dc || (show_no_user && !*show_no_user && dc->no_user)) { - return; - } - - error_printf("name \"%s\"", object_class_get_name(klass)); - if (dc->bus_type) { - error_printf(", bus %s", dc->bus_type); - } - if (qdev_class_has_alias(dc)) { - error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); - } - if (dc->desc) { - error_printf(", desc \"%s\"", dc->desc); - } - if (dc->no_user) { - error_printf(", no-user"); - } - error_printf("\n"); -} - -static int set_property(const char *name, const char *value, void *opaque) -{ - DeviceState *dev = opaque; - - if (strcmp(name, "driver") == 0) - return 0; - if (strcmp(name, "bus") == 0) - return 0; - - if (qdev_prop_parse(dev, name, value) == -1) { - return -1; - } - return 0; -} - -static const char *find_typename_by_alias(const char *alias) -{ - int i; - - for (i = 0; qdev_alias_table[i].alias; i++) { - if (qdev_alias_table[i].arch_mask && - !(qdev_alias_table[i].arch_mask & arch_type)) { - continue; - } - - if (strcmp(qdev_alias_table[i].alias, alias) == 0) { - return qdev_alias_table[i].typename; - } - } - - return NULL; -} - -int qdev_device_help(QemuOpts *opts) -{ - const char *driver; - Property *prop; - ObjectClass *klass; - - driver = qemu_opt_get(opts, "driver"); - if (driver && is_help_option(driver)) { - bool show_no_user = false; - object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user); - return 1; - } - - if (!driver || !qemu_opt_has_help_opt(opts)) { - return 0; - } - - klass = object_class_by_name(driver); - if (!klass) { - const char *typename = find_typename_by_alias(driver); - - if (typename) { - driver = typename; - klass = object_class_by_name(driver); - } - } - - if (!klass) { - return 0; - } - do { - for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) { - /* - * TODO Properties without a parser are just for dirty hacks. - * qdev_prop_ptr is the only such PropertyInfo. It's marked - * for removal. This conditional should be removed along with - * it. - */ - if (!prop->info->set) { - continue; /* no way to set it, don't show */ - } - error_printf("%s.%s=%s\n", driver, prop->name, - prop->info->legacy_name ?: prop->info->name); - } - klass = object_class_get_parent(klass); - } while (klass != object_class_by_name(TYPE_DEVICE)); - return 1; -} - -static Object *qdev_get_peripheral(void) -{ - static Object *dev; - - if (dev == NULL) { - dev = container_get(qdev_get_machine(), "/peripheral"); - } - - return dev; -} - -static Object *qdev_get_peripheral_anon(void) -{ - static Object *dev; - - if (dev == NULL) { - dev = container_get(qdev_get_machine(), "/peripheral-anon"); - } - - return dev; -} - -static void qbus_list_bus(DeviceState *dev) -{ - BusState *child; - const char *sep = " "; - - error_printf("child busses at \"%s\":", - dev->id ? dev->id : object_get_typename(OBJECT(dev))); - QLIST_FOREACH(child, &dev->child_bus, sibling) { - error_printf("%s\"%s\"", sep, child->name); - sep = ", "; - } - error_printf("\n"); -} - -static void qbus_list_dev(BusState *bus) -{ - BusChild *kid; - const char *sep = " "; - - error_printf("devices at \"%s\":", bus->name); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev))); - if (dev->id) - error_printf("/\"%s\"", dev->id); - sep = ", "; - } - error_printf("\n"); -} - -static BusState *qbus_find_bus(DeviceState *dev, char *elem) -{ - BusState *child; - - QLIST_FOREACH(child, &dev->child_bus, sibling) { - if (strcmp(child->name, elem) == 0) { - return child; - } - } - return NULL; -} - -static DeviceState *qbus_find_dev(BusState *bus, char *elem) -{ - BusChild *kid; - - /* - * try to match in order: - * (1) instance id, if present - * (2) driver name - * (3) driver alias, if present - */ - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - if (dev->id && strcmp(dev->id, elem) == 0) { - return dev; - } - } - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) { - return dev; - } - } - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - DeviceClass *dc = DEVICE_GET_CLASS(dev); - - if (qdev_class_has_alias(dc) && - strcmp(qdev_class_get_alias(dc), elem) == 0) { - return dev; - } - } - return NULL; -} - -static BusState *qbus_find_recursive(BusState *bus, const char *name, - const char *bus_typename) -{ - BusClass *bus_class = BUS_GET_CLASS(bus); - BusChild *kid; - BusState *child, *ret; - int match = 1; - - if (name && (strcmp(bus->name, name) != 0)) { - match = 0; - } - if (bus_typename && !object_dynamic_cast(OBJECT(bus), bus_typename)) { - match = 0; - } - if ((bus_class->max_dev != 0) && (bus_class->max_dev <= bus->max_index)) { - if (name != NULL) { - /* bus was explicitly specified: return an error. */ - qerror_report(ERROR_CLASS_GENERIC_ERROR, "Bus '%s' is full", - bus->name); - return NULL; - } else { - /* bus was not specified: try to find another one. */ - match = 0; - } - } - if (match) { - return bus; - } - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - QLIST_FOREACH(child, &dev->child_bus, sibling) { - ret = qbus_find_recursive(child, name, bus_typename); - if (ret) { - return ret; - } - } - } - return NULL; -} - -static BusState *qbus_find(const char *path) -{ - DeviceState *dev; - BusState *bus; - char elem[128]; - int pos, len; - - /* find start element */ - if (path[0] == '/') { - bus = sysbus_get_default(); - pos = 0; - } else { - if (sscanf(path, "%127[^/]%n", elem, &len) != 1) { - assert(!path[0]); - elem[0] = len = 0; - } - bus = qbus_find_recursive(sysbus_get_default(), elem, NULL); - if (!bus) { - qerror_report(QERR_BUS_NOT_FOUND, elem); - return NULL; - } - pos = len; - } - - for (;;) { - assert(path[pos] == '/' || !path[pos]); - while (path[pos] == '/') { - pos++; - } - if (path[pos] == '\0') { - return bus; - } - - /* find device */ - if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); - elem[0] = len = 0; - } - pos += len; - dev = qbus_find_dev(bus, elem); - if (!dev) { - qerror_report(QERR_DEVICE_NOT_FOUND, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_dev(bus); - } - return NULL; - } - - assert(path[pos] == '/' || !path[pos]); - while (path[pos] == '/') { - pos++; - } - if (path[pos] == '\0') { - /* last specified element is a device. If it has exactly - * one child bus accept it nevertheless */ - switch (dev->num_child_bus) { - case 0: - qerror_report(QERR_DEVICE_NO_BUS, elem); - return NULL; - case 1: - return QLIST_FIRST(&dev->child_bus); - default: - qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_bus(dev); - } - return NULL; - } - } - - /* find bus */ - if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); - elem[0] = len = 0; - } - pos += len; - bus = qbus_find_bus(dev, elem); - if (!bus) { - qerror_report(QERR_BUS_NOT_FOUND, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_bus(dev); - } - return NULL; - } - } -} - -DeviceState *qdev_device_add(QemuOpts *opts) -{ - ObjectClass *obj; - DeviceClass *k; - const char *driver, *path, *id; - DeviceState *qdev; - BusState *bus; - - driver = qemu_opt_get(opts, "driver"); - if (!driver) { - qerror_report(QERR_MISSING_PARAMETER, "driver"); - return NULL; - } - - /* find driver */ - obj = object_class_by_name(driver); - if (!obj) { - const char *typename = find_typename_by_alias(driver); - - if (typename) { - driver = typename; - obj = object_class_by_name(driver); - } - } - - if (!obj) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type"); - return NULL; - } - - k = DEVICE_CLASS(obj); - - /* find bus */ - path = qemu_opt_get(opts, "bus"); - if (path != NULL) { - bus = qbus_find(path); - if (!bus) { - return NULL; - } - if (!object_dynamic_cast(OBJECT(bus), k->bus_type)) { - qerror_report(QERR_BAD_BUS_FOR_DEVICE, - driver, object_get_typename(OBJECT(bus))); - return NULL; - } - } else { - bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type); - if (!bus) { - qerror_report(QERR_NO_BUS_FOR_DEVICE, - k->bus_type, driver); - return NULL; - } - } - if (qdev_hotplug && !bus->allow_hotplug) { - qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); - return NULL; - } - - if (!bus) { - bus = sysbus_get_default(); - } - - /* create device, set properties */ - qdev = DEVICE(object_new(driver)); - qdev_set_parent_bus(qdev, bus); - - id = qemu_opts_id(opts); - if (id) { - qdev->id = id; - } - if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) { - qdev_free(qdev); - return NULL; - } - if (qdev->id) { - object_property_add_child(qdev_get_peripheral(), qdev->id, - OBJECT(qdev), NULL); - } else { - static int anon_count; - gchar *name = g_strdup_printf("device[%d]", anon_count++); - object_property_add_child(qdev_get_peripheral_anon(), name, - OBJECT(qdev), NULL); - g_free(name); - } - if (qdev_init(qdev) < 0) { - qerror_report(QERR_DEVICE_INIT_FAILED, driver); - return NULL; - } - qdev->opts = opts; - return qdev; -} - - -#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) -static void qbus_print(Monitor *mon, BusState *bus, int indent); - -static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, - int indent) -{ - if (!props) - return; - for (; props->name; props++) { - Error *err = NULL; - char *value; - char *legacy_name = g_strdup_printf("legacy-%s", props->name); - if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { - value = object_property_get_str(OBJECT(dev), legacy_name, &err); - } else { - value = object_property_print(OBJECT(dev), props->name, &err); - } - g_free(legacy_name); - - if (err) { - error_free(err); - continue; - } - qdev_printf("%s = %s\n", props->name, - value && *value ? value : ""); - g_free(value); - } -} - -static void bus_print_dev(BusState *bus, Monitor *mon, DeviceState *dev, int indent) -{ - BusClass *bc = BUS_GET_CLASS(bus); - - if (bc->print_dev) { - bc->print_dev(mon, dev, indent); - } -} - -static void qdev_print(Monitor *mon, DeviceState *dev, int indent) -{ - ObjectClass *class; - BusState *child; - qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)), - dev->id ? dev->id : ""); - indent += 2; - if (dev->num_gpio_in) { - qdev_printf("gpio-in %d\n", dev->num_gpio_in); - } - if (dev->num_gpio_out) { - qdev_printf("gpio-out %d\n", dev->num_gpio_out); - } - class = object_get_class(OBJECT(dev)); - do { - qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent); - class = object_class_get_parent(class); - } while (class != object_class_by_name(TYPE_DEVICE)); - bus_print_dev(dev->parent_bus, mon, dev, indent); - QLIST_FOREACH(child, &dev->child_bus, sibling) { - qbus_print(mon, child, indent); - } -} - -static void qbus_print(Monitor *mon, BusState *bus, int indent) -{ - BusChild *kid; - - qdev_printf("bus: %s\n", bus->name); - indent += 2; - qdev_printf("type %s\n", object_get_typename(OBJECT(bus))); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - qdev_print(mon, dev, indent); - } -} -#undef qdev_printf - -void do_info_qtree(Monitor *mon, const QDict *qdict) -{ - if (sysbus_get_default()) - qbus_print(mon, sysbus_get_default(), 0); -} - -void do_info_qdm(Monitor *mon, const QDict *qdict) -{ - object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL); -} - -int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - Error *local_err = NULL; - QemuOpts *opts; - DeviceState *dev; - - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); - if (error_is_set(&local_err)) { - qerror_report_err(local_err); - error_free(local_err); - return -1; - } - if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { - qemu_opts_del(opts); - return 0; - } - dev = qdev_device_add(opts); - if (!dev) { - qemu_opts_del(opts); - return -1; - } - object_unref(OBJECT(dev)); - return 0; -} - -void qmp_device_del(const char *id, Error **errp) -{ - DeviceState *dev; - - dev = qdev_find_recursive(sysbus_get_default(), id); - if (NULL == dev) { - error_set(errp, QERR_DEVICE_NOT_FOUND, id); - return; - } - - qdev_unplug(dev, errp); -} - -void qdev_machine_init(void) -{ - qdev_get_peripheral_anon(); - qdev_get_peripheral(); -} - -QemuOptsList qemu_device_opts = { - .name = "device", - .implied_opt_name = "driver", - .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head), - .desc = { - /* - * no elements => accept any - * sanity checking will happen later - * when setting device properties - */ - { /* end of list */ } - }, -}; - -QemuOptsList qemu_global_opts = { - .name = "global", - .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), - .desc = { - { - .name = "driver", - .type = QEMU_OPT_STRING, - },{ - .name = "property", - .type = QEMU_OPT_STRING, - },{ - .name = "value", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -int qemu_global_option(const char *str) -{ - char driver[64], property[64]; - QemuOpts *opts; - int rc, offset; - - rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); - if (rc < 2 || str[offset] != '=') { - error_report("can't parse: \"%s\"", str); - return -1; - } - - opts = qemu_opts_create_nofail(&qemu_global_opts); - qemu_opt_set(opts, "driver", driver); - qemu_opt_set(opts, "property", property); - qemu_opt_set(opts, "value", str+offset+1); - return 0; -} diff --git a/hw/qdev-monitor.h b/hw/qdev-monitor.h deleted file mode 100644 index 9ec485028e..0000000000 --- a/hw/qdev-monitor.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef QEMU_QDEV_MONITOR_H -#define QEMU_QDEV_MONITOR_H - -#include "qdev-core.h" -#include "monitor/monitor.h" - -/*** monitor commands ***/ - -void do_info_qtree(Monitor *mon, const QDict *qdict); -void do_info_qdm(Monitor *mon, const QDict *qdict); -int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); -int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data); -int qdev_device_help(QemuOpts *opts); -DeviceState *qdev_device_add(QemuOpts *opts); - -#endif diff --git a/hw/qdev.c b/hw/qdev.c index 689cd543e9..62bc8990f0 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -28,6 +28,7 @@ #include "qdev.h" #include "sysemu/sysemu.h" #include "qapi/error.h" +#include "qapi/qmp/qerror.h" #include "qapi/visitor.h" int qdev_hotplug = 0; diff --git a/hw/qdev.h b/hw/qdev.h index 365b8d6ca2..f814656e0a 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -4,6 +4,5 @@ #include "hw/hw.h" #include "qdev-core.h" #include "qdev-properties.h" -#include "qdev-monitor.h" #endif diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index effe51110f..475d7ba856 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -14,6 +14,7 @@ #include #include "qemu/thread.h" +#include "qemu/error-report.h" #include "sclp.h" #include "event-facility.h" diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index c08718b679..5473ac2cd5 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -27,6 +27,7 @@ #include "hw/usb.h" #include "hw/usb/desc.h" #include "net/net.h" +#include "qapi/qmp/qerror.h" #include "qemu/queue.h" #include "qemu/config-file.h" #include "sysemu/sysemu.h" diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c index e063127df6..2cdf4ec052 100644 --- a/hw/virtio-rng.c +++ b/hw/virtio-rng.c @@ -11,6 +11,7 @@ #include "qemu/iov.h" #include "qdev.h" +#include "qapi/qmp/qerror.h" #include "virtio.h" #include "virtio-rng.h" #include "qemu/rng.h" diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 0715865489..27070d1eea 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -14,6 +14,7 @@ */ #include "virtio-scsi.h" +#include "qemu/error-report.h" #include #include diff --git a/hw/xilinx.h b/hw/xilinx.h index 09bc2e4913..a78281f730 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -2,8 +2,9 @@ #define HW_XILINX_H 1 -#include "stream.h" #include "qemu-common.h" +#include "qapi/qmp/qerror.h" +#include "stream.h" #include "net/net.h" static inline DeviceState * diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index e5d9251b8b..66b9ec1cc5 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -26,6 +26,7 @@ #include "qemu/log.h" #include "net/net.h" #include "net/checksum.h" +#include "qapi/qmp/qerror.h" #include "stream.h" diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h new file mode 100644 index 0000000000..8d16e119d3 --- /dev/null +++ b/include/monitor/qdev.h @@ -0,0 +1,15 @@ +#ifndef QEMU_QDEV_MONITOR_H +#define QEMU_QDEV_MONITOR_H + +#include "hw/qdev-core.h" +#include "monitor/monitor.h" + +/*** monitor commands ***/ + +void do_info_qtree(Monitor *mon, const QDict *qdict); +void do_info_qdm(Monitor *mon, const QDict *qdict); +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); +int qdev_device_help(QemuOpts *opts); +DeviceState *qdev_device_add(QemuOpts *opts); + +#endif diff --git a/monitor.c b/monitor.c index 32a6e74fd9..c48530bd55 100644 --- a/monitor.c +++ b/monitor.c @@ -23,7 +23,7 @@ */ #include #include "hw/hw.h" -#include "hw/qdev.h" +#include "monitor/qdev.h" #include "hw/usb.h" #include "hw/pcmcia.h" #include "hw/pc.h" diff --git a/qdev-monitor.c b/qdev-monitor.c new file mode 100644 index 0000000000..9a78ccff6d --- /dev/null +++ b/qdev-monitor.c @@ -0,0 +1,684 @@ +/* + * Dynamic device configuration and creation. + * + * Copyright (c) 2009 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "hw/qdev.h" +#include "monitor/monitor.h" +#include "monitor/qdev.h" +#include "qmp-commands.h" +#include "sysemu/arch_init.h" +#include "qemu/config-file.h" + +/* + * Aliases were a bad idea from the start. Let's keep them + * from spreading further. + */ +typedef struct QDevAlias +{ + const char *typename; + const char *alias; + uint32_t arch_mask; +} QDevAlias; + +static const QDevAlias qdev_alias_table[] = { + { "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, + { "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, + { "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, + { "virtio-balloon-pci", "virtio-balloon", + QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, + { "virtio-blk-s390", "virtio-blk", QEMU_ARCH_S390X }, + { "virtio-net-s390", "virtio-net", QEMU_ARCH_S390X }, + { "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X }, + { "lsi53c895a", "lsi" }, + { "ich9-ahci", "ahci" }, + { "kvm-pci-assign", "pci-assign" }, + { } +}; + +static const char *qdev_class_get_alias(DeviceClass *dc) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(dc)); + int i; + + for (i = 0; qdev_alias_table[i].typename; i++) { + if (qdev_alias_table[i].arch_mask && + !(qdev_alias_table[i].arch_mask & arch_type)) { + continue; + } + + if (strcmp(qdev_alias_table[i].typename, typename) == 0) { + return qdev_alias_table[i].alias; + } + } + + return NULL; +} + +static bool qdev_class_has_alias(DeviceClass *dc) +{ + return (qdev_class_get_alias(dc) != NULL); +} + +static void qdev_print_devinfo(ObjectClass *klass, void *opaque) +{ + DeviceClass *dc; + bool *show_no_user = opaque; + + dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); + + if (!dc || (show_no_user && !*show_no_user && dc->no_user)) { + return; + } + + error_printf("name \"%s\"", object_class_get_name(klass)); + if (dc->bus_type) { + error_printf(", bus %s", dc->bus_type); + } + if (qdev_class_has_alias(dc)) { + error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); + } + if (dc->desc) { + error_printf(", desc \"%s\"", dc->desc); + } + if (dc->no_user) { + error_printf(", no-user"); + } + error_printf("\n"); +} + +static int set_property(const char *name, const char *value, void *opaque) +{ + DeviceState *dev = opaque; + + if (strcmp(name, "driver") == 0) + return 0; + if (strcmp(name, "bus") == 0) + return 0; + + if (qdev_prop_parse(dev, name, value) == -1) { + return -1; + } + return 0; +} + +static const char *find_typename_by_alias(const char *alias) +{ + int i; + + for (i = 0; qdev_alias_table[i].alias; i++) { + if (qdev_alias_table[i].arch_mask && + !(qdev_alias_table[i].arch_mask & arch_type)) { + continue; + } + + if (strcmp(qdev_alias_table[i].alias, alias) == 0) { + return qdev_alias_table[i].typename; + } + } + + return NULL; +} + +int qdev_device_help(QemuOpts *opts) +{ + const char *driver; + Property *prop; + ObjectClass *klass; + + driver = qemu_opt_get(opts, "driver"); + if (driver && is_help_option(driver)) { + bool show_no_user = false; + object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user); + return 1; + } + + if (!driver || !qemu_opt_has_help_opt(opts)) { + return 0; + } + + klass = object_class_by_name(driver); + if (!klass) { + const char *typename = find_typename_by_alias(driver); + + if (typename) { + driver = typename; + klass = object_class_by_name(driver); + } + } + + if (!klass) { + return 0; + } + do { + for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) { + /* + * TODO Properties without a parser are just for dirty hacks. + * qdev_prop_ptr is the only such PropertyInfo. It's marked + * for removal. This conditional should be removed along with + * it. + */ + if (!prop->info->set) { + continue; /* no way to set it, don't show */ + } + error_printf("%s.%s=%s\n", driver, prop->name, + prop->info->legacy_name ?: prop->info->name); + } + klass = object_class_get_parent(klass); + } while (klass != object_class_by_name(TYPE_DEVICE)); + return 1; +} + +static Object *qdev_get_peripheral(void) +{ + static Object *dev; + + if (dev == NULL) { + dev = container_get(qdev_get_machine(), "/peripheral"); + } + + return dev; +} + +static Object *qdev_get_peripheral_anon(void) +{ + static Object *dev; + + if (dev == NULL) { + dev = container_get(qdev_get_machine(), "/peripheral-anon"); + } + + return dev; +} + +static void qbus_list_bus(DeviceState *dev) +{ + BusState *child; + const char *sep = " "; + + error_printf("child busses at \"%s\":", + dev->id ? dev->id : object_get_typename(OBJECT(dev))); + QLIST_FOREACH(child, &dev->child_bus, sibling) { + error_printf("%s\"%s\"", sep, child->name); + sep = ", "; + } + error_printf("\n"); +} + +static void qbus_list_dev(BusState *bus) +{ + BusChild *kid; + const char *sep = " "; + + error_printf("devices at \"%s\":", bus->name); + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev))); + if (dev->id) + error_printf("/\"%s\"", dev->id); + sep = ", "; + } + error_printf("\n"); +} + +static BusState *qbus_find_bus(DeviceState *dev, char *elem) +{ + BusState *child; + + QLIST_FOREACH(child, &dev->child_bus, sibling) { + if (strcmp(child->name, elem) == 0) { + return child; + } + } + return NULL; +} + +static DeviceState *qbus_find_dev(BusState *bus, char *elem) +{ + BusChild *kid; + + /* + * try to match in order: + * (1) instance id, if present + * (2) driver name + * (3) driver alias, if present + */ + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + if (dev->id && strcmp(dev->id, elem) == 0) { + return dev; + } + } + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) { + return dev; + } + } + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (qdev_class_has_alias(dc) && + strcmp(qdev_class_get_alias(dc), elem) == 0) { + return dev; + } + } + return NULL; +} + +static BusState *qbus_find_recursive(BusState *bus, const char *name, + const char *bus_typename) +{ + BusClass *bus_class = BUS_GET_CLASS(bus); + BusChild *kid; + BusState *child, *ret; + int match = 1; + + if (name && (strcmp(bus->name, name) != 0)) { + match = 0; + } + if (bus_typename && !object_dynamic_cast(OBJECT(bus), bus_typename)) { + match = 0; + } + if ((bus_class->max_dev != 0) && (bus_class->max_dev <= bus->max_index)) { + if (name != NULL) { + /* bus was explicitly specified: return an error. */ + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Bus '%s' is full", + bus->name); + return NULL; + } else { + /* bus was not specified: try to find another one. */ + match = 0; + } + } + if (match) { + return bus; + } + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + QLIST_FOREACH(child, &dev->child_bus, sibling) { + ret = qbus_find_recursive(child, name, bus_typename); + if (ret) { + return ret; + } + } + } + return NULL; +} + +static BusState *qbus_find(const char *path) +{ + DeviceState *dev; + BusState *bus; + char elem[128]; + int pos, len; + + /* find start element */ + if (path[0] == '/') { + bus = sysbus_get_default(); + pos = 0; + } else { + if (sscanf(path, "%127[^/]%n", elem, &len) != 1) { + assert(!path[0]); + elem[0] = len = 0; + } + bus = qbus_find_recursive(sysbus_get_default(), elem, NULL); + if (!bus) { + qerror_report(QERR_BUS_NOT_FOUND, elem); + return NULL; + } + pos = len; + } + + for (;;) { + assert(path[pos] == '/' || !path[pos]); + while (path[pos] == '/') { + pos++; + } + if (path[pos] == '\0') { + return bus; + } + + /* find device */ + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; + } + pos += len; + dev = qbus_find_dev(bus, elem); + if (!dev) { + qerror_report(QERR_DEVICE_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_dev(bus); + } + return NULL; + } + + assert(path[pos] == '/' || !path[pos]); + while (path[pos] == '/') { + pos++; + } + if (path[pos] == '\0') { + /* last specified element is a device. If it has exactly + * one child bus accept it nevertheless */ + switch (dev->num_child_bus) { + case 0: + qerror_report(QERR_DEVICE_NO_BUS, elem); + return NULL; + case 1: + return QLIST_FIRST(&dev->child_bus); + default: + qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } + return NULL; + } + } + + /* find bus */ + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; + } + pos += len; + bus = qbus_find_bus(dev, elem); + if (!bus) { + qerror_report(QERR_BUS_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } + return NULL; + } + } +} + +DeviceState *qdev_device_add(QemuOpts *opts) +{ + ObjectClass *obj; + DeviceClass *k; + const char *driver, *path, *id; + DeviceState *qdev; + BusState *bus; + + driver = qemu_opt_get(opts, "driver"); + if (!driver) { + qerror_report(QERR_MISSING_PARAMETER, "driver"); + return NULL; + } + + /* find driver */ + obj = object_class_by_name(driver); + if (!obj) { + const char *typename = find_typename_by_alias(driver); + + if (typename) { + driver = typename; + obj = object_class_by_name(driver); + } + } + + if (!obj) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type"); + return NULL; + } + + k = DEVICE_CLASS(obj); + + /* find bus */ + path = qemu_opt_get(opts, "bus"); + if (path != NULL) { + bus = qbus_find(path); + if (!bus) { + return NULL; + } + if (!object_dynamic_cast(OBJECT(bus), k->bus_type)) { + qerror_report(QERR_BAD_BUS_FOR_DEVICE, + driver, object_get_typename(OBJECT(bus))); + return NULL; + } + } else { + bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type); + if (!bus) { + qerror_report(QERR_NO_BUS_FOR_DEVICE, + k->bus_type, driver); + return NULL; + } + } + if (qdev_hotplug && !bus->allow_hotplug) { + qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); + return NULL; + } + + if (!bus) { + bus = sysbus_get_default(); + } + + /* create device, set properties */ + qdev = DEVICE(object_new(driver)); + qdev_set_parent_bus(qdev, bus); + + id = qemu_opts_id(opts); + if (id) { + qdev->id = id; + } + if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) { + qdev_free(qdev); + return NULL; + } + if (qdev->id) { + object_property_add_child(qdev_get_peripheral(), qdev->id, + OBJECT(qdev), NULL); + } else { + static int anon_count; + gchar *name = g_strdup_printf("device[%d]", anon_count++); + object_property_add_child(qdev_get_peripheral_anon(), name, + OBJECT(qdev), NULL); + g_free(name); + } + if (qdev_init(qdev) < 0) { + qerror_report(QERR_DEVICE_INIT_FAILED, driver); + return NULL; + } + qdev->opts = opts; + return qdev; +} + + +#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) +static void qbus_print(Monitor *mon, BusState *bus, int indent); + +static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, + int indent) +{ + if (!props) + return; + for (; props->name; props++) { + Error *err = NULL; + char *value; + char *legacy_name = g_strdup_printf("legacy-%s", props->name); + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { + value = object_property_get_str(OBJECT(dev), legacy_name, &err); + } else { + value = object_property_print(OBJECT(dev), props->name, &err); + } + g_free(legacy_name); + + if (err) { + error_free(err); + continue; + } + qdev_printf("%s = %s\n", props->name, + value && *value ? value : ""); + g_free(value); + } +} + +static void bus_print_dev(BusState *bus, Monitor *mon, DeviceState *dev, int indent) +{ + BusClass *bc = BUS_GET_CLASS(bus); + + if (bc->print_dev) { + bc->print_dev(mon, dev, indent); + } +} + +static void qdev_print(Monitor *mon, DeviceState *dev, int indent) +{ + ObjectClass *class; + BusState *child; + qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)), + dev->id ? dev->id : ""); + indent += 2; + if (dev->num_gpio_in) { + qdev_printf("gpio-in %d\n", dev->num_gpio_in); + } + if (dev->num_gpio_out) { + qdev_printf("gpio-out %d\n", dev->num_gpio_out); + } + class = object_get_class(OBJECT(dev)); + do { + qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent); + class = object_class_get_parent(class); + } while (class != object_class_by_name(TYPE_DEVICE)); + bus_print_dev(dev->parent_bus, mon, dev, indent); + QLIST_FOREACH(child, &dev->child_bus, sibling) { + qbus_print(mon, child, indent); + } +} + +static void qbus_print(Monitor *mon, BusState *bus, int indent) +{ + BusChild *kid; + + qdev_printf("bus: %s\n", bus->name); + indent += 2; + qdev_printf("type %s\n", object_get_typename(OBJECT(bus))); + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + qdev_print(mon, dev, indent); + } +} +#undef qdev_printf + +void do_info_qtree(Monitor *mon, const QDict *qdict) +{ + if (sysbus_get_default()) + qbus_print(mon, sysbus_get_default(), 0); +} + +void do_info_qdm(Monitor *mon, const QDict *qdict) +{ + object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL); +} + +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + Error *local_err = NULL; + QemuOpts *opts; + DeviceState *dev; + + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { + qemu_opts_del(opts); + return 0; + } + dev = qdev_device_add(opts); + if (!dev) { + qemu_opts_del(opts); + return -1; + } + object_unref(OBJECT(dev)); + return 0; +} + +void qmp_device_del(const char *id, Error **errp) +{ + DeviceState *dev; + + dev = qdev_find_recursive(sysbus_get_default(), id); + if (NULL == dev) { + error_set(errp, QERR_DEVICE_NOT_FOUND, id); + return; + } + + qdev_unplug(dev, errp); +} + +void qdev_machine_init(void) +{ + qdev_get_peripheral_anon(); + qdev_get_peripheral(); +} + +QemuOptsList qemu_device_opts = { + .name = "device", + .implied_opt_name = "driver", + .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head), + .desc = { + /* + * no elements => accept any + * sanity checking will happen later + * when setting device properties + */ + { /* end of list */ } + }, +}; + +QemuOptsList qemu_global_opts = { + .name = "global", + .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), + .desc = { + { + .name = "driver", + .type = QEMU_OPT_STRING, + },{ + .name = "property", + .type = QEMU_OPT_STRING, + },{ + .name = "value", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +int qemu_global_option(const char *str) +{ + char driver[64], property[64]; + QemuOpts *opts; + int rc, offset; + + rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); + if (rc < 2 || str[offset] != '=') { + error_report("can't parse: \"%s\"", str); + return -1; + } + + opts = qemu_opts_create_nofail(&qemu_global_opts); + qemu_opt_set(opts, "driver", driver); + qemu_opt_set(opts, "property", property); + qemu_opt_set(opts, "value", str+offset+1); + return 0; +} diff --git a/util/qemu-config.c b/util/qemu-config.c index db6ec03a78..01ca8901cf 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -2,6 +2,7 @@ #include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/config-file.h" +#include "qapi/qmp/qerror.h" #include "hw/qdev.h" #include "qapi/error.h" diff --git a/vl.c b/vl.c index e0a8eeb24b..bbdbafdca6 100644 --- a/vl.c +++ b/vl.c @@ -126,6 +126,7 @@ int main(int argc, char **argv) #include "hw/xen.h" #include "hw/qdev.h" #include "hw/loader.h" +#include "monitor/qdev.h" #include "bt/bt.h" #include "net/net.h" #include "net/slirp.h" -- cgit v1.2.3 From 1559e0d4b54d1b0744983b57da893617ceae8b94 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 17:20:47 +0100 Subject: hw: move device-hotplug.o to toplevel, compile it once The situation with device-hotplug.c is similar to qdev-monitor.c. Add a stub for pci_drive_hot_add, so that it can be compiled once, and move it out of hw/. Signed-off-by: Paolo Bonzini --- Makefile.objs | 2 +- device-hotplug.c | 79 ++++++++++++++++++++++++++++++++++++++++++ hw/Makefile.objs | 1 - hw/device-hotplug.c | 88 ----------------------------------------------- stubs/Makefile.objs | 1 + stubs/pci-drive-hot-add.c | 10 ++++++ 6 files changed, 91 insertions(+), 90 deletions(-) create mode 100644 device-hotplug.c delete mode 100644 hw/device-hotplug.c create mode 100644 stubs/pci-drive-hot-add.c diff --git a/Makefile.objs b/Makefile.objs index 2a8174dd15..8c90b92d01 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -51,7 +51,7 @@ ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ common-obj-y += readline.o -common-obj-y += qdev-monitor.o +common-obj-y += qdev-monitor.o device-hotplug.o common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o diff --git a/device-hotplug.c b/device-hotplug.c new file mode 100644 index 0000000000..103d34ac45 --- /dev/null +++ b/device-hotplug.c @@ -0,0 +1,79 @@ +/* + * QEMU device hotplug helpers + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/boards.h" +#include "sysemu/blockdev.h" +#include "qemu/config-file.h" +#include "sysemu/sysemu.h" +#include "monitor/monitor.h" + +DriveInfo *add_init_drive(const char *optstr) +{ + DriveInfo *dinfo; + QemuOpts *opts; + + opts = drive_def(optstr); + if (!opts) + return NULL; + + dinfo = drive_init(opts, current_machine->block_default_type); + if (!dinfo) { + qemu_opts_del(opts); + return NULL; + } + + return dinfo; +} + +void drive_hot_add(Monitor *mon, const QDict *qdict) +{ + DriveInfo *dinfo = NULL; + const char *opts = qdict_get_str(qdict, "opts"); + + dinfo = add_init_drive(opts); + if (!dinfo) { + goto err; + } + if (dinfo->devaddr) { + monitor_printf(mon, "Parameter addr not supported\n"); + goto err; + } + + switch (dinfo->type) { + case IF_NONE: + monitor_printf(mon, "OK\n"); + break; + default: + if (pci_drive_hot_add(mon, qdict, dinfo)) { + goto err; + } + } + return; + +err: + if (dinfo) { + drive_put_ref(dinfo); + } +} diff --git a/hw/Makefile.objs b/hw/Makefile.objs index f7ee133627..43f467a1ee 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -206,7 +206,6 @@ obj-$(CONFIG_SOFTMMU) += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ obj-$(CONFIG_VGA) += vga.o -obj-$(CONFIG_SOFTMMU) += device-hotplug.o obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o # Inter-VM PCI shared memory & VFIO PCI device assignment diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c deleted file mode 100644 index 88da145a89..0000000000 --- a/hw/device-hotplug.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * QEMU device hotplug helpers - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw.h" -#include "boards.h" -#include "sysemu/blockdev.h" -#include "qemu/config-file.h" -#include "sysemu/sysemu.h" -#include "monitor/monitor.h" - -DriveInfo *add_init_drive(const char *optstr) -{ - DriveInfo *dinfo; - QemuOpts *opts; - - opts = drive_def(optstr); - if (!opts) - return NULL; - - dinfo = drive_init(opts, current_machine->block_default_type); - if (!dinfo) { - qemu_opts_del(opts); - return NULL; - } - - return dinfo; -} - -#if !defined(TARGET_I386) -int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo) -{ - /* On non-x86 we don't do PCI hotplug */ - monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type); - return -1; -} -#endif - -void drive_hot_add(Monitor *mon, const QDict *qdict) -{ - DriveInfo *dinfo = NULL; - const char *opts = qdict_get_str(qdict, "opts"); - - dinfo = add_init_drive(opts); - if (!dinfo) { - goto err; - } - if (dinfo->devaddr) { - monitor_printf(mon, "Parameter addr not supported\n"); - goto err; - } - - switch (dinfo->type) { - case IF_NONE: - monitor_printf(mon, "OK\n"); - break; - default: - if (pci_drive_hot_add(mon, qdict, dinfo)) { - goto err; - } - } - return; - -err: - if (dinfo) { - drive_put_ref(dinfo); - } -} diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index a2603947db..9c55b34354 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -15,6 +15,7 @@ stub-obj-y += mon-printf.o stub-obj-y += mon-print-filename.o stub-obj-y += mon-protocol-event.o stub-obj-y += mon-set-error.o +stub-obj-y += pci-drive-hot-add.o stub-obj-y += reset.o stub-obj-y += set-fd-handler.o stub-obj-y += slirp.o diff --git a/stubs/pci-drive-hot-add.c b/stubs/pci-drive-hot-add.c new file mode 100644 index 0000000000..1d98145802 --- /dev/null +++ b/stubs/pci-drive-hot-add.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo) +{ + /* On non-x86 we don't do PCI hotplug */ + monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type); + return -1; +} -- cgit v1.2.3 From 7e6b14dfb575a687cb26be9995c96e5bbf5cba2e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:32:02 +0100 Subject: virtio-9p: use CONFIG_VIRTFS, not CONFIG_LINUX Signed-off-by: Paolo Bonzini --- hw/virtio-pci.h | 2 +- hw/virtio.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index d24957cc25..e775525c05 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -75,7 +75,7 @@ struct VirtIOPCIProxy { VirtIOBlkConf blk; NICConf nic; uint32_t host_features; -#ifdef CONFIG_LINUX +#ifdef CONFIG_VIRTFS V9fsConf fsconf; #endif virtio_serial_conf serial; diff --git a/hw/virtio.h b/hw/virtio.h index 1e206b8355..ae43d25193 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -19,7 +19,7 @@ #include "qdev.h" #include "sysemu/sysemu.h" #include "qemu/event_notifier.h" -#ifdef CONFIG_LINUX +#ifdef CONFIG_VIRTFS #include "9p.h" #endif @@ -252,7 +252,7 @@ typedef struct VirtIOSCSIConf VirtIOSCSIConf; VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf); typedef struct VirtIORNGConf VirtIORNGConf; VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf); -#ifdef CONFIG_LINUX +#ifdef CONFIG_VIRTFS VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); #endif -- cgit v1.2.3 From 60653b28f505288689d0b44218de4bb9fd254519 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:37:49 +0100 Subject: virtio-9p: remove PCI dependencies from hw/9pfs/ Also move the 9p.h file to 9pfs/virtio-9p-device.h, for consistency with the corresponding .c file. Signed-off-by: Paolo Bonzini --- hw/9p.h | 24 --------------------- hw/9pfs/virtio-9p-device.c | 53 +--------------------------------------------- hw/9pfs/virtio-9p-device.h | 24 +++++++++++++++++++++ hw/9pfs/virtio-9p.c | 3 +-- hw/9pfs/virtio-9p.h | 1 - hw/virtio-pci.c | 50 ++++++++++++++++++++++++++++++++++++++++++- hw/virtio-pci.h | 2 +- hw/virtio.h | 2 +- 8 files changed, 77 insertions(+), 82 deletions(-) delete mode 100644 hw/9p.h create mode 100644 hw/9pfs/virtio-9p-device.h diff --git a/hw/9p.h b/hw/9p.h deleted file mode 100644 index d9951d6bcc..0000000000 --- a/hw/9p.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Virtio 9p - * - * Copyright IBM, Corp. 2010 - * - * Authors: - * Aneesh Kumar K.V - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#ifndef QEMU_9P_H -#define QEMU_9P_H - -typedef struct V9fsConf -{ - /* tag name for the device */ - char *tag; - char *fsdev_id; -} V9fsConf; - -#endif diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 74155fb61e..d321c802f2 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -14,9 +14,9 @@ #include "hw/virtio.h" #include "hw/pc.h" #include "qemu/sockets.h" -#include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" +#include "virtio-9p-device.h" #include "virtio-9p-xattr.h" #include "virtio-9p-coth.h" @@ -136,54 +136,3 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) return &s->vdev; } - -static int virtio_9p_init_pci(PCIDevice *pci_dev) -{ - VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); - VirtIODevice *vdev; - - vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); - vdev->nvectors = proxy->nvectors; - virtio_init_pci(proxy, vdev); - /* make the actual value visible */ - proxy->nvectors = vdev->nvectors; - return 0; -} - -static Property virtio_9p_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), - DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_9p_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = virtio_9p_init_pci; - k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = PCI_DEVICE_ID_VIRTIO_9P; - k->revision = VIRTIO_PCI_ABI_VERSION; - k->class_id = 0x2; - dc->props = virtio_9p_properties; - dc->reset = virtio_pci_reset; -} - -static const TypeInfo virtio_9p_info = { - .name = "virtio-9p-pci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VirtIOPCIProxy), - .class_init = virtio_9p_class_init, -}; - -static void virtio_9p_register_types(void) -{ - type_register_static(&virtio_9p_info); - virtio_9p_set_fd_limit(); -} - -type_init(virtio_9p_register_types) diff --git a/hw/9pfs/virtio-9p-device.h b/hw/9pfs/virtio-9p-device.h new file mode 100644 index 0000000000..65789db131 --- /dev/null +++ b/hw/9pfs/virtio-9p-device.h @@ -0,0 +1,24 @@ +/* + * Virtio 9p + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Aneesh Kumar K.V + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_VIRTIO_9P_DEVICE_H +#define QEMU_VIRTIO_9P_DEVICE_H + +typedef struct V9fsConf +{ + /* tag name for the device */ + char *tag; + char *fsdev_id; +} V9fsConf; + +#endif diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index d3ea820eae..5cc4c92012 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -14,7 +14,6 @@ #include "hw/virtio.h" #include "hw/pc.h" #include "qemu/sockets.h" -#include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" #include "virtio-9p-xattr.h" @@ -3269,7 +3268,7 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) free_pdu(s, pdu); } -void virtio_9p_set_fd_limit(void) +static void __attribute__((__constructor__)) virtio_9p_set_fd_limit(void) { struct rlimit rlim; if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 406fe522db..52b1c6997f 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -389,7 +389,6 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) } extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq); -extern void virtio_9p_set_fd_limit(void); extern void v9fs_reclaim_fd(V9fsPDU *pdu); extern void v9fs_path_init(V9fsPath *path); extern void v9fs_path_free(V9fsPath *path); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index a869f535de..df1dd7744c 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -255,7 +255,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) proxy->ioeventfd_started = false; } -void virtio_pci_reset(DeviceState *d) +static void virtio_pci_reset(DeviceState *d) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); virtio_pci_stop_ioeventfd(proxy); @@ -1313,6 +1313,51 @@ static const TypeInfo virtio_scsi_info = { .class_init = virtio_scsi_class_init, }; +#ifdef CONFIG_VIRTFS +static int virtio_9p_init_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev; + + vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); + vdev->nvectors = proxy->nvectors; + virtio_init_pci(proxy, vdev); + /* make the actual value visible */ + proxy->nvectors = vdev->nvectors; + return 0; +} + +static Property virtio_9p_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), + DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_9p_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_9p_init_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_9P; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = 0x2; + dc->props = virtio_9p_properties; + dc->reset = virtio_pci_reset; +} + +static const TypeInfo virtio_9p_info = { + .name = "virtio-9p-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_9p_class_init, +}; +#endif + /* * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. */ @@ -1475,6 +1520,9 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_rng_info); type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); +#ifdef CONFIG_VIRTFS + type_register_static(&virtio_9p_info); +#endif } type_init(virtio_pci_register_types) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index e775525c05..d01db97e1e 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -22,6 +22,7 @@ #include "virtio-serial.h" #include "virtio-scsi.h" #include "virtio-bus.h" +#include "9pfs/virtio-9p-device.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; @@ -90,7 +91,6 @@ struct VirtIOPCIProxy { }; void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev); -void virtio_pci_reset(DeviceState *d); void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev); /* Virtio ABI version, if we increment this, we break the guest driver. */ diff --git a/hw/virtio.h b/hw/virtio.h index ae43d25193..8cc71e99b6 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -20,7 +20,7 @@ #include "sysemu/sysemu.h" #include "qemu/event_notifier.h" #ifdef CONFIG_VIRTFS -#include "9p.h" +#include "9pfs/virtio-9p-device.h" #endif /* from Linux's linux/virtio_config.h */ -- cgit v1.2.3 From eac7ec7f6a5c9e1a0a082ea8525f31549b1f0cb4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:00:38 +0100 Subject: vt82c686: vt82c686 is not a PCI host bridge Signed-off-by: Paolo Bonzini --- hw/vt82c686.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 2d8e3988db..c2b1bfce10 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -26,8 +26,6 @@ #include "qemu/timer.h" #include "exec/address-spaces.h" -typedef uint32_t pci_addr_t; -#include "pci/pci_host.h" //#define DEBUG_VT82C686B #ifdef DEBUG_VT82C686B -- cgit v1.2.3 From 7948b4b009b60c6e3b21daad29088b204ddb1966 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 3 Feb 2013 20:18:28 +0100 Subject: ppc: do not use ../ in include files This simplifies the scripted execution of the next patch. Signed-off-by: Paolo Bonzini --- hw/ppc/e500-ccsr.h | 2 +- hw/ppc/e500plat.c | 2 +- hw/ppc/mpc8544ds.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppc/e500-ccsr.h b/hw/ppc/e500-ccsr.h index f20f51bcd2..12a2ba4b97 100644 --- a/hw/ppc/e500-ccsr.h +++ b/hw/ppc/e500-ccsr.h @@ -1,7 +1,7 @@ #ifndef E500_CCSR_H #define E500_CCSR_H -#include "../sysbus.h" +#include "hw/sysbus.h" typedef struct PPCE500CCSRState { /*< private >*/ diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 25ac4b1dae..4b3057528c 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -12,7 +12,7 @@ #include "config.h" #include "qemu-common.h" #include "e500.h" -#include "../boards.h" +#include "hw/boards.h" #include "sysemu/device_tree.h" #include "hw/pci/pci.h" #include "hw/openpic.h" diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index e25c70b1f3..cf29788c4d 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -12,7 +12,7 @@ #include "config.h" #include "qemu-common.h" #include "e500.h" -#include "../boards.h" +#include "hw/boards.h" #include "sysemu/device_tree.h" #include "hw/openpic.h" -- cgit v1.2.3 From 83c9f4ca794ec3b6fa7e5a5bb055d378916503e0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:40:22 +0100 Subject: hw: include hw header files with full paths Done with this script: cd hw for i in `find . -name '*.h' | sed 's/^..//'`; do echo '\,^#.*include.*["<]'$i'[">], s,'$i',hw/&,' done | sed -i -f - `find . -type f` This is so that paths remain valid as files are moved. Instead, files in hw/dataplane are referenced with the relative path. We know they are not going to move to include/, and they are the only include files that are in subdirectories _and_ move. Signed-off-by: Paolo Bonzini --- hw/a15mpcore.c | 2 +- hw/a9mpcore.c | 2 +- hw/a9scu.c | 2 +- hw/ac97.c | 6 +++--- hw/acpi.c | 6 +++--- hw/acpi_ich9.c | 10 +++++----- hw/acpi_ich9.h | 2 +- hw/acpi_piix4.c | 14 +++++++------- hw/adb.c | 4 ++-- hw/adb.h | 2 +- hw/adlib.c | 8 ++++---- hw/ads7846.c | 2 +- hw/alpha_dp264.c | 16 ++++++++-------- hw/alpha_pci.c | 2 +- hw/alpha_sys.h | 10 +++++----- hw/alpha_typhoon.c | 6 +++--- hw/an5206.c | 8 ++++---- hw/apb_pci.c | 12 ++++++------ hw/apic.c | 12 ++++++------ hw/apic_common.c | 4 ++-- hw/apic_internal.h | 2 +- hw/apm.c | 6 +++--- hw/apm.h | 2 +- hw/applesmc.c | 4 ++-- hw/arm11mpcore.c | 2 +- hw/arm_boot.c | 8 ++++---- hw/arm_gic.c | 4 ++-- hw/arm_gic_common.c | 2 +- hw/arm_gic_internal.h | 2 +- hw/arm_l2x0.c | 2 +- hw/arm_mptimer.c | 2 +- hw/arm_pic.c | 4 ++-- hw/arm_sysctl.c | 6 +++--- hw/arm_timer.c | 6 +++--- hw/armv7m.c | 6 +++--- hw/armv7m_nvic.c | 6 +++--- hw/axis_dev88.c | 12 ++++++------ hw/bitbang_i2c.c | 6 +++--- hw/bitbang_i2c.h | 2 +- hw/blizzard.c | 14 +++++++------- hw/boards.h | 2 +- hw/bonito.c | 10 +++++----- hw/bt-hci-csr.c | 4 ++-- hw/bt-hci.c | 4 ++-- hw/bt-hid.c | 4 ++-- hw/bt-l2cap.c | 2 +- hw/bt-sdp.c | 2 +- hw/bt.c | 2 +- hw/cadence_gem.c | 2 +- hw/cadence_ttc.c | 2 +- hw/cadence_uart.c | 2 +- hw/cbus.c | 4 ++-- hw/ccid.h | 2 +- hw/cdrom.c | 2 +- hw/cirrus_vga.c | 44 +++++++++++++++++++++---------------------- hw/cirrus_vga_rop.h | 8 ++++---- hw/collie.c | 14 +++++++------- hw/cris-boot.c | 6 +++--- hw/cris_pic_cpu.c | 6 +++--- hw/cs4231.c | 2 +- hw/cs4231a.c | 8 ++++---- hw/cuda.c | 6 +++--- hw/dataplane/event-poll.c | 2 +- hw/dataplane/ioq.c | 2 +- hw/dataplane/virtio-blk.c | 2 +- hw/dataplane/vring.c | 2 +- hw/dataplane/vring.h | 2 +- hw/debugcon.c | 6 +++--- hw/debugexit.c | 4 ++-- hw/dec_pci.c | 12 ++++++------ hw/dma.c | 4 ++-- hw/dp8393x.c | 4 ++-- hw/ds1225y.c | 2 +- hw/ds1338.c | 2 +- hw/dummy_m68k.c | 6 +++--- hw/e1000.c | 8 ++++---- hw/ecc.c | 4 ++-- hw/eccmemctl.c | 2 +- hw/eepro100.c | 6 +++--- hw/eeprom93xx.c | 4 ++-- hw/empty_slot.c | 6 +++--- hw/es1370.c | 6 +++--- hw/escc.c | 6 +++--- hw/esp-pci.c | 6 +++--- hw/esp.c | 4 ++-- hw/esp.h | 2 +- hw/etraxfs.h | 2 +- hw/etraxfs_dma.c | 4 ++-- hw/etraxfs_eth.c | 4 ++-- hw/etraxfs_pic.c | 4 ++-- hw/etraxfs_ser.c | 2 +- hw/etraxfs_timer.c | 4 ++-- hw/exynos4210.c | 12 ++++++------ hw/exynos4210_combiner.c | 4 ++-- hw/exynos4210_fimd.c | 2 +- hw/exynos4210_gic.c | 6 +++--- hw/exynos4210_i2c.c | 4 ++-- hw/exynos4210_mct.c | 6 +++--- hw/exynos4210_pmu.c | 2 +- hw/exynos4210_pwm.c | 6 +++--- hw/exynos4210_rtc.c | 8 ++++---- hw/exynos4210_uart.c | 4 ++-- hw/exynos4_boards.c | 8 ++++---- hw/fdc.c | 10 +++++----- hw/fmopl.c | 2 +- hw/framebuffer.c | 4 ++-- hw/fw_cfg.c | 8 ++++---- hw/g364fb.c | 4 ++-- hw/grackle_pci.c | 6 +++--- hw/grlib.h | 4 ++-- hw/grlib_apbuart.c | 2 +- hw/grlib_gptimer.c | 4 ++-- hw/grlib_irqmp.c | 4 ++-- hw/gt64xxx.c | 10 +++++----- hw/gumstix.c | 10 +++++----- hw/gus.c | 10 +++++----- hw/gusemu_hal.c | 4 ++-- hw/gusemu_mixer.c | 4 ++-- hw/hda-audio.c | 8 ++++---- hw/heathrow_pic.c | 4 ++-- hw/hid.c | 4 ++-- hw/highbank.c | 12 ++++++------ hw/hpet.c | 12 ++++++------ hw/hw.h | 2 +- hw/i2c.c | 2 +- hw/i2c.h | 2 +- hw/i82374.c | 2 +- hw/i82378.c | 8 ++++---- hw/i8254.c | 10 +++++----- hw/i8254.h | 4 ++-- hw/i8254_common.c | 10 +++++----- hw/i8254_internal.h | 6 +++--- hw/i8259.c | 8 ++++---- hw/i8259_common.c | 4 ++-- hw/i8259_internal.h | 6 +++--- hw/i82801b11.c | 4 ++-- hw/ich9.h | 26 ++++++++++++------------- hw/ide.h | 4 ++-- hw/imx_avic.c | 4 ++-- hw/imx_ccm.c | 6 +++--- hw/imx_serial.c | 6 +++--- hw/imx_timer.c | 8 ++++---- hw/integratorcp.c | 8 ++++---- hw/intel-hda.c | 12 ++++++------ hw/intel-hda.h | 2 +- hw/ioapic.c | 10 +++++----- hw/ioapic_common.c | 6 +++--- hw/ioapic_internal.h | 4 ++-- hw/ioh3420.c | 8 ++++---- hw/ioh3420.h | 2 +- hw/ipack.c | 2 +- hw/ipack.h | 2 +- hw/ipoctal232.c | 2 +- hw/irq.c | 2 +- hw/isa-bus.c | 6 +++--- hw/isa.h | 2 +- hw/isa_mmio.c | 4 ++-- hw/ivshmem.c | 8 ++++---- hw/jazz_led.c | 2 +- hw/kvmvapic.c | 2 +- hw/kzm.c | 14 +++++++------- hw/lan9118.c | 6 +++--- hw/lance.c | 6 +++--- hw/leon3.c | 10 +++++----- hw/lm32_boards.c | 16 ++++++++-------- hw/lm32_hwsetup.h | 2 +- hw/lm32_juart.c | 6 +++--- hw/lm32_pic.c | 8 ++++---- hw/lm32_sys.c | 4 ++-- hw/lm32_timer.c | 6 +++--- hw/lm32_uart.c | 4 ++-- hw/lm4549.c | 4 ++-- hw/lm832x.c | 4 ++-- hw/loader.c | 12 ++++++------ hw/lpc_ich9.c | 28 +++++++++++++-------------- hw/lsi53c895a.c | 6 +++--- hw/m25p80.c | 6 +++--- hw/m48t59.c | 8 ++++---- hw/mac_dbdma.c | 6 +++--- hw/mac_nvram.c | 6 +++--- hw/macio.c | 10 +++++----- hw/mainstone.c | 14 +++++++------- hw/marvell_88w8618_audio.c | 8 ++++---- hw/max111x.c | 2 +- hw/max7310.c | 2 +- hw/mc146818rtc.c | 6 +++--- hw/mc146818rtc.h | 4 ++-- hw/mcf5206.c | 6 +++--- hw/mcf5208.c | 10 +++++----- hw/mcf_fec.c | 4 ++-- hw/mcf_intc.c | 4 ++-- hw/mcf_uart.c | 4 ++-- hw/megasas.c | 12 ++++++------ hw/microblaze_boot.c | 4 ++-- hw/microblaze_boot.h | 2 +- hw/microblaze_pic_cpu.c | 4 ++-- hw/milkymist-ac97.c | 4 ++-- hw/milkymist-hpdmc.c | 4 ++-- hw/milkymist-hw.h | 4 ++-- hw/milkymist-memcard.c | 6 +++--- hw/milkymist-minimac2.c | 6 +++--- hw/milkymist-pfpu.c | 4 ++-- hw/milkymist-softusb.c | 6 +++--- hw/milkymist-sysctl.c | 6 +++--- hw/milkymist-tmu2.c | 4 ++-- hw/milkymist-uart.c | 4 ++-- hw/milkymist-vgafb.c | 16 ++++++++-------- hw/milkymist.c | 16 ++++++++-------- hw/mips_addr.c | 4 ++-- hw/mips_fulong2e.c | 32 +++++++++++++++---------------- hw/mips_int.c | 4 ++-- hw/mips_jazz.c | 30 ++++++++++++++--------------- hw/mips_malta.c | 34 ++++++++++++++++----------------- hw/mips_mipssim.c | 18 +++++++++--------- hw/mips_r4k.c | 26 ++++++++++++------------- hw/mips_timer.c | 4 ++-- hw/mipsnet.c | 4 ++-- hw/mpc8544_guts.c | 4 ++-- hw/mst_fpga.c | 4 ++-- hw/multiboot.c | 8 ++++---- hw/musicpal.c | 16 ++++++++-------- hw/nand.c | 6 +++--- hw/ne2000-isa.c | 10 +++++----- hw/ne2000.c | 8 ++++---- hw/nseries.c | 22 +++++++++++----------- hw/omap1.c | 10 +++++----- hw/omap2.c | 12 ++++++------ hw/omap_clk.c | 4 ++-- hw/omap_dma.c | 6 +++--- hw/omap_dss.c | 4 ++-- hw/omap_gpio.c | 6 +++--- hw/omap_gpmc.c | 6 +++--- hw/omap_gptimer.c | 4 ++-- hw/omap_i2c.c | 8 ++++---- hw/omap_intc.c | 6 +++--- hw/omap_l4.c | 4 ++-- hw/omap_lcdc.c | 14 +++++++------- hw/omap_mmc.c | 6 +++--- hw/omap_sdrc.c | 4 ++-- hw/omap_spi.c | 4 ++-- hw/omap_sx1.c | 10 +++++----- hw/omap_synctimer.c | 4 ++-- hw/omap_tap.c | 4 ++-- hw/omap_uart.c | 6 +++--- hw/onenand.c | 8 ++++---- hw/opencores_eth.c | 4 ++-- hw/openpic.c | 14 +++++++------- hw/openrisc_pic.c | 2 +- hw/openrisc_sim.c | 10 +++++----- hw/openrisc_timer.c | 2 +- hw/palm.c | 12 ++++++------ hw/pam.c | 2 +- hw/parallel.c | 6 +++--- hw/pc-testdev.c | 6 +++--- hw/pc.c | 36 +++++++++++++++++------------------ hw/pc.h | 6 +++--- hw/pc87312.c | 2 +- hw/pc87312.h | 2 +- hw/pc_piix.c | 24 +++++++++++------------ hw/pc_q35.c | 16 ++++++++-------- hw/pc_sysfw.c | 10 +++++----- hw/pci_bridge_dev.c | 12 ++++++------ hw/pckbd.c | 8 ++++---- hw/pcnet-pci.c | 6 +++--- hw/pcnet.c | 4 ++-- hw/pcspk.c | 10 +++++----- hw/pcspk.h | 4 ++-- hw/petalogix_ml605_mmu.c | 22 +++++++++++----------- hw/petalogix_s3adsp1800_mmu.c | 16 ++++++++-------- hw/pflash_cfi01.c | 6 +++--- hw/pflash_cfi02.c | 6 +++--- hw/piix4.c | 10 +++++----- hw/piix_pci.c | 16 ++++++++-------- hw/pl011.c | 2 +- hw/pl022.c | 4 ++-- hw/pl031.c | 2 +- hw/pl041.c | 6 +++--- hw/pl050.c | 4 ++-- hw/pl061.c | 2 +- hw/pl080.c | 2 +- hw/pl110.c | 14 +++++++------- hw/pl110_template.h | 12 ++++++------ hw/pl181.c | 4 ++-- hw/pl190.c | 2 +- hw/pm_smbus.c | 8 ++++---- hw/ppc.c | 8 ++++---- hw/ppc405.h | 2 +- hw/ppc405_boards.c | 14 +++++++------- hw/ppc405_uc.c | 8 ++++---- hw/ppc440_bamboo.c | 16 ++++++++-------- hw/ppc4xx.h | 2 +- hw/ppc4xx_devs.c | 6 +++--- hw/ppc4xx_pci.c | 10 +++++----- hw/ppc_booke.c | 8 ++++---- hw/ppce500_pci.c | 8 ++++---- hw/ppce500_spin.c | 4 ++-- hw/prep_pci.c | 10 +++++----- hw/ps2.c | 4 ++-- hw/ptimer.c | 4 ++-- hw/puv3.c | 10 +++++----- hw/puv3_dma.c | 6 +++--- hw/puv3_gpio.c | 6 +++--- hw/puv3_intc.c | 4 ++-- hw/puv3_ost.c | 6 +++--- hw/puv3_pm.c | 6 +++--- hw/pxa2xx.c | 10 +++++----- hw/pxa2xx_dma.c | 6 +++--- hw/pxa2xx_gpio.c | 6 +++--- hw/pxa2xx_keypad.c | 4 ++-- hw/pxa2xx_lcd.c | 16 ++++++++-------- hw/pxa2xx_mmci.c | 8 ++++---- hw/pxa2xx_pcmcia.c | 6 +++--- hw/pxa2xx_pic.c | 6 +++--- hw/pxa2xx_timer.c | 6 +++--- hw/q35.c | 4 ++-- hw/q35.h | 22 +++++++++++----------- hw/qdev-addr.c | 4 ++-- hw/qdev-properties-system.c | 2 +- hw/qdev-properties.c | 2 +- hw/qdev-properties.h | 2 +- hw/qdev.c | 2 +- hw/qdev.h | 4 ++-- hw/qxl-logger.c | 2 +- hw/qxl-render.c | 2 +- hw/qxl.c | 2 +- hw/qxl.h | 6 +++--- hw/r2d.c | 22 +++++++++++----------- hw/rc4030.c | 4 ++-- hw/realview.c | 14 +++++++------- hw/realview_gic.c | 2 +- hw/rtl8139.c | 6 +++--- hw/s390x/event-facility.c | 4 ++-- hw/s390x/s390-virtio-ccw.c | 2 +- hw/s390x/sclp.c | 2 +- hw/s390x/sclpconsole.c | 4 ++-- hw/s390x/sclpquiesce.c | 4 ++-- hw/sb16.c | 8 ++++---- hw/sbi.c | 2 +- hw/scsi-bus.c | 8 ++++---- hw/scsi-disk.c | 4 ++-- hw/scsi-generic.c | 4 ++-- hw/scsi.h | 2 +- hw/sd.c | 4 ++-- hw/sdhci.c | 4 ++-- hw/sdhci.h | 4 ++-- hw/serial-isa.c | 4 ++-- hw/serial-pci.c | 4 ++-- hw/serial.c | 2 +- hw/serial.h | 2 +- hw/sga.c | 6 +++--- hw/sh.h | 2 +- hw/sh7750.c | 10 +++++----- hw/sh7750_regnames.c | 8 ++++---- hw/sh_intc.c | 6 +++--- hw/sh_intc.h | 2 +- hw/sh_pci.c | 8 ++++---- hw/sh_serial.c | 4 ++-- hw/sh_timer.c | 6 +++--- hw/shix.c | 8 ++++---- hw/slavio_intctl.c | 4 ++-- hw/slavio_misc.c | 2 +- hw/slavio_timer.c | 6 +++--- hw/sm501.c | 24 +++++++++++------------ hw/smbios.c | 4 ++-- hw/smbus.c | 6 +++--- hw/smbus.h | 2 +- hw/smbus_eeprom.c | 6 +++--- hw/smbus_ich9.c | 14 +++++++------- hw/smc91c111.c | 4 ++-- hw/soc_dma.c | 2 +- hw/spapr.c | 4 ++-- hw/spapr_iommu.c | 4 ++-- hw/spapr_llan.c | 2 +- hw/spapr_pci.c | 10 +++++----- hw/spapr_vio.c | 6 +++--- hw/spapr_vscsi.c | 8 ++++---- hw/spapr_vty.c | 2 +- hw/sparc32_dma.c | 8 ++++---- hw/spitz.c | 22 +++++++++++----------- hw/ssd0303.c | 2 +- hw/ssd0323.c | 2 +- hw/ssi-sd.c | 4 ++-- hw/ssi.c | 2 +- hw/ssi.h | 2 +- hw/stellaris.c | 12 ++++++------ hw/stellaris_enet.c | 2 +- hw/stellaris_input.c | 4 ++-- hw/stream.c | 2 +- hw/strongarm.c | 8 ++++---- hw/sun4c_intctl.c | 6 +++--- hw/sun4m.c | 30 ++++++++++++++--------------- hw/sun4m.h | 2 +- hw/sun4m_iommu.c | 4 ++-- hw/sun4u.c | 26 ++++++++++++------------- hw/sysbus.c | 2 +- hw/sysbus.h | 2 +- hw/tc58128.c | 6 +++--- hw/tc6393xb.c | 16 ++++++++-------- hw/tcx.c | 4 ++-- hw/tmp105.c | 6 +++--- hw/tmp105.h | 4 ++-- hw/tosa.c | 20 ++++++++++---------- hw/tpci200.c | 4 ++-- hw/tsc2005.c | 4 ++-- hw/tsc210x.c | 6 +++--- hw/tusb6010.c | 10 +++++----- hw/twl92230.c | 4 ++-- hw/unin_pci.c | 8 ++++---- hw/usb.h | 2 +- hw/versatile_i2c.c | 4 ++-- hw/versatile_pci.c | 6 +++--- hw/versatilepb.c | 14 +++++++------- hw/vexpress.c | 12 ++++++------ hw/vfio_pci.c | 6 +++--- hw/vga-isa-mm.c | 6 +++--- hw/vga-isa.c | 8 ++++---- hw/vga-pci.c | 8 ++++---- hw/vga.c | 26 ++++++++++++------------- hw/vhost.c | 2 +- hw/vhost_net.c | 6 +++--- hw/virtex_ml507.c | 22 +++++++++++----------- hw/virtio-balloon.c | 6 +++--- hw/virtio-balloon.h | 4 ++-- hw/virtio-blk.c | 6 +++--- hw/virtio-blk.h | 2 +- hw/virtio-bus.c | 8 ++++---- hw/virtio-bus.h | 4 ++-- hw/virtio-console.c | 2 +- hw/virtio-net.c | 6 +++--- hw/virtio-net.h | 4 ++-- hw/virtio-pci.c | 22 +++++++++++----------- hw/virtio-pci.h | 14 +++++++------- hw/virtio-rng.c | 6 +++--- hw/virtio-scsi.c | 2 +- hw/virtio-scsi.h | 4 ++-- hw/virtio-serial-bus.c | 4 ++-- hw/virtio-serial.h | 4 ++-- hw/virtio.c | 4 ++-- hw/virtio.h | 6 +++--- hw/vmmouse.c | 8 ++++---- hw/vmport.c | 8 ++++---- hw/vmware_vga.c | 8 ++++---- hw/vt82c686.c | 24 +++++++++++------------ hw/wdt_i6300esb.c | 6 +++--- hw/wdt_ib700.c | 8 ++++---- hw/wm8750.c | 4 ++-- hw/xen-host-pci-device.c | 2 +- hw/xen-host-pci-device.h | 2 +- hw/xen_apic.c | 2 +- hw/xen_backend.c | 4 ++-- hw/xen_backend.h | 2 +- hw/xen_common.h | 4 ++-- hw/xen_console.c | 4 ++-- hw/xen_devconfig.c | 2 +- hw/xen_disk.c | 6 +++--- hw/xen_domainbuild.c | 4 ++-- hw/xen_domainbuild.h | 2 +- hw/xen_machine_pv.c | 10 +++++----- hw/xen_nic.c | 4 ++-- hw/xen_platform.c | 12 ++++++------ hw/xen_pt.c | 8 ++++---- hw/xen_pt.h | 6 +++--- hw/xen_pt_config_init.c | 4 ++-- hw/xen_pt_msi.c | 6 +++--- hw/xenfb.c | 4 ++-- hw/xgmac.c | 2 +- hw/xics.c | 2 +- hw/xilinx.h | 2 +- hw/xilinx_axidma.c | 8 ++++---- hw/xilinx_axienet.c | 4 ++-- hw/xilinx_ethlite.c | 4 ++-- hw/xilinx_intc.c | 4 ++-- hw/xilinx_spi.c | 4 ++-- hw/xilinx_spips.c | 6 +++--- hw/xilinx_timer.c | 4 ++-- hw/xilinx_uartlite.c | 2 +- hw/xilinx_zynq.c | 12 ++++++------ hw/xio3130_downstream.c | 8 ++++---- hw/xio3130_downstream.h | 2 +- hw/xio3130_upstream.c | 8 ++++---- hw/xio3130_upstream.h | 2 +- hw/xtensa_lx60.c | 12 ++++++------ hw/xtensa_pic.c | 2 +- hw/xtensa_sim.c | 4 ++-- hw/z2.c | 16 ++++++++-------- hw/zaurus.c | 6 +++--- hw/zynq_slcr.c | 4 ++-- 487 files changed, 1604 insertions(+), 1604 deletions(-) diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index fe6c34ca53..d973d53f0a 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -18,7 +18,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" /* A15MP private memory region. */ diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 01aee0264d..0a1a10f37a 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -8,7 +8,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" typedef struct A9MPPrivState { SysBusDevice busdev; diff --git a/hw/a9scu.c b/hw/a9scu.c index 0e9e54d7fb..05897c2fa2 100644 --- a/hw/a9scu.c +++ b/hw/a9scu.c @@ -8,7 +8,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" /* A9MP private memory region. */ diff --git a/hw/ac97.c b/hw/ac97.c index 6c565e755c..c7d601fdb7 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -17,10 +17,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" enum { diff --git a/hw/acpi.c b/hw/acpi.c index 8c9dcc51c4..53e47d5857 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -19,9 +19,9 @@ * GNU GPL, version 2 or (at your option) any later version. */ #include "sysemu/sysemu.h" -#include "hw.h" -#include "pc.h" -#include "acpi.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/acpi.h" #include "monitor/monitor.h" struct acpi_table_header { diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c index d2f9808242..29f84ffb45 100644 --- a/hw/acpi_ich9.c +++ b/hw/acpi_ich9.c @@ -23,16 +23,16 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "acpi.h" +#include "hw/acpi.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" -#include "ich9.h" +#include "hw/ich9.h" //#define DEBUG diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h index ecb82abc65..91c3aeb7ea 100644 --- a/hw/acpi_ich9.h +++ b/hw/acpi_ich9.h @@ -21,7 +21,7 @@ #ifndef HW_ACPI_ICH9_H #define HW_ACPI_ICH9_H -#include "acpi.h" +#include "hw/acpi.h" typedef struct ICH9LPCPMRegs { /* diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 65b26013bd..7a4b712919 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -18,16 +18,16 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "apm.h" -#include "pm_smbus.h" -#include "pci/pci.h" -#include "acpi.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/pm_smbus.h" +#include "hw/pci/pci.h" +#include "hw/acpi.h" #include "sysemu/sysemu.h" #include "qemu/range.h" #include "exec/ioport.h" -#include "fw_cfg.h" +#include "hw/fw_cfg.h" #include "exec/address-spaces.h" //#define DEBUG diff --git a/hw/adb.c b/hw/adb.c index 6cf54650c8..fd9052c16b 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "adb.h" +#include "hw/hw.h" +#include "hw/adb.h" #include "ui/console.h" /* debug ADB */ diff --git a/hw/adb.h b/hw/adb.h index 721f1ac43e..bdfccd4041 100644 --- a/hw/adb.h +++ b/hw/adb.h @@ -26,7 +26,7 @@ #if !defined(__ADB_H__) #define __ADB_H__ -#include "qdev.h" +#include "hw/qdev.h" #define MAX_ADB_DEVICES 16 diff --git a/hw/adlib.c b/hw/adlib.c index 07c69fc967..e6bce59512 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" +#include "hw/isa.h" //#define DEBUG @@ -47,7 +47,7 @@ void YMF262UpdateOneQEMU (int which, INT16 *dst, int length); #define SHIFT 2 #else -#include "fmopl.h" +#include "hw/fmopl.h" #define SHIFT 1 #endif diff --git a/hw/ads7846.c b/hw/ads7846.c index 29e5585d91..5da3dc5b2c 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -10,7 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "ssi.h" +#include "hw/ssi.h" #include "ui/console.h" typedef struct { diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 1cd549c69f..13aaa57b90 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -6,16 +6,16 @@ * that we need to emulate as well. */ -#include "hw.h" +#include "hw/hw.h" #include "elf.h" -#include "loader.h" -#include "boards.h" -#include "alpha_sys.h" +#include "hw/loader.h" +#include "hw/boards.h" +#include "hw/alpha_sys.h" #include "sysemu/sysemu.h" -#include "mc146818rtc.h" -#include "ide.h" -#include "i8254.h" -#include "serial.h" +#include "hw/mc146818rtc.h" +#include "hw/ide.h" +#include "hw/i8254.h" +#include "hw/serial.h" #define MAX_IDE_BUS 2 diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index 7327d488fd..84628686ad 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -7,7 +7,7 @@ */ #include "config.h" -#include "alpha_sys.h" +#include "hw/alpha_sys.h" #include "qemu/log.h" #include "sysemu/sysemu.h" diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index 233a71ecdb..b4ebd2a9cc 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -3,11 +3,11 @@ #ifndef HW_ALPHA_H #define HW_ALPHA_H 1 -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "ide.h" -#include "pc.h" -#include "irq.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/ide.h" +#include "hw/pc.h" +#include "hw/irq.h" PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4], diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index bf9aabfc08..95571ffc5d 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -8,10 +8,10 @@ #include "cpu.h" #include "exec/exec-all.h" -#include "hw.h" -#include "devices.h" +#include "hw/hw.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" -#include "alpha_sys.h" +#include "hw/alpha_sys.h" #include "exec/address-spaces.h" diff --git a/hw/an5206.c b/hw/an5206.c index 924be81d57..7c21c66cde 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -6,10 +6,10 @@ * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" -#include "boards.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/mcf.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 7eb0c2bbcb..7992d6f6fd 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -26,12 +26,12 @@ Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is the secondary PCI bridge. */ -#include "sysbus.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "pci/pci_bridge.h" -#include "pci/pci_bus.h" -#include "apb_pci.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" +#include "hw/apb_pci.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/apic.c b/hw/apic.c index fd14b73023..8eddba06e5 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -17,14 +17,14 @@ * License along with this library; if not, see */ #include "qemu/thread.h" -#include "apic_internal.h" -#include "apic.h" -#include "ioapic.h" -#include "pci/msi.h" +#include "hw/apic_internal.h" +#include "hw/apic.h" +#include "hw/ioapic.h" +#include "hw/pci/msi.h" #include "qemu/host-utils.h" #include "trace.h" -#include "pc.h" -#include "apic-msidef.h" +#include "hw/pc.h" +#include "hw/apic-msidef.h" #define MAX_APIC_WORDS 8 diff --git a/hw/apic_common.c b/hw/apic_common.c index d8c9810509..d0c261602c 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -17,8 +17,8 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see */ -#include "apic.h" -#include "apic_internal.h" +#include "hw/apic.h" +#include "hw/apic_internal.h" #include "trace.h" #include "sysemu/kvm.h" diff --git a/hw/apic_internal.h b/hw/apic_internal.h index 9265e52cd6..578241f861 100644 --- a/hw/apic_internal.h +++ b/hw/apic_internal.h @@ -21,7 +21,7 @@ #define QEMU_APIC_INTERNAL_H #include "exec/memory.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" /* APIC Local Vector Table */ diff --git a/hw/apm.c b/hw/apm.c index 2e1b1372d2..e2846f99c8 100644 --- a/hw/apm.c +++ b/hw/apm.c @@ -20,9 +20,9 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "apm.h" -#include "hw.h" -#include "pci/pci.h" +#include "hw/apm.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" //#define DEBUG diff --git a/hw/apm.h b/hw/apm.h index 9abb47f99f..3edea5f623 100644 --- a/hw/apm.h +++ b/hw/apm.h @@ -3,7 +3,7 @@ #include #include "qemu-common.h" -#include "hw.h" +#include "hw/hw.h" #include "exec/memory.h" typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg); diff --git a/hw/applesmc.c b/hw/applesmc.c index 5a8c4ff2d2..44b9bacd88 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -30,8 +30,8 @@ * */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #include "ui/console.h" #include "qemu/timer.h" diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index ca49948ffc..90dceade71 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" /* MPCore private memory region. */ diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 4065424d60..43253fd34a 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -8,11 +8,11 @@ */ #include "config.h" -#include "hw.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/device_tree.h" #include "qemu/config-file.h" diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 90e43d0728..6b30e0bf42 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -18,8 +18,8 @@ * armv7m_nvic device. */ -#include "sysbus.h" -#include "arm_gic_internal.h" +#include "hw/sysbus.h" +#include "hw/arm_gic_internal.h" //#define DEBUG_GIC diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 40e8dd7045..745b4b2a0a 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -18,7 +18,7 @@ * with this program; if not, see . */ -#include "arm_gic_internal.h" +#include "hw/arm_gic_internal.h" static void gic_save(QEMUFile *f, void *opaque) { diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h index 699352ca8b..b10ac5e9f6 100644 --- a/hw/arm_gic_internal.h +++ b/hw/arm_gic_internal.h @@ -21,7 +21,7 @@ #ifndef QEMU_ARM_GIC_INTERNAL_H #define QEMU_ARM_GIC_INTERNAL_H -#include "sysbus.h" +#include "hw/sysbus.h" /* Maximum number of possible interrupts, determined by the GIC architecture */ #define GIC_MAXIRQ 1020 diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c index ae1e51d009..eb4427d9c4 100644 --- a/hw/arm_l2x0.c +++ b/hw/arm_l2x0.c @@ -18,7 +18,7 @@ * */ -#include "sysbus.h" +#include "hw/sysbus.h" /* L2C-310 r3p2 */ #define CACHE_ID 0x410000c8 diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 7b08aa3644..f59a9f11f0 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -19,7 +19,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" /* This device implements the per-cpu private timer and watchdog block diff --git a/hw/arm_pic.c b/hw/arm_pic.c index ffb4d4171a..a7ad893cc2 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -7,8 +7,8 @@ * This code is licensed under the LGPL */ -#include "hw.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" /* Input 0 is IRQ and input 1 is FIQ. */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 7ecb7da54b..a46f8d450e 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -7,10 +7,10 @@ * This code is licensed under the GPL. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "sysbus.h" -#include "primecell.h" +#include "hw/sysbus.h" +#include "hw/primecell.h" #include "sysemu/sysemu.h" #define LOCK_VALUE 0xa05f diff --git a/hw/arm_timer.c b/hw/arm_timer.c index c1e56be74e..644987046a 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -7,11 +7,11 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "qdev.h" -#include "ptimer.h" +#include "hw/qdev.h" +#include "hw/ptimer.h" /* Common timer implementation. */ diff --git a/hw/armv7m.c b/hw/armv7m.c index 904696ca7f..1d5bb592c4 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -7,9 +7,9 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "loader.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/loader.h" #include "elf.h" /* Bitbanded IO. Each word corresponds to a single bit. */ diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index d5798d0309..4d3042348b 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -10,11 +10,11 @@ * NVIC. Much of that is also implemented here. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "arm-misc.h" +#include "hw/arm-misc.h" #include "exec/address-spaces.h" -#include "arm_gic_internal.h" +#include "hw/arm_gic_internal.h" typedef struct { GICState gic; diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index dd37fa13e2..eccd423abf 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -22,14 +22,14 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "flash.h" -#include "boards.h" -#include "etraxfs.h" -#include "loader.h" +#include "hw/flash.h" +#include "hw/boards.h" +#include "hw/etraxfs.h" +#include "hw/loader.h" #include "elf.h" -#include "cris-boot.h" +#include "hw/cris-boot.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c index 114508fade..b8e6d3a103 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -9,9 +9,9 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "bitbang_i2c.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/bitbang_i2c.h" +#include "hw/sysbus.h" //#define DEBUG_BITBANG_I2C diff --git a/hw/bitbang_i2c.h b/hw/bitbang_i2c.h index 519d2dc22f..e86062742c 100644 --- a/hw/bitbang_i2c.h +++ b/hw/bitbang_i2c.h @@ -1,7 +1,7 @@ #ifndef BITBANG_I2C_H #define BITBANG_I2C_H -#include "i2c.h" +#include "hw/i2c.h" typedef struct bitbang_i2c_interface bitbang_i2c_interface; diff --git a/hw/blizzard.c b/hw/blizzard.c index 24bde32e5a..805f4d5558 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -20,8 +20,8 @@ #include "qemu-common.h" #include "ui/console.h" -#include "devices.h" -#include "vga_int.h" +#include "hw/devices.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int); @@ -941,15 +941,15 @@ static void blizzard_screen_dump(void *opaque, const char *filename, } #define DEPTH 8 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 15 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 16 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 24 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 32 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" void *s1d13745_init(qemu_irq gpio_int) { diff --git a/hw/boards.h b/hw/boards.h index 3813d4e551..425bdc74a8 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -4,7 +4,7 @@ #define HW_BOARDS_H #include "sysemu/blockdev.h" -#include "qdev.h" +#include "hw/qdev.h" #define DEFAULT_MACHINE_OPTIONS \ .boot_order = "cad" diff --git a/hw/bonito.c b/hw/bonito.c index 0498c9be79..3456e7840e 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -39,11 +39,11 @@ #include -#include "hw.h" -#include "pci/pci.h" -#include "pc.h" -#include "mips.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pc.h" +#include "hw/mips.h" +#include "hw/pci/pci_host.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c index 2070bb940c..e4ada3c731 100644 --- a/hw/bt-hci-csr.c +++ b/hw/bt-hci-csr.c @@ -21,9 +21,9 @@ #include "qemu-common.h" #include "char/char.h" #include "qemu/timer.h" -#include "irq.h" +#include "hw/irq.h" #include "bt/bt.h" -#include "bt.h" +#include "hw/bt.h" struct csrhci_s { int enable; diff --git a/hw/bt-hci.c b/hw/bt-hci.c index 69d2c73862..a76edea2c9 100644 --- a/hw/bt-hci.c +++ b/hw/bt-hci.c @@ -20,9 +20,9 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "usb.h" +#include "hw/usb.h" #include "bt/bt.h" -#include "bt.h" +#include "hw/bt.h" struct bt_hci_s { uint8_t *(*evt_packet)(void *opaque); diff --git a/hw/bt-hid.c b/hw/bt-hid.c index cfa7c145b8..69ccf9b432 100644 --- a/hw/bt-hid.c +++ b/hw/bt-hid.c @@ -21,8 +21,8 @@ #include "qemu-common.h" #include "qemu/timer.h" #include "ui/console.h" -#include "hid.h" -#include "bt.h" +#include "hw/hid.h" +#include "hw/bt.h" enum hid_transaction_req { BT_HANDSHAKE = 0x0, diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c index ba061c0da3..521587a112 100644 --- a/hw/bt-l2cap.c +++ b/hw/bt-l2cap.c @@ -19,7 +19,7 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "bt.h" +#include "hw/bt.h" #define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */ diff --git a/hw/bt-sdp.c b/hw/bt-sdp.c index c0431d1a40..218e075df7 100644 --- a/hw/bt-sdp.c +++ b/hw/bt-sdp.c @@ -18,7 +18,7 @@ */ #include "qemu-common.h" -#include "bt.h" +#include "hw/bt.h" struct bt_l2cap_sdp_state_s { struct bt_l2cap_conn_params_s *channel; diff --git a/hw/bt.c b/hw/bt.c index 4f2372d794..24ef4de49d 100644 --- a/hw/bt.c +++ b/hw/bt.c @@ -19,7 +19,7 @@ #include "qemu-common.h" #include "bt/bt.h" -#include "bt.h" +#include "hw/bt.h" /* Slave implementations can ignore this */ static void bt_dummy_lmp_mode_change(struct bt_link_s *link) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index de7d15ab76..e177057e49 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -24,7 +24,7 @@ #include /* For crc32 */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" #include "net/checksum.h" diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index 67028a3f75..ba584f4719 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -16,7 +16,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #ifdef CADENCE_TTC_ERR_DEBUG diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c index 5766d38f13..5426f10018 100644 --- a/hw/cadence_uart.c +++ b/hw/cadence_uart.c @@ -16,7 +16,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "qemu/timer.h" diff --git a/hw/cbus.c b/hw/cbus.c index 6fd3905448..29b467b61f 100644 --- a/hw/cbus.c +++ b/hw/cbus.c @@ -21,8 +21,8 @@ */ #include "qemu-common.h" -#include "irq.h" -#include "devices.h" +#include "hw/irq.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" //#define DEBUG diff --git a/hw/ccid.h b/hw/ccid.h index 6adc745a6d..9334da8acd 100644 --- a/hw/ccid.h +++ b/hw/ccid.h @@ -10,7 +10,7 @@ #ifndef CCID_H #define CCID_H -#include "qdev.h" +#include "hw/qdev.h" typedef struct CCIDCardState CCIDCardState; typedef struct CCIDCardInfo CCIDCardInfo; diff --git a/hw/cdrom.c b/hw/cdrom.c index 3b99535dce..a018eec40a 100644 --- a/hw/cdrom.c +++ b/hw/cdrom.c @@ -26,7 +26,7 @@ here. */ #include "qemu-common.h" -#include "scsi.h" +#include "hw/scsi.h" static void lba_to_msf(uint8_t *buf, int lba) { diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 2a2c8dad62..7babcb67c8 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -26,11 +26,11 @@ * Reference: Finn Thogersons' VGADOC4b * available at http://home.worldonline.dk/~finth/ */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "ui/console.h" -#include "vga_int.h" -#include "loader.h" +#include "hw/vga_int.h" +#include "hw/loader.h" /* * TODO: @@ -288,63 +288,63 @@ static void cirrus_bitblt_fill_nop(CirrusVGAState *s, #define ROP_NAME 0 #define ROP_FN(d, s) 0 -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_and_dst #define ROP_FN(d, s) (s) & (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_and_notdst #define ROP_FN(d, s) (s) & (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notdst #define ROP_FN(d, s) ~(d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src #define ROP_FN(d, s) s -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME 1 #define ROP_FN(d, s) ~0 -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_and_dst #define ROP_FN(d, s) (~(s)) & (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_xor_dst #define ROP_FN(d, s) (s) ^ (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_or_dst #define ROP_FN(d, s) (s) | (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_or_notdst #define ROP_FN(d, s) (~(s)) | (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_notxor_dst #define ROP_FN(d, s) ~((s) ^ (d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_or_notdst #define ROP_FN(d, s) (s) | (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc #define ROP_FN(d, s) (~(s)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_or_dst #define ROP_FN(d, s) (~(s)) | (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_and_notdst #define ROP_FN(d, s) (~(s)) & (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = { cirrus_bitblt_rop_fwd_0, @@ -2165,13 +2165,13 @@ static void cirrus_cursor_invalidate(VGACommonState *s1) } #define DEPTH 8 -#include "cirrus_vga_template.h" +#include "hw/cirrus_vga_template.h" #define DEPTH 16 -#include "cirrus_vga_template.h" +#include "hw/cirrus_vga_template.h" #define DEPTH 32 -#include "cirrus_vga_template.h" +#include "hw/cirrus_vga_template.h" static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) { diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h index 9c7bb09286..894610cc22 100644 --- a/hw/cirrus_vga_rop.h +++ b/hw/cirrus_vga_rop.h @@ -191,16 +191,16 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, } #define DEPTH 8 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #define DEPTH 16 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #define DEPTH 24 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #define DEPTH 32 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #undef ROP_NAME #undef ROP_OP diff --git a/hw/collie.c b/hw/collie.c index d19db590fe..17fddc8d5b 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -8,13 +8,13 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "sysbus.h" -#include "boards.h" -#include "devices.h" -#include "strongarm.h" -#include "arm-misc.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/devices.h" +#include "hw/strongarm.h" +#include "hw/arm-misc.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/cris-boot.c b/hw/cris-boot.c index b21326fade..c330e22a86 100644 --- a/hw/cris-boot.c +++ b/hw/cris-boot.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/loader.h" #include "elf.h" -#include "cris-boot.h" +#include "hw/cris-boot.h" static void main_cpu_reset(void *opaque) { diff --git a/hw/cris_pic_cpu.c b/hw/cris_pic_cpu.c index 3da0e86536..7f50471e53 100644 --- a/hw/cris_pic_cpu.c +++ b/hw/cris_pic_cpu.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" -#include "etraxfs.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/etraxfs.h" #define D(x) diff --git a/hw/cs4231.c b/hw/cs4231.c index ae384b90fd..2975336057 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/cs4231a.c b/hw/cs4231a.c index 73f08594bf..f005f25899 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" -#include "qdev.h" +#include "hw/isa.h" +#include "hw/qdev.h" #include "qemu/timer.h" /* diff --git a/hw/cuda.c b/hw/cuda.c index b36c53527a..2ae430d326 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -22,9 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" -#include "adb.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/adb.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" diff --git a/hw/dataplane/event-poll.c b/hw/dataplane/event-poll.c index 2b55c6e255..b98acf9aec 100644 --- a/hw/dataplane/event-poll.c +++ b/hw/dataplane/event-poll.c @@ -13,7 +13,7 @@ */ #include -#include "hw/dataplane/event-poll.h" +#include "event-poll.h" /* Add an event notifier and its callback for polling */ void event_poll_add(EventPoll *poll, EventHandler *handler, diff --git a/hw/dataplane/ioq.c b/hw/dataplane/ioq.c index 0c9f5c4d60..f709f87ed6 100644 --- a/hw/dataplane/ioq.c +++ b/hw/dataplane/ioq.c @@ -12,7 +12,7 @@ * */ -#include "hw/dataplane/ioq.h" +#include "ioq.h" void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs) { diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 8588f93114..8319c94b76 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -22,7 +22,7 @@ #include "migration/migration.h" #include "block/block.h" #include "hw/virtio-blk.h" -#include "hw/dataplane/virtio-blk.h" +#include "virtio-blk.h" enum { SEG_MAX = 126, /* maximum number of I/O segments */ diff --git a/hw/dataplane/vring.c b/hw/dataplane/vring.c index eff5ad8831..e3b225315f 100644 --- a/hw/dataplane/vring.c +++ b/hw/dataplane/vring.c @@ -15,7 +15,7 @@ */ #include "trace.h" -#include "hw/dataplane/vring.h" +#include "vring.h" #include "qemu/error-report.h" /* Map the guest's vring to host memory */ diff --git a/hw/dataplane/vring.h b/hw/dataplane/vring.h index 3274f623f5..defb1efcda 100644 --- a/hw/dataplane/vring.h +++ b/hw/dataplane/vring.h @@ -19,7 +19,7 @@ #include #include "qemu-common.h" -#include "hw/dataplane/hostmem.h" +#include "hostmem.h" #include "hw/virtio.h" typedef struct { diff --git a/hw/debugcon.c b/hw/debugcon.c index 81b2bb00fd..cab7691b12 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -24,10 +24,10 @@ * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" -#include "isa.h" -#include "pc.h" +#include "hw/isa.h" +#include "hw/pc.h" #define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" #define ISA_DEBUGCON_DEVICE(obj) \ diff --git a/hw/debugexit.c b/hw/debugexit.c index c1b489ddcb..ba67a8fb41 100644 --- a/hw/debugexit.c +++ b/hw/debugexit.c @@ -7,8 +7,8 @@ * (at your option) any later version. */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit" #define ISA_DEBUG_EXIT_DEVICE(obj) \ diff --git a/hw/dec_pci.c b/hw/dec_pci.c index ee3f4ca834..64a50924f6 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -23,12 +23,12 @@ * THE SOFTWARE. */ -#include "dec_pci.h" -#include "sysbus.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "pci/pci_bridge.h" -#include "pci/pci_bus.h" +#include "hw/dec_pci.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" /* debug DEC */ //#define DEBUG_DEC diff --git a/hw/dma.c b/hw/dma.c index 5bdf4358e3..fd1161ca31 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #include "qemu/main-loop.h" /* #define DEBUG_DMA */ diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 808157b38b..8b5ca6a4ec 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -17,10 +17,10 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "net/net.h" -#include "mips.h" +#include "hw/mips.h" //#define DEBUG_SONIC diff --git a/hw/ds1225y.c b/hw/ds1225y.c index a6219a7908..488f1d7241 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" typedef struct { diff --git a/hw/ds1338.c b/hw/ds1338.c index 1da0f96fdc..ae7ca9f82d 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -10,7 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "i2c.h" +#include "hw/i2c.h" /* Size of NVRAM including both the user-accessible area and the * secondary register area. diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 3a88805d0f..544d56b59d 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -6,9 +6,9 @@ * This code is licensed under the GPL */ -#include "hw.h" -#include "boards.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" diff --git a/hw/e1000.c b/hw/e1000.c index d6fe815eda..ed37061563 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -25,15 +25,15 @@ */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "net/net.h" #include "net/checksum.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" -#include "e1000_hw.h" +#include "hw/e1000_hw.h" #define E1000_DEBUG diff --git a/hw/ecc.c b/hw/ecc.c index 60d1f1d4f2..8c97c33deb 100644 --- a/hw/ecc.c +++ b/hw/ecc.c @@ -11,8 +11,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/flash.h" /* * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux. diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index dbac2c2bbc..6f4a407cbf 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" /* There are 3 versions of this chip used in SMP sun4m systems: diff --git a/hw/eepro100.c b/hw/eepro100.c index 5d237968e7..68d729c17a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -41,10 +41,10 @@ */ #include /* offsetof */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "eeprom93xx.h" +#include "hw/eeprom93xx.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c index 4c7158d1a5..39f560553d 100644 --- a/hw/eeprom93xx.c +++ b/hw/eeprom93xx.c @@ -35,8 +35,8 @@ * - No emulation of EEPROM timings. */ -#include "hw.h" -#include "eeprom93xx.h" +#include "hw/hw.h" +#include "hw/eeprom93xx.h" /* Debug EEPROM emulation. */ //~ #define DEBUG_EEPROM diff --git a/hw/empty_slot.c b/hw/empty_slot.c index d7b54973a4..5234a4ddc6 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -9,9 +9,9 @@ * version. */ -#include "hw.h" -#include "sysbus.h" -#include "empty_slot.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/empty_slot.h" //#define DEBUG_EMPTY_SLOT diff --git a/hw/es1370.c b/hw/es1370.c index 977d2e3767..e64cf23099 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -26,10 +26,10 @@ /* #define VERBOSE_ES1370 */ #define SILENT_ES1370 -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" /* Missing stuff: diff --git a/hw/escc.c b/hw/escc.c index 18c02921e3..baf0219304 100644 --- a/hw/escc.c +++ b/hw/escc.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "sysbus.h" -#include "escc.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/escc.h" #include "char/char.h" #include "ui/console.h" #include "trace.h" diff --git a/hw/esp-pci.c b/hw/esp-pci.c index c949e6e0d9..7599b39d8d 100644 --- a/hw/esp-pci.c +++ b/hw/esp-pci.c @@ -23,9 +23,9 @@ * THE SOFTWARE. */ -#include "pci/pci.h" -#include "eeprom93xx.h" -#include "esp.h" +#include "hw/pci/pci.h" +#include "hw/eeprom93xx.h" +#include "hw/esp.h" #include "trace.h" #include "qemu/log.h" diff --git a/hw/esp.c b/hw/esp.c index 2af48aac4b..5365eacec0 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -23,8 +23,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "esp.h" +#include "hw/sysbus.h" +#include "hw/esp.h" #include "trace.h" #include "qemu/log.h" diff --git a/hw/esp.h b/hw/esp.h index f15cc7b5bd..830673be8f 100644 --- a/hw/esp.h +++ b/hw/esp.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_ESP_H #define QEMU_HW_ESP_H -#include "scsi.h" +#include "hw/scsi.h" /* esp.c */ #define ESP_MAX_DEVS 7 diff --git a/hw/etraxfs.h b/hw/etraxfs.h index 180de5a088..0df4fdd2e9 100644 --- a/hw/etraxfs.h +++ b/hw/etraxfs.h @@ -26,7 +26,7 @@ #define HW_EXTRAXFS_H 1 #include "net/net.h" -#include "etraxfs_dma.h" +#include "hw/etraxfs_dma.h" qemu_irq *cris_pic_init_cpu(CPUCRISState *env); diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c index d41500316f..a84ec1f23c 100644 --- a/hw/etraxfs_dma.c +++ b/hw/etraxfs_dma.c @@ -23,12 +23,12 @@ */ #include #include -#include "hw.h" +#include "hw/hw.h" #include "exec/address-spaces.h" #include "qemu-common.h" #include "sysemu/sysemu.h" -#include "etraxfs_dma.h" +#include "hw/etraxfs_dma.h" #define D(x) diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index ad36411193..591bee245c 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -23,9 +23,9 @@ */ #include -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "etraxfs.h" +#include "hw/etraxfs.h" #define D(x) diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index 64af31c46e..635103c001 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" //#include "pc.h" //#include "etraxfs.h" diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 72c8868639..7e24d34230 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "qemu/log.h" diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index d3dac52315..3cd9476bb1 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #define D(x) diff --git a/hw/exynos4210.c b/hw/exynos4210.c index fa54e42a47..4592514bb2 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -21,13 +21,13 @@ * */ -#include "boards.h" +#include "hw/boards.h" #include "sysemu/sysemu.h" -#include "sysbus.h" -#include "arm-misc.h" -#include "loader.h" -#include "exynos4210.h" -#include "usb/hcd-ehci.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/loader.h" +#include "hw/exynos4210.h" +#include "hw/usb/hcd-ehci.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index ba644b43c2..5818f10132 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -27,9 +27,9 @@ * IRQs are passed to GIC through Combiner. */ -#include "sysbus.h" +#include "hw/sysbus.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" //#define DEBUG_COMBINER diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c index 3d498b77f8..6b31ae33b6 100644 --- a/hw/exynos4210_fimd.c +++ b/hw/exynos4210_fimd.c @@ -24,7 +24,7 @@ #include "qemu-common.h" #include "exec/cpu-all.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "ui/console.h" #include "ui/pixel_ops.h" #include "qemu/bswap.h" diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 94b138fa46..807849c574 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -20,10 +20,10 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu-common.h" -#include "irq.h" -#include "exynos4210.h" +#include "hw/irq.h" +#include "hw/exynos4210.h" enum ExtGicId { EXT_GIC_ID_MDMA_LCD0 = 66, diff --git a/hw/exynos4210_i2c.c b/hw/exynos4210_i2c.c index cefd736092..9e428759a1 100644 --- a/hw/exynos4210_i2c.c +++ b/hw/exynos4210_i2c.c @@ -21,8 +21,8 @@ */ #include "qemu/timer.h" -#include "sysbus.h" -#include "i2c.h" +#include "hw/sysbus.h" +#include "hw/i2c.h" #ifndef EXYNOS4_I2C_DEBUG #define EXYNOS4_I2C_DEBUG 0 diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c index d7d5904cc0..862c96212b 100644 --- a/hw/exynos4210_mct.c +++ b/hw/exynos4210_mct.c @@ -52,12 +52,12 @@ * there is no way to avoid frequently events). */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "ptimer.h" +#include "hw/ptimer.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" //#define DEBUG_MCT diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c index 7c81a1b628..ba5aa8d0e4 100644 --- a/hw/exynos4210_pmu.c +++ b/hw/exynos4210_pmu.c @@ -24,7 +24,7 @@ * uses PMU INFORM5 register as a holding pen. */ -#include "sysbus.h" +#include "hw/sysbus.h" #ifndef DEBUG_PMU #define DEBUG_PMU 0 diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c index c8656248a8..6d74cd4db5 100644 --- a/hw/exynos4210_pwm.c +++ b/hw/exynos4210_pwm.c @@ -20,12 +20,12 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "ptimer.h" +#include "hw/ptimer.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" //#define DEBUG_PWM diff --git a/hw/exynos4210_rtc.c b/hw/exynos4210_rtc.c index 5694a6207b..d170ca755a 100644 --- a/hw/exynos4210_rtc.c +++ b/hw/exynos4210_rtc.c @@ -25,16 +25,16 @@ * CLKOUTEN Bit[9] not used */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "ptimer.h" +#include "hw/ptimer.h" -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" #define DEBUG_RTC 0 diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index bdf797a029..006f3d44fb 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -19,11 +19,11 @@ * */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "char/char.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" #undef DEBUG_UART #undef DEBUG_UART_EXTEND diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index b59e6aabf3..473da349bd 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -22,12 +22,12 @@ */ #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "arm-misc.h" +#include "hw/arm-misc.h" #include "exec/address-spaces.h" -#include "exynos4210.h" -#include "boards.h" +#include "hw/exynos4210.h" +#include "hw/boards.h" #undef DEBUG diff --git a/hw/fdc.c b/hw/fdc.c index 976a587c42..a4bb1290ef 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -27,13 +27,13 @@ * way. There are changes in DOR register and DMA is not available. */ -#include "hw.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/fdc.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "isa.h" -#include "sysbus.h" -#include "qdev-addr.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/qdev-addr.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" #include "qemu/log.h" diff --git a/hw/fmopl.c b/hw/fmopl.c index f0a023477d..e50ba6c0ec 100644 --- a/hw/fmopl.c +++ b/hw/fmopl.c @@ -39,7 +39,7 @@ #include #include //#include "driver.h" /* use M.A.M.E. */ -#include "fmopl.h" +#include "hw/fmopl.h" #ifndef PI #define PI 3.14159265358979323846 diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 2a870961bc..d341aa0c6b 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -17,9 +17,9 @@ - Remove all DisplayState knowledge from devices. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" /* Render an image from a shared memory framebuffer. */ diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 02618f2480..63a199876c 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "isa.h" -#include "fw_cfg.h" -#include "sysbus.h" +#include "hw/isa.h" +#include "hw/fw_cfg.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" #include "qemu/config-file.h" diff --git a/hw/g364fb.c b/hw/g364fb.c index 0c0c8ba302..7b69815bc9 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -17,11 +17,11 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" #include "ui/pixel_ops.h" #include "trace.h" -#include "sysbus.h" +#include "hw/sysbus.h" typedef struct G364State { /* hardware */ diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 95639d5735..11e47d560e 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -23,9 +23,9 @@ * THE SOFTWARE. */ -#include "pci/pci_host.h" -#include "ppc/mac.h" -#include "pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" /* debug Grackle */ //#define DEBUG_GRACKLE diff --git a/hw/grlib.h b/hw/grlib.h index afd53892b0..470ce72250 100644 --- a/hw/grlib.h +++ b/hw/grlib.h @@ -25,8 +25,8 @@ #ifndef _GRLIB_H_ #define _GRLIB_H_ -#include "qdev.h" -#include "sysbus.h" +#include "hw/qdev.h" +#include "hw/sysbus.h" /* Emulation of GrLib device is base on the GRLIB IP Core User's Manual: * http://www.gaisler.com/products/grlib/grip.pdf diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index ba1685afd1..62f799083c 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "trace.h" diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 7962b74f2c..7043a34684 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "trace.h" diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index ef8dd95ac9..7ee469d191 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -24,10 +24,10 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "cpu.h" -#include "grlib.h" +#include "hw/grlib.h" #include "trace.h" diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 977a2c5e69..c73a58a045 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/pc.h" #include "exec/address-spaces.h" //#define DEBUG diff --git a/hw/gumstix.c b/hw/gumstix.c index bea16058f7..8859b7392f 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -34,12 +34,12 @@ * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289 */ -#include "hw.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/pxa.h" #include "net/net.h" -#include "flash.h" -#include "devices.h" -#include "boards.h" +#include "hw/flash.h" +#include "hw/devices.h" +#include "hw/boards.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/gus.c b/hw/gus.c index aa13fccf0d..d2682249ca 100644 --- a/hw/gus.c +++ b/hw/gus.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" -#include "gusemu.h" -#include "gustate.h" +#include "hw/isa.h" +#include "hw/gusemu.h" +#include "hw/gustate.h" #define dolog(...) AUD_log ("audio", __VA_ARGS__) #ifdef DEBUG diff --git a/hw/gusemu_hal.c b/hw/gusemu_hal.c index 6096690735..0eee617652 100644 --- a/hw/gusemu_hal.c +++ b/hw/gusemu_hal.c @@ -26,8 +26,8 @@ * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)? */ -#include "gustate.h" -#include "gusemu.h" +#include "hw/gustate.h" +#include "hw/gusemu.h" #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(GUSword *) (gusptr+(position))) diff --git a/hw/gusemu_mixer.c b/hw/gusemu_mixer.c index 6d8d9ced11..816c58a7ed 100644 --- a/hw/gusemu_mixer.c +++ b/hw/gusemu_mixer.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "gusemu.h" -#include "gustate.h" +#include "hw/gusemu.h" +#include "hw/gustate.h" #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(GUSword *) (gusptr+(position))) diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 3190bd1cf8..6bdd8209fb 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -17,10 +17,10 @@ * along with this program; if not, see . */ -#include "hw.h" -#include "pci/pci.h" -#include "intel-hda.h" -#include "intel-hda-defs.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/intel-hda.h" +#include "hw/intel-hda-defs.h" #include "audio/audio.h" /* -------------------------------------------------------------------------- */ diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index c0a71c3d5f..beb9661182 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -22,8 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" /* debug PIC */ //#define DEBUG_PIC diff --git a/hw/hid.c b/hw/hid.c index 89b5415c0f..28b34747ff 100644 --- a/hw/hid.c +++ b/hw/hid.c @@ -22,10 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" #include "qemu/timer.h" -#include "hid.h" +#include "hw/hid.h" #define HID_USAGE_ERROR_ROLLOVER 0x01 #define HID_USAGE_POSTFAIL 0x02 diff --git a/hw/highbank.c b/hw/highbank.c index defcc092b4..a622224dcc 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -17,14 +17,14 @@ * */ -#include "sysbus.h" -#include "arm-misc.h" -#include "devices.h" -#include "loader.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/loader.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "sysbus.h" +#include "hw/boards.h" +#include "hw/sysbus.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/hpet.c b/hw/hpet.c index 97eaa2f700..6bfbf3a68c 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -24,14 +24,14 @@ * This driver attempts to emulate an HPET device in software. */ -#include "hw.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/pc.h" #include "ui/console.h" #include "qemu/timer.h" -#include "hpet_emul.h" -#include "sysbus.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/hpet_emul.h" +#include "hw/sysbus.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" //#define HPET_DEBUG #ifdef HPET_DEBUG diff --git a/hw/hw.h b/hw/hw.h index dfced97bbc..1553e54aa7 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -9,7 +9,7 @@ #endif #include "exec/ioport.h" -#include "irq.h" +#include "hw/irq.h" #include "block/aio.h" #include "migration/qemu-file.h" #include "migration/vmstate.h" diff --git a/hw/i2c.c b/hw/i2c.c index ec314a40d1..ad361cc57f 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -7,7 +7,7 @@ * This code is licensed under the LGPL. */ -#include "i2c.h" +#include "hw/i2c.h" struct i2c_bus { diff --git a/hw/i2c.h b/hw/i2c.h index 0e80d5a9cb..461392f374 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -1,7 +1,7 @@ #ifndef QEMU_I2C_H #define QEMU_I2C_H -#include "qdev.h" +#include "hw/qdev.h" /* The QEMU I2C implementation only supports simple transfers that complete immediately. It does not support slave devices that need to be able to diff --git a/hw/i82374.c b/hw/i82374.c index 6a62ba2ab8..22115e4fcf 100644 --- a/hw/i82374.c +++ b/hw/i82374.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "isa.h" +#include "hw/isa.h" //#define DEBUG_I82374 diff --git a/hw/i82378.c b/hw/i82378.c index 0914d7bbfb..6f8c48b9ae 100644 --- a/hw/i82378.c +++ b/hw/i82378.c @@ -17,10 +17,10 @@ * License along with this library; if not, see . */ -#include "pci/pci.h" -#include "pc.h" -#include "i8254.h" -#include "pcspk.h" +#include "hw/pci/pci.h" +#include "hw/pc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" //#define DEBUG_I82378 diff --git a/hw/i8254.c b/hw/i8254.c index 394b2e81d7..67bfc6a806 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "qemu/timer.h" -#include "i8254.h" -#include "i8254_internal.h" +#include "hw/i8254.h" +#include "hw/i8254_internal.h" //#define DEBUG_PIT diff --git a/hw/i8254.h b/hw/i8254.h index ba6b598a99..7d4432e722 100644 --- a/hw/i8254.h +++ b/hw/i8254.h @@ -25,8 +25,8 @@ #ifndef HW_I8254_H #define HW_I8254_H -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #define PIT_FREQ 1193182 diff --git a/hw/i8254_common.c b/hw/i8254_common.c index 8c2e45a92e..c6c0c80c24 100644 --- a/hw/i8254_common.c +++ b/hw/i8254_common.c @@ -22,12 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "qemu/timer.h" -#include "i8254.h" -#include "i8254_internal.h" +#include "hw/i8254.h" +#include "hw/i8254_internal.h" /* val must be 0 or 1 */ void pit_set_gate(ISADevice *dev, int channel, int val) diff --git a/hw/i8254_internal.h b/hw/i8254_internal.h index 686f0c2ba9..30d5b1b950 100644 --- a/hw/i8254_internal.h +++ b/hw/i8254_internal.h @@ -25,9 +25,9 @@ #ifndef QEMU_I8254_INTERNAL_H #define QEMU_I8254_INTERNAL_H -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" typedef struct PITChannelState { int count; /* can be 65536 */ diff --git a/hw/i8259.c b/hw/i8259.c index 54fe14447b..1d8275232a 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "monitor/monitor.h" #include "qemu/timer.h" -#include "i8259_internal.h" +#include "hw/i8259_internal.h" /* debug PIC */ //#define DEBUG_PIC diff --git a/hw/i8259_common.c b/hw/i8259_common.c index fc91056afb..98052db1fa 100644 --- a/hw/i8259_common.c +++ b/hw/i8259_common.c @@ -22,8 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "pc.h" -#include "i8259_internal.h" +#include "hw/pc.h" +#include "hw/i8259_internal.h" void pic_reset_common(PICCommonState *s) { diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h index 8785b1da3f..2813ec1baa 100644 --- a/hw/i8259_internal.h +++ b/hw/i8259_internal.h @@ -25,9 +25,9 @@ #ifndef QEMU_I8259_INTERNAL_H #define QEMU_I8259_INTERNAL_H -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" typedef struct PICCommonState PICCommonState; diff --git a/hw/i82801b11.c b/hw/i82801b11.c index 3dc10000a4..992095c80f 100644 --- a/hw/i82801b11.c +++ b/hw/i82801b11.c @@ -41,8 +41,8 @@ * License along with this library; if not, see */ -#include "pci/pci.h" -#include "ich9.h" +#include "hw/pci/pci.h" +#include "hw/ich9.h" /*****************************************************************************/ diff --git a/hw/ich9.h b/hw/ich9.h index d4509bb606..59c25e9aa0 100644 --- a/hw/ich9.h +++ b/hw/ich9.h @@ -1,20 +1,20 @@ #ifndef HW_ICH9_H #define HW_ICH9_H -#include "hw.h" +#include "hw/hw.h" #include "qemu/range.h" -#include "isa.h" -#include "sysbus.h" -#include "pc.h" -#include "apm.h" -#include "ioapic.h" -#include "pci/pci.h" -#include "pci/pcie_host.h" -#include "pci/pci_bridge.h" -#include "acpi.h" -#include "acpi_ich9.h" -#include "pam.h" -#include "pci/pci_bus.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/ioapic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/acpi.h" +#include "hw/acpi_ich9.h" +#include "hw/pam.h" +#include "hw/pci/pci_bus.h" void ich9_lpc_set_irq(void *opaque, int irq_num, int level); int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); diff --git a/hw/ide.h b/hw/ide.h index 0eb3a74467..35444a39f9 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -1,8 +1,8 @@ #ifndef HW_IDE_H #define HW_IDE_H -#include "isa.h" -#include "pci/pci.h" +#include "hw/isa.h" +#include "hw/pci/pci.h" #include "exec/memory.h" #define MAX_IDE_DEVS 2 diff --git a/hw/imx_avic.c b/hw/imx_avic.c index f1f066cf9c..4e280b6ab9 100644 --- a/hw/imx_avic.c +++ b/hw/imx_avic.c @@ -14,8 +14,8 @@ * TODO: implement vectors. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "qemu/host-utils.h" #define DEBUG_INT 1 diff --git a/hw/imx_ccm.c b/hw/imx_ccm.c index 477903a546..ad7aad3397 100644 --- a/hw/imx_ccm.c +++ b/hw/imx_ccm.c @@ -10,10 +10,10 @@ * the CCM. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "imx.h" +#include "hw/imx.h" #define CKIH_FREQ 26000000 /* 26MHz crystal input */ #define CKIL_FREQ 32768 /* nominal 32khz clock */ diff --git a/hw/imx_serial.c b/hw/imx_serial.c index 2d8253e0ee..746723cd6e 100644 --- a/hw/imx_serial.c +++ b/hw/imx_serial.c @@ -17,11 +17,11 @@ * is a real serial device. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "char/char.h" -#include "imx.h" +#include "hw/imx.h" //#define DEBUG_SERIAL 1 #ifdef DEBUG_SERIAL diff --git a/hw/imx_timer.c b/hw/imx_timer.c index e924c747c5..a8c311141e 100644 --- a/hw/imx_timer.c +++ b/hw/imx_timer.c @@ -11,11 +11,11 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "ptimer.h" -#include "sysbus.h" -#include "imx.h" +#include "hw/ptimer.h" +#include "hw/sysbus.h" +#include "hw/imx.h" //#define DEBUG_TIMER 1 #ifdef DEBUG_TIMER diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 9e3630a43d..e0ba327a55 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -7,10 +7,10 @@ * This code is licensed under the GPL */ -#include "sysbus.h" -#include "devices.h" -#include "boards.h" -#include "arm-misc.h" +#include "hw/sysbus.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" #include "net/net.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 784c229d8f..728b60fb9a 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -17,13 +17,13 @@ * along with this program; if not, see . */ -#include "hw.h" -#include "pci/pci.h" -#include "pci/msi.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" #include "qemu/timer.h" -#include "audiodev.h" -#include "intel-hda.h" -#include "intel-hda-defs.h" +#include "hw/audiodev.h" +#include "hw/intel-hda.h" +#include "hw/intel-hda-defs.h" #include "sysemu/dma.h" /* --------------------------------------------------------------------- */ diff --git a/hw/intel-hda.h b/hw/intel-hda.h index 22e0968d50..2544f0a344 100644 --- a/hw/intel-hda.h +++ b/hw/intel-hda.h @@ -1,7 +1,7 @@ #ifndef HW_INTEL_HDA_H #define HW_INTEL_HDA_H -#include "qdev.h" +#include "hw/qdev.h" /* --------------------------------------------------------------------- */ /* hda bus */ diff --git a/hw/ioapic.c b/hw/ioapic.c index f06c2dcf2e..78629fac6c 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -20,11 +20,11 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "pc.h" -#include "apic.h" -#include "ioapic.h" -#include "ioapic_internal.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/apic.h" +#include "hw/ioapic.h" +#include "hw/ioapic_internal.h" //#define DEBUG_IOAPIC diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c index 7dc552f033..d4aff29544 100644 --- a/hw/ioapic_common.c +++ b/hw/ioapic_common.c @@ -19,9 +19,9 @@ * License along with this library; if not, see . */ -#include "ioapic.h" -#include "ioapic_internal.h" -#include "sysbus.h" +#include "hw/ioapic.h" +#include "hw/ioapic_internal.h" +#include "hw/sysbus.h" void ioapic_reset_common(DeviceState *dev) { diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h index c8447d7f3b..25576c819e 100644 --- a/hw/ioapic_internal.h +++ b/hw/ioapic_internal.h @@ -22,9 +22,9 @@ #ifndef QEMU_IOAPIC_INTERNAL_H #define QEMU_IOAPIC_INTERNAL_H -#include "hw.h" +#include "hw/hw.h" #include "exec/memory.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define MAX_IOAPICS 1 diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 95bceb5347..43f855427b 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -20,10 +20,10 @@ * with this program; if not, see . */ -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/pcie.h" -#include "ioh3420.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/ioh3420.h" #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ #define PCI_DEVICE_ID_IOH_REV 0x2 diff --git a/hw/ioh3420.h b/hw/ioh3420.h index 046cf2c281..7776e5b02d 100644 --- a/hw/ioh3420.h +++ b/hw/ioh3420.h @@ -1,7 +1,7 @@ #ifndef QEMU_IOH3420_H #define QEMU_IOH3420_H -#include "pci/pcie_port.h" +#include "hw/pci/pcie_port.h" PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/ipack.c b/hw/ipack.c index e15540d5cd..b1f46c10a4 100644 --- a/hw/ipack.c +++ b/hw/ipack.c @@ -8,7 +8,7 @@ * later version. */ -#include "ipack.h" +#include "hw/ipack.h" IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot) { diff --git a/hw/ipack.h b/hw/ipack.h index 69e26282d3..f2b7a12e05 100644 --- a/hw/ipack.h +++ b/hw/ipack.h @@ -11,7 +11,7 @@ #ifndef QEMU_IPACK_H #define QEMU_IPACK_H -#include "qdev.h" +#include "hw/qdev.h" typedef struct IPackBus IPackBus; diff --git a/hw/ipoctal232.c b/hw/ipoctal232.c index c1e3b197b5..1da6a99175 100644 --- a/hw/ipoctal232.c +++ b/hw/ipoctal232.c @@ -8,7 +8,7 @@ * later version. */ -#include "ipack.h" +#include "hw/ipack.h" #include "qemu/bitops.h" #include "char/char.h" diff --git a/hw/irq.c b/hw/irq.c index f4e2a7804a..20785428ef 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "irq.h" +#include "hw/irq.h" struct IRQState { qemu_irq_handler handler; diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 6dc34f09f3..67ff8fd314 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -16,11 +16,11 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "isa.h" +#include "hw/isa.h" #include "exec/address-spaces.h" static ISABus *isabus; diff --git a/hw/isa.h b/hw/isa.h index 7a8874abfd..82da37c11d 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -5,7 +5,7 @@ #include "exec/ioport.h" #include "exec/memory.h" -#include "qdev.h" +#include "hw/qdev.h" #define ISA_NUM_IRQS 16 diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c index 487cf6a8fb..a7860e7459 100644 --- a/hw/isa_mmio.c +++ b/hw/isa_mmio.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #include "exec/address-spaces.h" static void isa_mmio_writeb (void *opaque, hwaddr addr, diff --git a/hw/ivshmem.c b/hw/ivshmem.c index afaf9b3bbf..68a2cf2e69 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -16,10 +16,10 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "pci/msix.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/pci/msix.h" #include "sysemu/kvm.h" #include "migration/migration.h" #include "qapi/qmp/qerror.h" diff --git a/hw/jazz_led.c b/hw/jazz_led.c index 4822c485f2..a418a7d1b6 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -26,7 +26,7 @@ #include "ui/console.h" #include "ui/pixel_ops.h" #include "trace.h" -#include "sysbus.h" +#include "hw/sysbus.h" typedef enum { REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2, diff --git a/hw/kvmvapic.c b/hw/kvmvapic.c index 9265baf568..c151c95c3e 100644 --- a/hw/kvmvapic.c +++ b/hw/kvmvapic.c @@ -11,7 +11,7 @@ #include "sysemu/sysemu.h" #include "sysemu/cpus.h" #include "sysemu/kvm.h" -#include "apic_internal.h" +#include "hw/apic_internal.h" #define APIC_DEFAULT_ADDRESS 0xfee00000 diff --git a/hw/kzm.c b/hw/kzm.c index fb3316551d..ec50a319ac 100644 --- a/hw/kzm.c +++ b/hw/kzm.c @@ -13,16 +13,16 @@ * i.MX31 SoC */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" -#include "hw.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "serial.h" -#include "imx.h" +#include "hw/boards.h" +#include "hw/serial.h" +#include "hw/imx.h" /* Memory map for Kzm Emulation Baseboard: * 0x00000000-0x00003fff 16k secure ROM IGNORED diff --git a/hw/lan9118.c b/hw/lan9118.c index 0e844e535c..403fb868ae 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -10,11 +10,11 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "devices.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" -#include "ptimer.h" +#include "hw/ptimer.h" /* For crc32 */ #include diff --git a/hw/lance.c b/hw/lance.c index 4b92425299..acfffaed31 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -35,12 +35,12 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" #include "qemu/timer.h" #include "qemu/sockets.h" -#include "sun4m.h" -#include "pcnet.h" +#include "hw/sun4m.h" +#include "hw/pcnet.h" #include "trace.h" typedef struct { diff --git a/hw/leon3.c b/hw/leon3.c index f16a8bb4ec..f58061f8ed 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -21,18 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "char/char.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "trace.h" #include "exec/address-spaces.h" -#include "grlib.h" +#include "hw/grlib.h" /* Default system clock. */ #define CPU_CLK (40 * 1000 * 1000) diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index 2bc06d7b7b..1ce466a1b1 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -17,16 +17,16 @@ * License along with this library; if not, see . */ -#include "sysbus.h" -#include "hw.h" -#include "flash.h" -#include "devices.h" -#include "boards.h" -#include "loader.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "sysemu/blockdev.h" #include "elf.h" -#include "lm32_hwsetup.h" -#include "lm32.h" +#include "hw/lm32_hwsetup.h" +#include "hw/lm32.h" #include "exec/address-spaces.h" typedef struct { diff --git a/hw/lm32_hwsetup.h b/hw/lm32_hwsetup.h index 853e9abc7b..3449bd8dfc 100644 --- a/hw/lm32_hwsetup.h +++ b/hw/lm32_hwsetup.h @@ -26,7 +26,7 @@ #define QEMU_HW_LM32_HWSETUP_H #include "qemu-common.h" -#include "loader.h" +#include "hw/loader.h" typedef struct { void *data; diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c index 8c82c85f6d..472e9c25fd 100644 --- a/hw/lm32_juart.c +++ b/hw/lm32_juart.c @@ -17,12 +17,12 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "char/char.h" -#include "lm32_juart.h" +#include "hw/lm32_juart.h" enum { LM32_JUART_MIN_SAVE_VERSION = 0, diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c index 42f298ad51..d17c310d5c 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -19,12 +19,12 @@ #include -#include "hw.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/pc.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" -#include "lm32_pic.h" +#include "hw/lm32_pic.h" struct LM32PicState { SysBusDevice busdev; diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c index 187ef6d0d6..33a3b80ce7 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -28,8 +28,8 @@ * the test is passed or any non-zero value to it if the test is failed. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/log.h" #include "qemu/error-report.h" diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c index db527e9dc6..e06fac7082 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -21,11 +21,11 @@ * http://www.latticesemi.com/documents/mico32timer.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/error-report.h" #define DEFAULT_FREQUENCY (50*1000000) diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c index 9c89cca49b..02f6f89174 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -22,8 +22,8 @@ */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "char/char.h" #include "qemu/error-report.h" diff --git a/hw/lm4549.c b/hw/lm4549.c index b3c2d5f25d..67335cba61 100644 --- a/hw/lm4549.c +++ b/hw/lm4549.c @@ -13,9 +13,9 @@ * It supports only one playback voice and no record voice. */ -#include "hw.h" +#include "hw/hw.h" #include "audio/audio.h" -#include "lm4549.h" +#include "hw/lm4549.h" #if 0 #define LM4549_DEBUG 1 diff --git a/hw/lm832x.c b/hw/lm832x.c index 94b8ae06d8..a064dfd172 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -18,8 +18,8 @@ * with this program; if not, see . */ -#include "hw.h" -#include "i2c.h" +#include "hw/hw.h" +#include "hw/i2c.h" #include "qemu/timer.h" #include "ui/console.h" diff --git a/hw/loader.c b/hw/loader.c index 995edc3f98..d2a974beb9 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -42,13 +42,13 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "disas/disas.h" #include "monitor/monitor.h" #include "sysemu/sysemu.h" -#include "uboot_image.h" -#include "loader.h" -#include "fw_cfg.h" +#include "hw/uboot_image.h" +#include "hw/loader.h" +#include "hw/fw_cfg.h" #include "exec/memory.h" #include "exec/address-spaces.h" @@ -260,7 +260,7 @@ static void *load_at(int fd, int offset, int size) #define elf_word uint32_t #define elf_sword int32_t #define bswapSZs bswap32s -#include "elf_ops.h" +#include "hw/elf_ops.h" #undef elfhdr #undef elf_phdr @@ -280,7 +280,7 @@ static void *load_at(int fd, int offset, int size) #define elf_sword int64_t #define bswapSZs bswap64s #define SZ 64 -#include "elf_ops.h" +#include "hw/elf_ops.h" /* return < 0 if error, otherwise the number of bytes loaded in memory */ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index e25689bf87..e55d66a7a4 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -28,21 +28,21 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "hw.h" +#include "hw/hw.h" #include "qemu/range.h" -#include "isa.h" -#include "sysbus.h" -#include "pc.h" -#include "apm.h" -#include "ioapic.h" -#include "pci/pci.h" -#include "pci/pcie_host.h" -#include "pci/pci_bridge.h" -#include "ich9.h" -#include "acpi.h" -#include "acpi_ich9.h" -#include "pam.h" -#include "pci/pci_bus.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/ioapic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/ich9.h" +#include "hw/acpi.h" +#include "hw/acpi_ich9.h" +#include "hw/pam.h" +#include "hw/pci/pci_bus.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 860df328e5..5a8bf4d0e9 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -12,9 +12,9 @@ #include -#include "hw.h" -#include "pci/pci.h" -#include "scsi.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/scsi.h" #include "sysemu/dma.h" //#define DEBUG_LSI diff --git a/hw/m25p80.c b/hw/m25p80.c index 1372d06409..55e9d0d37a 100644 --- a/hw/m25p80.c +++ b/hw/m25p80.c @@ -21,10 +21,10 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/blockdev.h" -#include "ssi.h" -#include "devices.h" +#include "hw/ssi.h" +#include "hw/devices.h" #ifdef M25P80_ERR_DEBUG #define DB_PRINT(...) do { \ diff --git a/hw/m48t59.c b/hw/m48t59.c index 427d95b5a6..39a9d808cd 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "nvram.h" +#include "hw/hw.h" +#include "hw/nvram.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "sysbus.h" -#include "isa.h" +#include "hw/sysbus.h" +#include "hw/isa.h" #include "exec/address-spaces.h" //#define DEBUG_NVRAM diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index b894ab21aa..a1514708de 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -36,9 +36,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" -#include "mac_dbdma.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/mac_dbdma.h" #include "qemu/main-loop.h" /* debug DBDMA */ diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 25121fa482..ed32bde5ab 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -22,10 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "firmware_abi.h" +#include "hw/hw.h" +#include "hw/firmware_abi.h" #include "sysemu/sysemu.h" -#include "ppc/mac.h" +#include "hw/ppc/mac.h" /* debug NVR */ //#define DEBUG_NVR diff --git a/hw/macio.c b/hw/macio.c index 74bdcd1039..792fa390e6 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -22,11 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" -#include "pci/pci.h" -#include "mac_dbdma.h" -#include "escc.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" +#include "hw/mac_dbdma.h" +#include "hw/escc.h" #define TYPE_MACIO "macio" #define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO) diff --git a/hw/mainstone.c b/hw/mainstone.c index d1ff6e76d6..aea908f036 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -11,15 +11,15 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" #include "net/net.h" -#include "devices.h" -#include "boards.h" -#include "flash.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" /* Device addresses */ diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index c792caf271..e042046e4f 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -9,10 +9,10 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "hw.h" -#include "i2c.h" -#include "sysbus.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/sysbus.h" #include "audio/audio.h" #define MP_AUDIO_SIZE 0x00001000 diff --git a/hw/max111x.c b/hw/max111x.c index de1be4ddd6..d477ecdb29 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -10,7 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "ssi.h" +#include "hw/ssi.h" typedef struct { SSISlave ssidev; diff --git a/hw/max7310.c b/hw/max7310.c index c2df0b49eb..e5cb810a27 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -7,7 +7,7 @@ * This file is licensed under GNU GPL. */ -#include "i2c.h" +#include "hw/i2c.h" typedef struct { I2CSlave i2c; diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 2fb11f69a3..a2119ad2f1 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "mc146818rtc.h" +#include "hw/mc146818rtc.h" #include "qapi/visitor.h" #ifdef TARGET_I386 -#include "apic.h" +#include "hw/apic.h" #endif //#define DEBUG_CMOS diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h index f286b6a12a..967403edb5 100644 --- a/hw/mc146818rtc.h +++ b/hw/mc146818rtc.h @@ -1,8 +1,8 @@ #ifndef MC146818RTC_H #define MC146818RTC_H -#include "isa.h" -#include "mc146818rtc_regs.h" +#include "hw/isa.h" +#include "hw/mc146818rtc_regs.h" ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); diff --git a/hw/mcf5206.c b/hw/mcf5206.c index ea2db2325a..58cd8d46c9 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -5,10 +5,10 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 86402d30d5..748bf56983 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -5,14 +5,14 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "sysemu/sysemu.h" #include "net/net.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 8e60f09fbb..0227bd852c 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -5,9 +5,9 @@ * * This code is licensed under the GPL */ -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" -#include "mcf.h" +#include "hw/mcf.h" /* For crc32 */ #include #include "exec/address-spaces.h" diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index b213656300..fff27b34aa 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -5,8 +5,8 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "exec/address-spaces.h" typedef struct { diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index c44344317a..aacf0f05ed 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -5,8 +5,8 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "char/char.h" #include "exec/address-spaces.h" diff --git a/hw/megasas.c b/hw/megasas.c index eb191f5e12..9b815d4b8f 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -18,16 +18,16 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" -#include "pci/msix.h" +#include "hw/pci/msix.h" #include "qemu/iov.h" -#include "scsi.h" -#include "scsi-defs.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" #include "trace.h" -#include "mfi.h" +#include "hw/mfi.h" #define MEGASAS_VERSION "1.70" #define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */ diff --git a/hw/microblaze_boot.c b/hw/microblaze_boot.c index 3ec5c0f7dd..e13b3e13bb 100644 --- a/hw/microblaze_boot.c +++ b/hw/microblaze_boot.c @@ -28,10 +28,10 @@ #include "qemu/config-file.h" #include "qemu-common.h" #include "sysemu/device_tree.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" -#include "microblaze_boot.h" +#include "hw/microblaze_boot.h" static struct { diff --git a/hw/microblaze_boot.h b/hw/microblaze_boot.h index c1cf836b99..b14ef2b992 100644 --- a/hw/microblaze_boot.h +++ b/hw/microblaze_boot.h @@ -1,7 +1,7 @@ #ifndef __MICROBLAZE_BOOT__ #define __MICROBLAZE_BOOT__ -#include "hw.h" +#include "hw/hw.h" void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, uint32_t ramsize, const char *dtb_filename, diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze_pic_cpu.c index ff36a526fc..d4743ab390 100644 --- a/hw/microblaze_pic_cpu.c +++ b/hw/microblaze_pic_cpu.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "microblaze_pic_cpu.h" +#include "hw/hw.h" +#include "hw/microblaze_pic_cpu.h" #define D(x) diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c index d51d1ac993..e08e9dca16 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -21,8 +21,8 @@ * http://www.milkymist.org/socdoc/ac97.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "audio/audio.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c index ea4d210685..d922f6ffad 100644 --- a/hw/milkymist-hpdmc.c +++ b/hw/milkymist-hpdmc.c @@ -21,8 +21,8 @@ * http://www.milkymist.org/socdoc/hpdmc.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h index c8bd7e93dd..d49f96b5d4 100644 --- a/hw/milkymist-hw.h +++ b/hw/milkymist-hw.h @@ -1,8 +1,8 @@ #ifndef QEMU_HW_MILKYMIST_H #define QEMU_HW_MILKYMIST_H -#include "qdev.h" -#include "qdev-addr.h" +#include "hw/qdev.h" +#include "hw/qdev-addr.h" #include "net/net.h" static inline DeviceState *milkymist_uart_create(hwaddr base, diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c index 9d15309ab7..d5944bca69 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -21,13 +21,13 @@ * http://www.milkymist.org/socdoc/memcard.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "trace.h" #include "qemu/error-report.h" #include "sysemu/blockdev.h" -#include "sd.h" +#include "hw/sd.h" enum { ENABLE_CMD_TX = (1<<0), diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 9992dcceaf..c20ff904ec 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -22,12 +22,12 @@ * */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "net/net.h" #include "qemu/error-report.h" -#include "qdev-addr.h" +#include "hw/qdev-addr.h" #include diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index c347680ad7..ad44b4db22 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -22,8 +22,8 @@ * */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/log.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index 01660bebf0..d911686de7 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -21,11 +21,11 @@ * not available yet */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "ui/console.h" -#include "hid.h" +#include "hw/hid.h" #include "qemu/error-report.h" enum { diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index e69ac6f047..e083a280c4 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -21,12 +21,12 @@ * http://www.milkymist.org/socdoc/sysctl.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "trace.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/error-report.h" enum { diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c index 42de10aafd..b723a04cc9 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -24,8 +24,8 @@ * */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c index e73eb8476c..ac6f5373ad 100644 --- a/hw/milkymist-uart.c +++ b/hw/milkymist-uart.c @@ -21,8 +21,8 @@ * http://www.milkymist.org/socdoc/uart.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "char/char.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 4d0a5dfb78..85ebb851bd 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -22,24 +22,24 @@ * http://www.milkymist.org/socdoc/vgafb.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "ui/console.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" #include "ui/pixel_ops.h" #include "qemu/error-report.h" #define BITS 8 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 15 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 16 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 24 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 32 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" enum { R_CTRL = 0, diff --git a/hw/milkymist.c b/hw/milkymist.c index c04eb35fdd..fd36de57b5 100644 --- a/hw/milkymist.c +++ b/hw/milkymist.c @@ -17,17 +17,17 @@ * License along with this library; if not, see . */ -#include "sysbus.h" -#include "hw.h" -#include "flash.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" -#include "loader.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/blockdev.h" -#include "milkymist-hw.h" -#include "lm32.h" +#include "hw/milkymist-hw.h" +#include "hw/lm32.h" #include "exec/address-spaces.h" #define BIOS_FILENAME "mmone-bios.bin" diff --git a/hw/mips_addr.c b/hw/mips_addr.c index aa1c7d84d6..cddc25cf3f 100644 --- a/hw/mips_addr.c +++ b/hw/mips_addr.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips_cpudevs.h" +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr) { diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 8b532e1e0d..766aa9dfb5 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -18,29 +18,29 @@ * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf */ -#include "hw.h" -#include "pc.h" -#include "serial.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/fdc.h" #include "net/net.h" -#include "boards.h" -#include "smbus.h" +#include "hw/boards.h" +#include "hw/smbus.h" #include "block/block.h" -#include "flash.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pci/pci.h" +#include "hw/flash.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pci/pci.h" #include "char/char.h" #include "sysemu/sysemu.h" #include "audio/audio.h" #include "qemu/log.h" -#include "loader.h" -#include "mips-bios.h" -#include "ide.h" +#include "hw/loader.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" #include "elf.h" -#include "vt82c686.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/vt82c686.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/mips_int.c b/hw/mips_int.c index 6423fd0bd9..ddd3b1bb01 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips_cpudevs.h" +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" #include "cpu.h" static void cpu_mips_irq_request(void *opaque, int irq, int level) diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 17fbdde063..daeb985b1d 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -22,25 +22,25 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pc.h" -#include "serial.h" -#include "isa.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/isa.h" +#include "hw/fdc.h" #include "sysemu/sysemu.h" #include "sysemu/arch_init.h" -#include "boards.h" +#include "hw/boards.h" #include "net/net.h" -#include "esp.h" -#include "mips-bios.h" -#include "loader.h" -#include "mc146818rtc.h" -#include "i8254.h" -#include "pcspk.h" +#include "hw/esp.h" +#include "hw/mips-bios.h" +#include "hw/loader.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" enum jazz_model_e diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2a150dfb84..9a67dce207 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -22,32 +22,32 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "serial.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/fdc.h" #include "net/net.h" -#include "boards.h" -#include "smbus.h" +#include "hw/boards.h" +#include "hw/smbus.h" #include "block/block.h" -#include "flash.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pci/pci.h" +#include "hw/flash.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pci/pci.h" #include "char/char.h" #include "sysemu/sysemu.h" #include "sysemu/arch_init.h" -#include "boards.h" +#include "hw/boards.h" #include "qemu/log.h" -#include "mips-bios.h" -#include "ide.h" -#include "loader.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "sysbus.h" /* SysBusDevice */ +#include "hw/sysbus.h" /* SysBusDevice */ //#define DEBUG_BOARD_INIT diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index b0ab8f69e2..4935c78c01 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -24,18 +24,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "serial.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/serial.h" +#include "hw/isa.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "mips-bios.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/mips-bios.h" +#include "hw/loader.h" #include "elf.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" static struct _loaderparams { diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5df7eb4469..539a562620 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -7,23 +7,23 @@ * All peripherial devices are attached to this "bus" with * the standard PC ISA addresses. */ -#include "hw.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pc.h" -#include "serial.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/isa.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "flash.h" +#include "hw/boards.h" +#include "hw/flash.h" #include "qemu/log.h" -#include "mips-bios.h" -#include "ide.h" -#include "loader.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 83c400c158..9ad13f3924 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips_cpudevs.h" +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" #include "qemu/timer.h" #define TIMER_FREQ 100 * 1000 * 1000 diff --git a/hw/mipsnet.c b/hw/mipsnet.c index ff6bf7fdcb..ac6193a89e 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -1,7 +1,7 @@ -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" #include "trace.h" -#include "sysbus.h" +#include "hw/sysbus.h" /* MIPSnet register offsets */ diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c index 728723c946..193beab2c2 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -17,9 +17,9 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define MPC8544_GUTS_MMIO_SIZE 0x1000 #define MPC8544_GUTS_RSTCR_RESET 0x02 diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 7ae05e389f..1dd15054d0 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -10,8 +10,8 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" /* Mainstone FPGA for extern irqs */ #define FPGA_GPIO_PIN 0 diff --git a/hw/multiboot.c b/hw/multiboot.c index c4ec2e34a7..3cb228f0ca 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "fw_cfg.h" -#include "multiboot.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/fw_cfg.h" +#include "hw/multiboot.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/sysemu.h" diff --git a/hw/musicpal.c b/hw/musicpal.c index 272cb80303..a37dbd7961 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -9,19 +9,19 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "serial.h" +#include "hw/boards.h" +#include "hw/serial.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "block/block.h" -#include "flash.h" +#include "hw/flash.h" #include "ui/console.h" -#include "i2c.h" +#include "hw/i2c.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" #include "ui/pixel_ops.h" diff --git a/hw/nand.c b/hw/nand.c index 4a71265ed3..4176272993 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -18,10 +18,10 @@ #ifndef NAND_IO -# include "hw.h" -# include "flash.h" +# include "hw/hw.h" +# include "hw/flash.h" # include "sysemu/blockdev.h" -# include "sysbus.h" +# include "hw/sysbus.h" #include "qemu/error-report.h" # define NAND_CMD_READ0 0x00 diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 342c6bdad1..47c00c3a76 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" -#include "qdev.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" +#include "hw/qdev.h" #include "net/net.h" -#include "ne2000.h" +#include "hw/ne2000.h" #include "exec/address-spaces.h" typedef struct ISANE2000State { diff --git a/hw/ne2000.c b/hw/ne2000.c index 3dd1c844e8..7dadc1cea7 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "ne2000.h" -#include "loader.h" +#include "hw/ne2000.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" /* debug NE2000 card */ diff --git a/hw/nseries.c b/hw/nseries.c index 99d353aaa9..c5bf9f95b3 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -20,19 +20,19 @@ #include "qemu-common.h" #include "sysemu/sysemu.h" -#include "omap.h" -#include "arm-misc.h" -#include "irq.h" +#include "hw/omap.h" +#include "hw/arm-misc.h" +#include "hw/irq.h" #include "ui/console.h" -#include "boards.h" -#include "i2c.h" -#include "devices.h" -#include "flash.h" -#include "hw.h" -#include "bt.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/i2c.h" +#include "hw/devices.h" +#include "hw/flash.h" +#include "hw/hw.h" +#include "hw/bt.h" +#include "hw/loader.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" /* Nokia N8x0 support */ diff --git a/hw/omap1.c b/hw/omap1.c index 623b101f80..6f0a8ca074 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -16,14 +16,14 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "arm-misc.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/omap.h" #include "sysemu/sysemu.h" -#include "soc_dma.h" +#include "hw/soc_dma.h" #include "sysemu/blockdev.h" #include "qemu/range.h" -#include "sysbus.h" +#include "hw/sysbus.h" /* Should signal the TCMI/GPMC */ uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) diff --git a/hw/omap2.c b/hw/omap2.c index 038a82a517..0a2cd7bab6 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -19,15 +19,15 @@ */ #include "sysemu/blockdev.h" -#include "hw.h" -#include "arm-misc.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/omap.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" #include "char/char.h" -#include "flash.h" -#include "soc_dma.h" -#include "sysbus.h" +#include "hw/flash.h" +#include "hw/soc_dma.h" +#include "hw/sysbus.h" #include "audio/audio.h" /* Enhanced Audio Controller (CODEC only) */ diff --git a/hw/omap_clk.c b/hw/omap_clk.c index 8448006067..c7b5c11626 100644 --- a/hw/omap_clk.c +++ b/hw/omap_clk.c @@ -18,8 +18,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" struct clk { const char *name; diff --git a/hw/omap_dma.c b/hw/omap_dma.c index 0c878b6ef2..0c5902f6f9 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -19,9 +19,9 @@ */ #include "qemu-common.h" #include "qemu/timer.h" -#include "omap.h" -#include "irq.h" -#include "soc_dma.h" +#include "hw/omap.h" +#include "hw/irq.h" +#include "hw/soc_dma.h" struct omap_dma_channel_s { /* transfer data */ diff --git a/hw/omap_dss.c b/hw/omap_dss.c index ae51bdfe41..948ad8fcc5 100644 --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "omap.h" +#include "hw/omap.h" struct omap_dss_s { qemu_irq irq; diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index aadf1cc59f..c79f61c2ba 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -18,9 +18,9 @@ * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/sysbus.h" struct omap_gpio_s { qemu_irq irq; diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c index 02ab0ab568..ebb259c283 100644 --- a/hw/omap_gpmc.c +++ b/hw/omap_gpmc.c @@ -18,9 +18,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "flash.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "hw/omap.h" #include "exec/memory.h" #include "exec/address-spaces.h" diff --git a/hw/omap_gptimer.c b/hw/omap_gptimer.c index a5db710dcb..8485ee84f5 100644 --- a/hw/omap_gptimer.c +++ b/hw/omap_gptimer.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "omap.h" +#include "hw/omap.h" /* GP timers */ struct omap_gp_timer_s { diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index 143b198f1d..92f7b371ea 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -16,10 +16,10 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "i2c.h" -#include "omap.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/omap.h" +#include "hw/sysbus.h" typedef struct OMAPI2CState { diff --git a/hw/omap_intc.c b/hw/omap_intc.c index 4b0acd0f33..7da9c3548c 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/sysbus.h" /* Interrupt Handlers */ struct omap_intr_handler_bank_s { diff --git a/hw/omap_l4.c b/hw/omap_l4.c index 09e983f319..cbe8a06033 100644 --- a/hw/omap_l4.c +++ b/hw/omap_l4.c @@ -17,8 +17,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" struct omap_l4_s { MemoryRegion *address_space; diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 936850a621..c426f3a13a 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -16,10 +16,10 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "omap.h" -#include "framebuffer.h" +#include "hw/omap.h" +#include "hw/framebuffer.h" #include "ui/pixel_ops.h" struct omap_lcd_panel_s { @@ -70,13 +70,13 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) #define draw_line_func drawfn #define DEPTH 8 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" #define DEPTH 15 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" #define DEPTH 16 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" #define DEPTH 32 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" static draw_line_func draw_line_table2[33] = { [0 ... 32] = NULL, diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index 7ecd9bd4ca..6e48110c9e 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -16,9 +16,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" -#include "sd.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/sd.h" struct omap_mmc_s { qemu_irq irq; diff --git a/hw/omap_sdrc.c b/hw/omap_sdrc.c index b0f3b8e675..510e6cc580 100644 --- a/hw/omap_sdrc.c +++ b/hw/omap_sdrc.c @@ -17,8 +17,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" /* SDRAM Controller Subsystem */ struct omap_sdrc_s { diff --git a/hw/omap_spi.c b/hw/omap_spi.c index 8ff01ed99d..1cbd98d338 100644 --- a/hw/omap_spi.c +++ b/hw/omap_spi.c @@ -19,8 +19,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" /* Multichannel SPI */ struct omap_mcspi_s { diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 30998c5ff3..85982334bd 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -25,12 +25,12 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "omap.h" -#include "boards.h" -#include "arm-misc.h" -#include "flash.h" +#include "hw/omap.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/omap_synctimer.c b/hw/omap_synctimer.c index 945711eff5..13e7280e69 100644 --- a/hw/omap_synctimer.c +++ b/hw/omap_synctimer.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "omap.h" +#include "hw/omap.h" struct omap_synctimer_s { MemoryRegion iomem; uint32_t val; diff --git a/hw/omap_tap.c b/hw/omap_tap.c index e273e971ed..181ecee1a5 100644 --- a/hw/omap_tap.c +++ b/hw/omap_tap.c @@ -18,8 +18,8 @@ * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" /* TEST-Chip-level TAP */ static uint64_t omap_tap_read(void *opaque, hwaddr addr, diff --git a/hw/omap_uart.c b/hw/omap_uart.c index 0ebfbf8cae..af51ce7534 100644 --- a/hw/omap_uart.c +++ b/hw/omap_uart.c @@ -18,9 +18,9 @@ * with this program; if not, see . */ #include "char/char.h" -#include "hw.h" -#include "omap.h" -#include "serial.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/serial.h" #include "exec/address-spaces.h" /* UARTs */ diff --git a/hw/onenand.c b/hw/onenand.c index 00a8738caf..ddba366ef5 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -19,13 +19,13 @@ */ #include "qemu-common.h" -#include "hw.h" -#include "flash.h" -#include "irq.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "hw/irq.h" #include "sysemu/blockdev.h" #include "exec/memory.h" #include "exec/address-spaces.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/error-report.h" /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */ diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index f9ba5eeaba..be64bf2a68 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -31,8 +31,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "net/net.h" #include "sysemu/sysemu.h" #include "trace.h" diff --git a/hw/openpic.c b/hw/openpic.c index 20a479c794..03a7075c39 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -33,14 +33,14 @@ * Serial interrupts, as implemented in Raven chipset are not supported yet. * */ -#include "hw.h" -#include "ppc/mac.h" -#include "pci/pci.h" -#include "openpic.h" -#include "sysbus.h" -#include "pci/msi.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" +#include "hw/openpic.h" +#include "hw/sysbus.h" +#include "hw/pci/msi.h" #include "qemu/bitops.h" -#include "ppc.h" +#include "hw/ppc.h" //#define DEBUG_OPENPIC diff --git a/hw/openrisc_pic.c b/hw/openrisc_pic.c index aaeb9a9171..931511ec0f 100644 --- a/hw/openrisc_pic.c +++ b/hw/openrisc_pic.c @@ -18,7 +18,7 @@ * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "cpu.h" /* OpenRISC pic handler */ diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index 30947dee6e..db2aac8cf8 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -18,15 +18,15 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "boards.h" +#include "hw/hw.h" +#include "hw/boards.h" #include "elf.h" -#include "serial.h" +#include "hw/serial.h" #include "net/net.h" -#include "loader.h" +#include "hw/loader.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/qtest.h" #define KERNEL_LOAD_ADDR 0x100 diff --git a/hw/openrisc_timer.c b/hw/openrisc_timer.c index d965be77de..f6c877f425 100644 --- a/hw/openrisc_timer.c +++ b/hw/openrisc_timer.c @@ -19,7 +19,7 @@ */ #include "cpu.h" -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */ diff --git a/hw/palm.c b/hw/palm.c index a633dfc4b1..91bc74af24 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -16,15 +16,15 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "audio/audio.h" #include "sysemu/sysemu.h" #include "ui/console.h" -#include "omap.h" -#include "boards.h" -#include "arm-misc.h" -#include "devices.h" -#include "loader.h" +#include "hw/omap.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/loader.h" #include "exec/address-spaces.h" static uint32_t static_readb(void *opaque, hwaddr offset) diff --git a/hw/pam.c b/hw/pam.c index 1d72e88e62..6c0061e06e 100644 --- a/hw/pam.c +++ b/hw/pam.c @@ -27,7 +27,7 @@ * THE SOFTWARE. */ #include "sysemu/sysemu.h" -#include "pam.h" +#include "hw/pam.h" void smram_update(MemoryRegion *smram_region, uint8_t smram, uint8_t smm_enabled) diff --git a/hw/parallel.c b/hw/parallel.c index 3a4e06bab0..0b9af43d8b 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -22,10 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" -#include "isa.h" -#include "pc.h" +#include "hw/isa.h" +#include "hw/pc.h" #include "sysemu/sysemu.h" //#define DEBUG_PARALLEL diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c index cf64a1f203..8236bce0c7 100644 --- a/hw/pc-testdev.c +++ b/hw/pc-testdev.c @@ -39,9 +39,9 @@ #if defined(CONFIG_POSIX) #include #endif -#include "hw.h" -#include "qdev.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/qdev.h" +#include "hw/isa.h" #define IOMEM_LEN 0x10000 diff --git a/hw/pc.c b/hw/pc.c index 07caba78ba..309bb83cab 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -21,29 +21,29 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "serial.h" -#include "apic.h" -#include "fdc.h" -#include "ide.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/apic.h" +#include "hw/fdc.h" +#include "hw/ide.h" +#include "hw/pci/pci.h" #include "monitor/monitor.h" -#include "fw_cfg.h" -#include "hpet_emul.h" -#include "smbios.h" -#include "loader.h" +#include "hw/fw_cfg.h" +#include "hw/hpet_emul.h" +#include "hw/smbios.h" +#include "hw/loader.h" #include "elf.h" -#include "multiboot.h" -#include "mc146818rtc.h" -#include "i8254.h" -#include "pcspk.h" -#include "pci/msi.h" -#include "sysbus.h" +#include "hw/multiboot.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" +#include "hw/pci/msi.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "kvm_i386.h" -#include "xen.h" +#include "hw/xen.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" #include "ui/qemu-spice.h" diff --git a/hw/pc.h b/hw/pc.h index da1b102ef1..03a0277852 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -4,11 +4,11 @@ #include "qemu-common.h" #include "exec/memory.h" #include "exec/ioport.h" -#include "isa.h" -#include "fdc.h" +#include "hw/isa.h" +#include "hw/fdc.h" #include "net/net.h" #include "exec/memory.h" -#include "ioapic.h" +#include "hw/ioapic.h" /* PC-style peripherals (also used by other machines). */ diff --git a/hw/pc87312.c b/hw/pc87312.c index 0e9760e6b2..c4e4c6273b 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "pc87312.h" +#include "hw/pc87312.h" #include "qemu/error-report.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" diff --git a/hw/pc87312.h b/hw/pc87312.h index 7b9e6f6132..ad087c73e5 100644 --- a/hw/pc87312.h +++ b/hw/pc87312.h @@ -25,7 +25,7 @@ #ifndef QEMU_PC87312_H #define QEMU_PC87312_H -#include "isa.h" +#include "hw/isa.h" #define TYPE_PC87312 "pc87312" diff --git a/hw/pc_piix.c b/hw/pc_piix.c index aa9cc81a2d..73a8656df8 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -24,23 +24,23 @@ #include -#include "hw.h" -#include "pc.h" -#include "apic.h" -#include "pci/pci.h" -#include "pci/pci_ids.h" -#include "usb.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/apic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_ids.h" +#include "hw/usb.h" #include "net/net.h" -#include "boards.h" -#include "ide.h" +#include "hw/boards.h" +#include "hw/ide.h" #include "sysemu/kvm.h" -#include "kvm/clock.h" +#include "hw/kvm/clock.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/arch_init.h" #include "sysemu/blockdev.h" -#include "smbus.h" -#include "xen.h" +#include "hw/smbus.h" +#include "hw/xen.h" #include "exec/memory.h" #include "exec/address-spaces.h" #include "cpu.h" diff --git a/hw/pc_q35.c b/hw/pc_q35.c index e22fb9891d..4f5f347309 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -27,17 +27,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/arch_init.h" -#include "smbus.h" -#include "boards.h" -#include "mc146818rtc.h" -#include "xen.h" +#include "hw/smbus.h" +#include "hw/boards.h" +#include "hw/mc146818rtc.h" +#include "hw/xen.h" #include "sysemu/kvm.h" -#include "kvm/clock.h" -#include "q35.h" +#include "hw/kvm/clock.h" +#include "hw/q35.h" #include "exec/address-spaces.h" -#include "ich9.h" +#include "hw/ich9.h" #include "hw/ide/pci.h" #include "hw/ide/ahci.h" #include "hw/usb.h" diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index 8b65a7a4d8..3e01528e78 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -25,13 +25,13 @@ #include "sysemu/blockdev.h" #include "qemu/error-report.h" -#include "sysbus.h" -#include "hw.h" -#include "pc.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/pc.h" #include "hw/boards.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/kvm.h" #define BIOS_FILENAME "bios.bin" diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 1124c53b8c..9cc6a4082d 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -19,13 +19,13 @@ * with this program; if not, see . */ -#include "pci/pci_bridge.h" -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/shpc.h" -#include "pci/slotid_cap.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/shpc.h" +#include "hw/pci/slotid_cap.h" #include "exec/memory.h" -#include "pci/pci_bus.h" +#include "hw/pci/pci_bus.h" struct PCIBridgeDev { PCIBridge bridge; diff --git a/hw/pckbd.c b/hw/pckbd.c index 3bad09baf2..cc63df0570 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" -#include "pc.h" -#include "ps2.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/pc.h" +#include "hw/ps2.h" #include "sysemu/sysemu.h" /* debug PC keyboard */ diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index df63b22463..55f80ca671 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -27,13 +27,13 @@ * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 */ -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "loader.h" +#include "hw/loader.h" #include "qemu/timer.h" #include "sysemu/dma.h" -#include "pcnet.h" +#include "hw/pcnet.h" //#define PCNET_DEBUG //#define PCNET_DEBUG_IO diff --git a/hw/pcnet.c b/hw/pcnet.c index e0de1e3458..b0b462b02e 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -35,13 +35,13 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -#include "qdev.h" +#include "hw/qdev.h" #include "net/net.h" #include "qemu/timer.h" #include "qemu/sockets.h" #include "sysemu/sysemu.h" -#include "pcnet.h" +#include "hw/pcnet.h" //#define PCNET_DEBUG //#define PCNET_DEBUG_IO diff --git a/hw/pcspk.c b/hw/pcspk.c index dfab9559ae..d533415950 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -22,13 +22,13 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "audio/audio.h" #include "qemu/timer.h" -#include "i8254.h" -#include "pcspk.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" #define PCSPK_BUF_LEN 1792 #define PCSPK_SAMPLE_RATE 32000 diff --git a/hw/pcspk.h b/hw/pcspk.h index 7f42bac1c8..f448d221da 100644 --- a/hw/pcspk.h +++ b/hw/pcspk.h @@ -25,8 +25,8 @@ #ifndef HW_PCSPK_H #define HW_PCSPK_H -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" static inline ISADevice *pcspk_init(ISABus *bus, ISADevice *pit) { diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index fe7a932009..cfc02207ab 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -25,23 +25,23 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #include "net/net.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" -#include "xilinx.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/xilinx.h" #include "sysemu/blockdev.h" -#include "serial.h" +#include "hw/serial.h" #include "exec/address-spaces.h" -#include "ssi.h" +#include "hw/ssi.h" -#include "microblaze_boot.h" -#include "microblaze_pic_cpu.h" +#include "hw/microblaze_boot.h" +#include "hw/microblaze_pic_cpu.h" -#include "stream.h" +#include "hw/stream.h" #define LMB_BRAM_SIZE (128 * 1024) #define FLASH_SIZE (32 * 1024 * 1024) diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c index 8605fb8c00..24983621e5 100644 --- a/hw/petalogix_s3adsp1800_mmu.c +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -23,19 +23,19 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #include "net/net.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" -#include "xilinx.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/xilinx.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "microblaze_boot.h" -#include "microblaze_pic_cpu.h" +#include "hw/microblaze_boot.h" +#include "hw/microblaze_pic_cpu.h" #define LMB_BRAM_SIZE (128 * 1024) #define FLASH_SIZE (16 * 1024 * 1024) diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 123b00653a..5d57babe07 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -36,13 +36,13 @@ * It does not implement much more ... */ -#include "hw.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/flash.h" #include "block/block.h" #include "qemu/timer.h" #include "exec/address-spaces.h" #include "qemu/host-utils.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define PFLASH_BUG(fmt, ...) \ do { \ diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 44bd4654f0..37b4fcc234 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -35,13 +35,13 @@ * It does not implement multiple sectors erase */ -#include "hw.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/flash.h" #include "qemu/timer.h" #include "block/block.h" #include "exec/address-spaces.h" #include "qemu/host-utils.h" -#include "sysbus.h" +#include "hw/sysbus.h" //#define PFLASH_DEBUG #ifdef PFLASH_DEBUG diff --git a/hw/piix4.c b/hw/piix4.c index c1cb94d39f..0f5cd014e5 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "isa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/isa.h" +#include "hw/sysbus.h" PCIDevice *piix4_dev; diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 6c77e493e4..ac33db5cde 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -22,15 +22,15 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "isa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/isa.h" +#include "hw/sysbus.h" #include "qemu/range.h" -#include "xen.h" -#include "pam.h" +#include "hw/xen.h" +#include "hw/pam.h" #include "sysemu/sysemu.h" /* diff --git a/hw/pl011.c b/hw/pl011.c index 002a50e16a..332d5b970c 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" typedef struct { diff --git a/hw/pl022.c b/hw/pl022.c index c160e9061c..536c2166fe 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -7,8 +7,8 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "ssi.h" +#include "hw/sysbus.h" +#include "hw/ssi.h" //#define DEBUG_PL022 1 diff --git a/hw/pl031.c b/hw/pl031.c index 757867ff79..764940be7e 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -11,7 +11,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" diff --git a/hw/pl041.c b/hw/pl041.c index 0b71c45748..92dddc2923 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -20,10 +20,10 @@ * */ -#include "sysbus.h" +#include "hw/sysbus.h" -#include "pl041.h" -#include "lm4549.h" +#include "hw/pl041.h" +#include "hw/lm4549.h" #if 0 #define PL041_DEBUG_LEVEL 1 diff --git a/hw/pl050.c b/hw/pl050.c index 5d06bc9a3f..bc31ab6885 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -7,8 +7,8 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "ps2.h" +#include "hw/sysbus.h" +#include "hw/ps2.h" typedef struct { SysBusDevice busdev; diff --git a/hw/pl061.c b/hw/pl061.c index a78e819d96..74bc109488 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -8,7 +8,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" //#define DEBUG_PL061 1 diff --git a/hw/pl080.c b/hw/pl080.c index f6bbf98a7e..00b66b45b0 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #define PL080_MAX_CHANNELS 8 #define PL080_CONF_E 0x1 diff --git a/hw/pl110.c b/hw/pl110.c index 3d0ac00ade..924642d697 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -7,9 +7,9 @@ * This code is licensed under the GNU LGPL */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "ui/console.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" #include "ui/pixel_ops.h" #define PL110_CR_EN 0x001 @@ -111,15 +111,15 @@ static const unsigned char *idregs[] = { }; #define BITS 8 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 15 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 16 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 24 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 32 -#include "pl110_template.h" +#include "hw/pl110_template.h" static int pl110_enabled(pl110_state *s) { diff --git a/hw/pl110_template.h b/hw/pl110_template.h index e738e4a241..ec4bfd6f8c 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -27,20 +27,20 @@ #undef RGB #define BORDER bgr #define ORDER 0 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 1 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 2 -#include "pl110_template.h" +#include "hw/pl110_template.h" #undef BORDER #define RGB #define BORDER rgb #define ORDER 0 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 1 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 2 -#include "pl110_template.h" +#include "hw/pl110_template.h" #undef BORDER static drawfn glue(pl110_draw_fn_,BITS)[48] = diff --git a/hw/pl181.c b/hw/pl181.c index 98529f7821..2527296776 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -8,8 +8,8 @@ */ #include "sysemu/blockdev.h" -#include "sysbus.h" -#include "sd.h" +#include "hw/sysbus.h" +#include "hw/sd.h" //#define DEBUG_PL181 1 diff --git a/hw/pl190.c b/hw/pl190.c index 76ac159374..9610673d94 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" /* The number of virtual priority levels. 16 user vectors plus the unvectored IRQ. Chained interrupts would require an additional level diff --git a/hw/pm_smbus.c b/hw/pm_smbus.c index ea1380ca68..790061065c 100644 --- a/hw/pm_smbus.c +++ b/hw/pm_smbus.c @@ -17,10 +17,10 @@ * License along with this library; if not, see * . */ -#include "hw.h" -#include "pc.h" -#include "pm_smbus.h" -#include "smbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pm_smbus.h" +#include "hw/smbus.h" /* no save/load? */ diff --git a/hw/ppc.c b/hw/ppc.c index 8cfb84fa13..c9437fc6a7 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" +#include "hw/hw.h" +#include "hw/ppc.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "nvram.h" +#include "hw/nvram.h" #include "qemu/log.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" diff --git a/hw/ppc405.h b/hw/ppc405.h index 535cbfb339..45c2159aa6 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -25,7 +25,7 @@ #if !defined(PPC_405_H) #define PPC_405_H -#include "ppc4xx.h" +#include "hw/ppc4xx.h" /* Bootinfo as set-up by u-boot */ typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index cf371db053..ba443cf8ef 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc405.h" -#include "nvram.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" +#include "hw/nvram.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" #include "block/block.h" -#include "boards.h" +#include "hw/boards.h" #include "qemu/log.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index d8cbe875bd..8465f6dcd4 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc405.h" -#include "serial.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" +#include "hw/serial.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "qemu/log.h" diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 73b5ac725c..66911b58c6 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -14,20 +14,20 @@ #include "config.h" #include "qemu-common.h" #include "net/net.h" -#include "hw.h" -#include "pci/pci.h" -#include "boards.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/boards.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "sysemu/device_tree.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" -#include "serial.h" -#include "ppc.h" -#include "ppc405.h" +#include "hw/serial.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index 59dba9e292..91d84bad63 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -25,7 +25,7 @@ #if !defined(PPC_4XX_H) #define PPC_4XX_H -#include "pci/pci.h" +#include "hw/pci/pci.h" /* PowerPC 4xx core initialization */ PowerPCCPU *ppc4xx_init(const char *cpu_model, diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index b6bb0e166a..49ec728a7b 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc4xx.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc4xx.h" #include "qemu/log.h" #include "exec/address-spaces.h" diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index ba2d669b83..f3bbe88529 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -19,11 +19,11 @@ /* This file implements emulation of the 32-bit PCI controller found in some * 4xx SoCs, such as the 440EP. */ -#include "hw.h" -#include "ppc.h" -#include "ppc4xx.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc4xx.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "exec/address-spaces.h" #undef DEBUG diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index 25a4e91b69..30375c0c41 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" +#include "hw/hw.h" +#include "hw/ppc.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "nvram.h" +#include "hw/nvram.h" #include "qemu/log.h" -#include "loader.h" +#include "hw/loader.h" /* Timer Control Register */ diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 1e1ade3d2e..310ae1c03d 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -14,12 +14,12 @@ * (at your option) any later version. */ -#include "hw.h" +#include "hw/hw.h" #include "hw/ppc/e500-ccsr.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "qemu/bswap.h" -#include "ppce500_pci.h" +#include "hw/ppce500_pci.h" #ifdef DEBUG_PCI #define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 5bdce52e24..d904fbe176 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -27,9 +27,9 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/kvm.h" #define MAX_CPUS 32 diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 52ee5d9401..d21e87671e 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -23,11 +23,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" -#include "pci/pci_bus.h" -#include "pci/pci_host.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_host.h" +#include "hw/pc.h" #include "exec/address-spaces.h" #define TYPE_RAVEN_PCI_DEVICE "raven" diff --git a/hw/ps2.c b/hw/ps2.c index 15cfd5bb76..233a087a5e 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ps2.h" +#include "hw/hw.h" +#include "hw/ps2.h" #include "ui/console.h" #include "sysemu/sysemu.h" diff --git a/hw/ptimer.c b/hw/ptimer.c index 24af6a2afe..4bc96c9fa2 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -5,9 +5,9 @@ * * This code is licensed under the GNU LGPL. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/host-utils.h" struct ptimer_state diff --git a/hw/puv3.c b/hw/puv3.c index c722510d7e..f9d0c2bab1 100644 --- a/hw/puv3.c +++ b/hw/puv3.c @@ -13,13 +13,13 @@ #include "ui/console.h" #include "elf.h" #include "exec/address-spaces.h" -#include "sysbus.h" -#include "boards.h" -#include "loader.h" -#include "pc.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/pc.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" #define KERNEL_LOAD_ADDR 0x03000000 #define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c index 9de63b4c34..c05a14ea16 100644 --- a/hw/puv3_dma.c +++ b/hw/puv3_dma.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" #define PUV3_DMA_CH_NR (6) #define PUV3_DMA_CH_MASK (0xff) diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c index 152248d291..b2a790b683 100644 --- a/hw/puv3_gpio.c +++ b/hw/puv3_gpio.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" typedef struct { SysBusDevice busdev; diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c index 07f5649065..6bc9e1a752 100644 --- a/hw/puv3_intc.c +++ b/hw/puv3_intc.c @@ -8,10 +8,10 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "sysbus.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" typedef struct { SysBusDevice busdev; diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c index 14c6f21a75..10a522adbb 100644 --- a/hw/puv3_ost.c +++ b/hw/puv3_ost.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "sysbus.h" -#include "ptimer.h" +#include "hw/sysbus.h" +#include "hw/ptimer.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" /* puv3 ostimer implementation. */ typedef struct { diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c index 87a687afae..6b8d94dd07 100644 --- a/hw/puv3_pm.c +++ b/hw/puv3_pm.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" typedef struct { SysBusDevice busdev; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d303320d42..c0f50c90fe 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -7,12 +7,12 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "pxa.h" +#include "hw/sysbus.h" +#include "hw/pxa.h" #include "sysemu/sysemu.h" -#include "serial.h" -#include "i2c.h" -#include "ssi.h" +#include "hw/serial.h" +#include "hw/i2c.h" +#include "hw/ssi.h" #include "char/char.h" #include "sysemu/blockdev.h" diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index c0dba45752..1db21c99ab 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -8,9 +8,9 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "pxa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/sysbus.h" #define PXA255_DMA_NUM_CHANNELS 16 #define PXA27X_DMA_NUM_CHANNELS 32 diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 05d2ad2add..eef8411e86 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -7,9 +7,9 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "sysbus.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/pxa.h" #define PXA2XX_GPIO_BANKS 4 diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 4ff04ad63b..32ea7a5d34 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -11,8 +11,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/pxa.h" #include "ui/console.h" /* diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 512a27e702..6484d27de1 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -10,13 +10,13 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pxa.h" +#include "hw/pxa.h" #include "ui/pixel_ops.h" /* FIXME: For graphic_rotate. Should probably be done in common code. */ #include "sysemu/sysemu.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" struct DMAChannel { uint32_t branch; @@ -976,15 +976,15 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = { }; #define BITS 8 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 15 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 16 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 24 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 32 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq) diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 3589968712..0df83cc1df 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -10,10 +10,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "sd.h" -#include "qdev.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/sd.h" +#include "hw/qdev.h" struct PXA2xxMMCIState { MemoryRegion iomem; diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index 3a79c728ab..66fefba58c 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -10,9 +10,9 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pcmcia.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/pcmcia.h" +#include "hw/pxa.h" struct PXA2xxPCMCIAState { diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index 90b8fef3f9..145fc78c2f 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -8,9 +8,9 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "pxa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/sysbus.h" #define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ #define ICMR 0x04 /* Interrupt Controller Mask register */ diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 5c9d2e8bc6..c173fe4c11 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -7,11 +7,11 @@ * This code is licensed under the GPL. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "pxa.h" -#include "sysbus.h" +#include "hw/pxa.h" +#include "hw/sysbus.h" #define OSMR0 0x00 #define OSMR1 0x04 diff --git a/hw/q35.c b/hw/q35.c index efebc2786a..0a25b8bf1f 100644 --- a/hw/q35.c +++ b/hw/q35.c @@ -27,8 +27,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "q35.h" +#include "hw/hw.h" +#include "hw/q35.h" /**************************************************************************** * Q35 host diff --git a/hw/q35.h b/hw/q35.h index 246c12cb04..d766bb7b02 100644 --- a/hw/q35.h +++ b/hw/q35.h @@ -22,18 +22,18 @@ #ifndef HW_Q35_H #define HW_Q35_H -#include "hw.h" +#include "hw/hw.h" #include "qemu/range.h" -#include "isa.h" -#include "sysbus.h" -#include "pc.h" -#include "apm.h" -#include "apic.h" -#include "pci/pci.h" -#include "pci/pcie_host.h" -#include "acpi.h" -#include "acpi_ich9.h" -#include "pam.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/apic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/acpi.h" +#include "hw/acpi_ich9.h" +#include "hw/pam.h" #define TYPE_Q35_HOST_DEVICE "q35-pcihost" #define Q35_HOST_DEVICE(obj) \ diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index fc2c437911..2398b4a37f 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -1,5 +1,5 @@ -#include "qdev.h" -#include "qdev-addr.h" +#include "hw/qdev.h" +#include "hw/qdev-addr.h" #include "exec/hwaddr.h" #include "qapi/qmp/qerror.h" #include "qapi/visitor.h" diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c index ce3af22193..87951444a1 100644 --- a/hw/qdev-properties-system.c +++ b/hw/qdev-properties-system.c @@ -11,7 +11,7 @@ */ #include "net/net.h" -#include "qdev.h" +#include "hw/qdev.h" #include "qapi/qmp/qerror.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index a8a31f56e4..0307a7830b 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -1,5 +1,5 @@ #include "net/net.h" -#include "qdev.h" +#include "hw/qdev.h" #include "qapi/qmp/qerror.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h index 20c67f3443..0b0465c9b3 100644 --- a/hw/qdev-properties.h +++ b/hw/qdev-properties.h @@ -1,7 +1,7 @@ #ifndef QEMU_QDEV_PROPERTIES_H #define QEMU_QDEV_PROPERTIES_H -#include "qdev-core.h" +#include "hw/qdev-core.h" /*** qdev-properties.c ***/ diff --git a/hw/qdev.c b/hw/qdev.c index 62bc8990f0..0b20280133 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -25,7 +25,7 @@ inherit from a particular bus (e.g. PCI or I2C) rather than this API directly. */ -#include "qdev.h" +#include "hw/qdev.h" #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qmp/qerror.h" diff --git a/hw/qdev.h b/hw/qdev.h index f814656e0a..5cb8b080a6 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -2,7 +2,7 @@ #define QDEV_H #include "hw/hw.h" -#include "qdev-core.h" -#include "qdev-properties.h" +#include "hw/qdev-core.h" +#include "hw/qdev-properties.h" #endif diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c index 3cd85d9b97..84f9aa1eda 100644 --- a/hw/qxl-logger.c +++ b/hw/qxl-logger.c @@ -20,7 +20,7 @@ */ #include "qemu/timer.h" -#include "qxl.h" +#include "hw/qxl.h" static const char *qxl_type[] = { [ QXL_CMD_NOP ] = "nop", diff --git a/hw/qxl-render.c b/hw/qxl-render.c index 455fb91269..d77df42b7e 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -19,7 +19,7 @@ * along with this program; if not, see . */ -#include "qxl.h" +#include "hw/qxl.h" static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) { diff --git a/hw/qxl.c b/hw/qxl.c index 2e1c5e225b..ef693486c2 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -27,7 +27,7 @@ #include "sysemu/sysemu.h" #include "trace.h" -#include "qxl.h" +#include "hw/qxl.h" /* * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as diff --git a/hw/qxl.h b/hw/qxl.h index f867a1d0ac..36f1a2502b 100644 --- a/hw/qxl.h +++ b/hw/qxl.h @@ -4,9 +4,9 @@ #include "qemu-common.h" #include "ui/console.h" -#include "hw.h" -#include "pci/pci.h" -#include "vga_int.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/vga_int.h" #include "qemu/thread.h" #include "ui/qemu-spice.h" diff --git a/hw/r2d.c b/hw/r2d.c index 2d0dd1ffba..faa03d2069 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -23,19 +23,19 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" -#include "sh.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "pci/pci.h" +#include "hw/boards.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "sh7750_regs.h" -#include "ide.h" -#include "loader.h" -#include "usb.h" -#include "flash.h" +#include "hw/sh7750_regs.h" +#include "hw/ide.h" +#include "hw/loader.h" +#include "hw/usb.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/rc4030.c b/hw/rc4030.c index a0358a319c..b065515e67 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" +#include "hw/hw.h" +#include "hw/mips.h" #include "qemu/timer.h" /********************************************************/ diff --git a/hw/realview.c b/hw/realview.c index 78da7676c4..5fb490c832 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -7,15 +7,15 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "primecell.h" -#include "devices.h" -#include "pci/pci.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/primecell.h" +#include "hw/devices.h" +#include "hw/pci/pci.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "i2c.h" +#include "hw/boards.h" +#include "hw/i2c.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 8f2a7e2f34..0ec30caa06 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" typedef struct { SysBusDevice busdev; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index d7716beb9e..786b875c58 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -51,12 +51,12 @@ /* For crc32 */ #include -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" #include "qemu/timer.h" #include "net/net.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" #include "qemu/iov.h" diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 6b56995189..0faade0766 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -18,8 +18,8 @@ #include "monitor/monitor.h" #include "sysemu/sysemu.h" -#include "sclp.h" -#include "event-facility.h" +#include "hw/s390x/sclp.h" +#include "hw/s390x/event-facility.h" typedef struct EventTypesBus { BusState qbus; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 6549211820..d4364143ea 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -12,7 +12,7 @@ #include "hw/boards.h" #include "exec/address-spaces.h" #include "s390-virtio.h" -#include "sclp.h" +#include "hw/s390x/sclp.h" #include "ioinst.h" #include "css.h" #include "virtio-ccw.h" diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index a9d3a6a91d..86d6ae0023 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -16,7 +16,7 @@ #include "sysemu/kvm.h" #include "exec/memory.h" -#include "sclp.h" +#include "hw/s390x/sclp.h" static inline S390SCLPDevice *get_event_facility(void) { diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index 475d7ba856..5c881e5f3f 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -16,8 +16,8 @@ #include "qemu/thread.h" #include "qemu/error-report.h" -#include "sclp.h" -#include "event-facility.h" +#include "hw/s390x/sclp.h" +#include "hw/s390x/event-facility.h" #include "char/char.h" typedef struct ASCIIConsoleData { diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 2538498959..5fadc86d42 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -13,8 +13,8 @@ */ #include #include "sysemu/sysemu.h" -#include "sclp.h" -#include "event-facility.h" +#include "hw/s390x/sclp.h" +#include "hw/s390x/event-facility.h" typedef struct SignalQuiesce { EventBufferHeader ebh; diff --git a/hw/sb16.c b/hw/sb16.c index 52dfedf5f1..bd51cebfd8 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" -#include "qdev.h" +#include "hw/isa.h" +#include "hw/qdev.h" #include "qemu/timer.h" #include "qemu/host-utils.h" diff --git a/hw/sbi.c b/hw/sbi.c index d58184a6aa..8795749de8 100644 --- a/hw/sbi.c +++ b/hw/sbi.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" //#define DEBUG_IRQ diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index a97f1cdc1c..163d7a1a48 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1,8 +1,8 @@ -#include "hw.h" +#include "hw/hw.h" #include "qemu/error-report.h" -#include "scsi.h" -#include "scsi-defs.h" -#include "qdev.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" +#include "hw/qdev.h" #include "sysemu/blockdev.h" #include "trace.h" #include "sysemu/dma.h" diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index d41158693e..1e128182db 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -30,8 +30,8 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "qemu-common.h" #include "qemu/error-report.h" -#include "scsi.h" -#include "scsi-defs.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" #include "sysemu/sysemu.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 8175474a67..4d04caccce 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -13,7 +13,7 @@ #include "qemu-common.h" #include "qemu/error-report.h" -#include "scsi.h" +#include "hw/scsi.h" #include "sysemu/blockdev.h" #ifdef __linux__ @@ -35,7 +35,7 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) #include #include #include -#include "scsi-defs.h" +#include "hw/scsi-defs.h" #define SCSI_SENSE_BUF_SIZE 96 diff --git a/hw/scsi.h b/hw/scsi.h index a5b5b2ec0d..33e2e0bdf1 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_SCSI_H #define QEMU_HW_SCSI_H -#include "qdev.h" +#include "hw/qdev.h" #include "block/block.h" #include "hw/block-common.h" #include "sysemu/sysemu.h" diff --git a/hw/sd.c b/hw/sd.c index 428bd78e32..a895123867 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -29,9 +29,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "hw.h" +#include "hw/hw.h" #include "block/block.h" -#include "sd.h" +#include "hw/sd.h" #include "qemu/bitmap.h" //#define DEBUG_SD 1 diff --git a/hw/sdhci.c b/hw/sdhci.c index e535df9671..93feada049 100644 --- a/hw/sdhci.c +++ b/hw/sdhci.c @@ -22,14 +22,14 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/blockdev.h" #include "sysemu/dma.h" #include "qemu/timer.h" #include "block/block_int.h" #include "qemu/bitops.h" -#include "sdhci.h" +#include "hw/sdhci.h" /* host controller debug messages */ #ifndef SDHC_DEBUG diff --git a/hw/sdhci.h b/hw/sdhci.h index 931d7406f0..a560c3c93f 100644 --- a/hw/sdhci.h +++ b/hw/sdhci.h @@ -26,8 +26,8 @@ #define SDHCI_H #include "qemu-common.h" -#include "sysbus.h" -#include "sd.h" +#include "hw/sysbus.h" +#include "hw/sd.h" /* R/W SDMA System Address register 0x0 */ #define SDHC_SYSAD 0x00 diff --git a/hw/serial-isa.c b/hw/serial-isa.c index 5a6f51f856..a630a7d506 100644 --- a/hw/serial-isa.c +++ b/hw/serial-isa.c @@ -23,8 +23,8 @@ * THE SOFTWARE. */ -#include "serial.h" -#include "isa.h" +#include "hw/serial.h" +#include "hw/isa.h" typedef struct ISASerialState { ISADevice dev; diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 1c31353f6d..954657ba32 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -25,8 +25,8 @@ /* see docs/specs/pci-serial.txt */ -#include "serial.h" -#include "pci/pci.h" +#include "hw/serial.h" +#include "hw/pci/pci.h" #define PCI_SERIAL_MAX_PORTS 4 diff --git a/hw/serial.c b/hw/serial.c index f0ce9b0c15..6a83543125 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "serial.h" +#include "hw/serial.h" #include "char/char.h" #include "qemu/timer.h" #include "exec/address-spaces.h" diff --git a/hw/serial.h b/hw/serial.h index 98ee4241be..814b8c666f 100644 --- a/hw/serial.h +++ b/hw/serial.h @@ -25,7 +25,7 @@ #ifndef HW_SERIAL_H #define HW_SERIAL_H 1 -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" #include "exec/memory.h" diff --git a/hw/sga.c b/hw/sga.c index 29bc3e0246..4b1d4e5369 100644 --- a/hw/sga.c +++ b/hw/sga.c @@ -24,9 +24,9 @@ * sgabios code originally available at code.google.com/p/sgabios * */ -#include "pci/pci.h" -#include "pc.h" -#include "loader.h" +#include "hw/pci/pci.h" +#include "hw/pc.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" #define SGABIOS_FILENAME "sgabios.bin" diff --git a/hw/sh.h b/hw/sh.h index 77bf8aad2c..6230954eac 100644 --- a/hw/sh.h +++ b/hw/sh.h @@ -2,7 +2,7 @@ #define QEMU_SH_H /* Definitions for SH board emulation. */ -#include "sh_intc.h" +#include "hw/sh_intc.h" #define A7ADDR(x) ((x) & 0x1fffffff) #define P4ADDR(x) ((x) | 0xe0000000) diff --git a/hw/sh7750.c b/hw/sh7750.c index 666f8655ed..6778c94f8e 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -23,12 +23,12 @@ * THE SOFTWARE. */ #include -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "sysemu/sysemu.h" -#include "sh7750_regs.h" -#include "sh7750_regnames.h" -#include "sh_intc.h" +#include "hw/sh7750_regs.h" +#include "hw/sh7750_regnames.h" +#include "hw/sh_intc.h" #include "cpu.h" #include "exec/address-spaces.h" diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c index 5a5a2d80de..389698d24a 100644 --- a/hw/sh7750_regnames.c +++ b/hw/sh7750_regnames.c @@ -1,7 +1,7 @@ -#include "hw.h" -#include "sh.h" -#include "sh7750_regs.h" -#include "sh7750_regnames.h" +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/sh7750_regs.h" +#include "hw/sh7750_regnames.h" #define REGNAME(r) {r, #r}, diff --git a/hw/sh_intc.c b/hw/sh_intc.c index c3f77d5092..9e64e4d353 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -8,9 +8,9 @@ * This code is licensed under the GPL. */ -#include "sh_intc.h" -#include "hw.h" -#include "sh.h" +#include "hw/sh_intc.h" +#include "hw/hw.h" +#include "hw/sh.h" //#define DEBUG_INTC //#define DEBUG_INTC_SOURCES diff --git a/hw/sh_intc.h b/hw/sh_intc.h index 6f11beeddd..b7ddcb096a 100644 --- a/hw/sh_intc.h +++ b/hw/sh_intc.h @@ -2,7 +2,7 @@ #define __SH_INTC_H__ #include "qemu-common.h" -#include "irq.h" +#include "hw/irq.h" #include "exec/address-spaces.h" typedef unsigned char intc_enum; diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 077d957003..96535dbe01 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "sysbus.h" -#include "sh.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/sysbus.h" +#include "hw/sh.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "qemu/bswap.h" #include "exec/address-spaces.h" diff --git a/hw/sh_serial.c b/hw/sh_serial.c index 21c5b1362d..40e797c5a2 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -24,8 +24,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "char/char.h" #include "exec/address-spaces.h" diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 64ea23fce6..b4503230a9 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -8,11 +8,11 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "qemu/timer.h" #include "exec/address-spaces.h" -#include "ptimer.h" +#include "hw/ptimer.h" //#define DEBUG_TIMER diff --git a/hw/shix.c b/hw/shix.c index 6f2d55a155..192579d065 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -27,11 +27,11 @@ More information in target-sh4/README.sh4 */ -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "exec/address-spaces.h" #define BIOS_FILENAME "shix_bios.bin" diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 136ceebc80..b60592b35d 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "sun4m.h" +#include "hw/sun4m.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" //#define DEBUG_IRQ_COUNT diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index af24cc1ae8..a7a9368864 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -23,7 +23,7 @@ */ #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 68a4c0cca4..83f22a0366 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "sun4m.h" +#include "hw/sun4m.h" #include "qemu/timer.h" -#include "ptimer.h" -#include "sysbus.h" +#include "hw/ptimer.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/sm501.c b/hw/sm501.c index b7ac7f9bff..0e019111bb 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -23,12 +23,12 @@ */ #include -#include "hw.h" -#include "serial.h" +#include "hw/hw.h" +#include "hw/serial.h" #include "ui/console.h" -#include "devices.h" -#include "sysbus.h" -#include "qdev-addr.h" +#include "hw/devices.h" +#include "hw/sysbus.h" +#include "hw/qdev-addr.h" #include "qemu/range.h" #include "ui/pixel_ops.h" @@ -1171,28 +1171,28 @@ typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette, int c_y, uint8_t *d, int width); #define DEPTH 8 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define DEPTH 15 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define BGR_FORMAT #define DEPTH 15 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define DEPTH 16 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define BGR_FORMAT #define DEPTH 16 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define DEPTH 32 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define BGR_FORMAT #define DEPTH 32 -#include "sm501_template.h" +#include "hw/sm501_template.h" static draw_line_func * draw_line8_funcs[] = { draw_line8_8, diff --git a/hw/smbios.c b/hw/smbios.c index a7b8bfc383..672ee9b0e7 100644 --- a/hw/smbios.c +++ b/hw/smbios.c @@ -14,8 +14,8 @@ */ #include "sysemu/sysemu.h" -#include "smbios.h" -#include "loader.h" +#include "hw/smbios.h" +#include "hw/loader.h" /* * Structures shared with the BIOS diff --git a/hw/smbus.c b/hw/smbus.c index a908591590..9626415bca 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -9,9 +9,9 @@ /* TODO: Implement PEC. */ -#include "hw.h" -#include "i2c.h" -#include "smbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/smbus.h" //#define DEBUG_SMBUS 1 diff --git a/hw/smbus.h b/hw/smbus.h index 6ed45bd03d..c3db620e00 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include "i2c.h" +#include "hw/i2c.h" #define TYPE_SMBUS_DEVICE "smbus-device" #define SMBUS_DEVICE(obj) \ diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index d36dc7bbe3..dff8403d6c 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "i2c.h" -#include "smbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/smbus.h" //#define DEBUG diff --git a/hw/smbus_ich9.c b/hw/smbus_ich9.c index 16db3a743c..732ebd3bb0 100644 --- a/hw/smbus_ich9.c +++ b/hw/smbus_ich9.c @@ -24,15 +24,15 @@ * GNU GPL, version 2 or (at your option) any later version. * */ -#include "hw.h" -#include "pc.h" -#include "pm_smbus.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pm_smbus.h" +#include "hw/pci/pci.h" #include "sysemu/sysemu.h" -#include "i2c.h" -#include "smbus.h" +#include "hw/i2c.h" +#include "hw/smbus.h" -#include "ich9.h" +#include "hw/ich9.h" #define TYPE_ICH9_SMB_DEVICE "ICH9 SMB" #define ICH9_SMB_DEVICE(obj) \ diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 67fd074d85..c2feae6eb8 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -7,9 +7,9 @@ * This code is licensed under the GPL */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "devices.h" +#include "hw/devices.h" /* For crc32 */ #include diff --git a/hw/soc_dma.c b/hw/soc_dma.c index 64e8ee1d13..db5d609388 100644 --- a/hw/soc_dma.c +++ b/hw/soc_dma.c @@ -19,7 +19,7 @@ */ #include "qemu-common.h" #include "qemu/timer.h" -#include "soc_dma.h" +#include "hw/soc_dma.h" static void transfer_mem2mem(struct soc_dma_ch_s *ch) { diff --git a/hw/spapr.c b/hw/spapr.c index e88a27aa71..2709c660c1 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -25,7 +25,7 @@ * */ #include "sysemu/sysemu.h" -#include "hw.h" +#include "hw/hw.h" #include "elf.h" #include "net/net.h" #include "sysemu/blockdev.h" @@ -45,7 +45,7 @@ #include "sysemu/kvm.h" #include "kvm_ppc.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "exec/address-spaces.h" #include "hw/usb.h" diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index d8a098cb1b..8d500bf6be 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -16,9 +16,9 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/kvm.h" -#include "qdev.h" +#include "hw/qdev.h" #include "kvm_ppc.h" #include "sysemu/dma.h" #include "exec/address-spaces.h" diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 6ef29362f5..5d2565b484 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -24,7 +24,7 @@ * THE SOFTWARE. * */ -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" #include "hw/qdev.h" #include "hw/spapr.h" diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 4eacbcfd58..36adbc5592 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -22,11 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" -#include "pci/msi.h" -#include "pci/msix.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/pci/pci_host.h" #include "hw/spapr.h" #include "hw/spapr_pci.h" #include "exec/address-spaces.h" diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 34c9ca6b65..6eb3ab5482 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -19,11 +19,11 @@ * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "boards.h" +#include "hw/boards.h" #include "monitor/monitor.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" #include "hw/sysbus.h" #include "sysemu/kvm.h" diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 7fc0e13f9f..27940949ce 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -31,10 +31,10 @@ * - Add indirect descriptors support * - Maybe do autosense (PAPR seems to mandate it, linux doesn't care) */ -#include "hw.h" -#include "scsi.h" -#include "scsi-defs.h" -#include "srp.h" +#include "hw/hw.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" +#include "hw/srp.h" #include "hw/qdev.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 5c63eaafa9..be08571d23 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -1,4 +1,4 @@ -#include "qdev.h" +#include "hw/qdev.h" #include "char/char.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 6d0df51749..18e368ec98 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -25,10 +25,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "sparc32_dma.h" -#include "sun4m.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sparc32_dma.h" +#include "hw/sun4m.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/spitz.c b/hw/spitz.c index 5bc49fcd27..f5832bea93 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -10,23 +10,23 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" #include "sysemu/sysemu.h" -#include "pcmcia.h" -#include "i2c.h" -#include "ssi.h" -#include "flash.h" +#include "hw/pcmcia.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "hw/flash.h" #include "qemu/timer.h" -#include "devices.h" -#include "sharpsl.h" +#include "hw/devices.h" +#include "hw/sharpsl.h" #include "ui/console.h" #include "block/block.h" #include "audio/audio.h" -#include "boards.h" +#include "hw/boards.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" #undef REG_FMT diff --git a/hw/ssd0303.c b/hw/ssd0303.c index 8777b1681a..db50909734 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -10,7 +10,7 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ -#include "i2c.h" +#include "hw/i2c.h" #include "ui/console.h" //#define DEBUG_SSD0303 1 diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 84c86a5244..27b4151994 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -10,7 +10,7 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ -#include "ssi.h" +#include "hw/ssi.h" #include "ui/console.h" //#define DEBUG_SSD0323 1 diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index dca8906e7d..4d3c4f6445 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -11,8 +11,8 @@ */ #include "sysemu/blockdev.h" -#include "ssi.h" -#include "sd.h" +#include "hw/ssi.h" +#include "hw/sd.h" //#define DEBUG_SSI_SD 1 diff --git a/hw/ssi.c b/hw/ssi.c index 0b18176f7a..1264d9da23 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -12,7 +12,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "ssi.h" +#include "hw/ssi.h" struct SSIBus { BusState qbus; diff --git a/hw/ssi.h b/hw/ssi.h index a05d60beb4..fdae317295 100644 --- a/hw/ssi.h +++ b/hw/ssi.h @@ -11,7 +11,7 @@ #ifndef QEMU_SSI_H #define QEMU_SSI_H -#include "qdev.h" +#include "hw/qdev.h" typedef struct SSISlave SSISlave; diff --git a/hw/stellaris.c b/hw/stellaris.c index 9b8f2034f1..f4ce7945f3 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -7,14 +7,14 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "ssi.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/ssi.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "qemu/timer.h" -#include "i2c.h" +#include "hw/i2c.h" #include "net/net.h" -#include "boards.h" +#include "hw/boards.h" #include "exec/address-spaces.h" #define GPIO_A 0 diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 6c701fb67b..59b84564a0 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -6,7 +6,7 @@ * * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" #include diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c index 7a95c3fc88..4e407922a0 100644 --- a/hw/stellaris_input.c +++ b/hw/stellaris_input.c @@ -6,8 +6,8 @@ * * This code is licensed under the GPL. */ -#include "hw.h" -#include "devices.h" +#include "hw/hw.h" +#include "hw/devices.h" #include "ui/console.h" typedef struct { diff --git a/hw/stream.c b/hw/stream.c index d4cf84d4c0..a07d6a56d3 100644 --- a/hw/stream.c +++ b/hw/stream.c @@ -1,4 +1,4 @@ -#include "stream.h" +#include "hw/stream.h" void stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app) diff --git a/hw/strongarm.c b/hw/strongarm.c index ab736e300e..49f9577e32 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -26,13 +26,13 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "strongarm.h" +#include "hw/sysbus.h" +#include "hw/strongarm.h" #include "qemu/error-report.h" -#include "arm-misc.h" +#include "hw/arm-misc.h" #include "char/char.h" #include "sysemu/sysemu.h" -#include "ssi.h" +#include "hw/ssi.h" //#define DEBUG diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c index f8f4d023a3..9d443d1b10 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "sun4m.h" +#include "hw/hw.h" +#include "hw/sun4m.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" //#define DEBUG_IRQ_COUNT //#define DEBUG_IRQ diff --git a/hw/sun4m.c b/hw/sun4m.c index 9903f443cb..37bd04108d 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -21,24 +21,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "sun4m.h" -#include "nvram.h" -#include "sparc32_dma.h" -#include "fdc.h" +#include "hw/sun4m.h" +#include "hw/nvram.h" +#include "hw/sparc32_dma.h" +#include "hw/fdc.h" #include "sysemu/sysemu.h" #include "net/net.h" -#include "boards.h" -#include "firmware_abi.h" -#include "esp.h" -#include "pc.h" -#include "isa.h" -#include "fw_cfg.h" -#include "escc.h" -#include "empty_slot.h" -#include "qdev-addr.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/firmware_abi.h" +#include "hw/esp.h" +#include "hw/pc.h" +#include "hw/isa.h" +#include "hw/fw_cfg.h" +#include "hw/escc.h" +#include "hw/empty_slot.h" +#include "hw/qdev-addr.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/blockdev.h" #include "trace.h" diff --git a/hw/sun4m.h b/hw/sun4m.h index 0361eeed41..0d2cfb807b 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -31,6 +31,6 @@ void sun4m_pic_info(Monitor *mon, const QDict *qdict); void sun4m_irq_info(Monitor *mon, const QDict *qdict); /* sparc32_dma.c */ -#include "sparc32_dma.h" +#include "hw/sparc32_dma.h" #endif diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index 8f9635f343..33e77b02a3 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sun4m.h" -#include "sysbus.h" +#include "hw/sun4m.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/sun4u.c b/hw/sun4u.c index 9fbda29ac4..51ffa1c09b 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -21,22 +21,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" -#include "apb_pci.h" -#include "pc.h" -#include "serial.h" -#include "nvram.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/apb_pci.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/nvram.h" +#include "hw/fdc.h" #include "net/net.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "firmware_abi.h" -#include "fw_cfg.h" -#include "sysbus.h" -#include "ide.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/firmware_abi.h" +#include "hw/fw_cfg.h" +#include "hw/sysbus.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/sysbus.c b/hw/sysbus.c index 6d9d1df419..74bb4b81de 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -17,7 +17,7 @@ * License along with this library; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "monitor/monitor.h" #include "exec/address-spaces.h" diff --git a/hw/sysbus.h b/hw/sysbus.h index a7fcded6e7..17de506339 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -3,7 +3,7 @@ /* Devices attached directly to the main system bus. */ -#include "qdev.h" +#include "hw/qdev.h" #include "exec/memory.h" #define QDEV_MAX_MMIO 32 diff --git a/hw/tc58128.c b/hw/tc58128.c index 4ce80b18f3..f76f96d9e7 100644 --- a/hw/tc58128.c +++ b/hw/tc58128.c @@ -1,6 +1,6 @@ -#include "hw.h" -#include "sh.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/loader.h" #define CE1 0x0100 #define CE2 0x0200 diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index e815f83198..0755463a1d 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -10,9 +10,9 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "devices.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/devices.h" +#include "hw/flash.h" #include "ui/console.h" #include "ui/pixel_ops.h" #include "sysemu/blockdev.h" @@ -421,15 +421,15 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) } #define BITS 8 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 15 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 16 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 24 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 32 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update) { diff --git a/hw/tcx.c b/hw/tcx.c index 0ce2952f73..896407d865 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -25,8 +25,8 @@ #include "qemu-common.h" #include "ui/console.h" #include "ui/pixel_ops.h" -#include "sysbus.h" -#include "qdev-addr.h" +#include "hw/sysbus.h" +#include "hw/qdev-addr.h" #define MAXX 1024 #define MAXY 768 diff --git a/hw/tmp105.c b/hw/tmp105.c index 3ad2d2f04c..47e5437e0d 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -18,9 +18,9 @@ * with this program; if not, see . */ -#include "hw.h" -#include "i2c.h" -#include "tmp105.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/tmp105.h" #include "qapi/visitor.h" static void tmp105_interrupt_update(TMP105State *s) diff --git a/hw/tmp105.h b/hw/tmp105.h index d2189191e2..9a9632c54b 100644 --- a/hw/tmp105.h +++ b/hw/tmp105.h @@ -14,8 +14,8 @@ #ifndef QEMU_TMP105_H #define QEMU_TMP105_H -#include "i2c.h" -#include "tmp105_regs.h" +#include "hw/i2c.h" +#include "hw/tmp105_regs.h" #define TYPE_TMP105 "tmp105" #define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105) diff --git a/hw/tosa.c b/hw/tosa.c index efea109795..747888c64e 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -11,18 +11,18 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" -#include "devices.h" -#include "sharpsl.h" -#include "pcmcia.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/sharpsl.h" +#include "hw/pcmcia.h" #include "block/block.h" -#include "boards.h" -#include "i2c.h" -#include "ssi.h" +#include "hw/boards.h" +#include "hw/i2c.h" +#include "hw/ssi.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" #define TOSA_RAM 0x04000000 diff --git a/hw/tpci200.c b/hw/tpci200.c index a4823fb9f2..e3408ef4ba 100644 --- a/hw/tpci200.c +++ b/hw/tpci200.c @@ -8,8 +8,8 @@ * later version. */ -#include "ipack.h" -#include "pci/pci.h" +#include "hw/ipack.h" +#include "hw/pci/pci.h" #include "qemu/bitops.h" #include diff --git a/hw/tsc2005.c b/hw/tsc2005.c index 740ff86aa8..a771cd5e52 100644 --- a/hw/tsc2005.c +++ b/hw/tsc2005.c @@ -18,10 +18,10 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "ui/console.h" -#include "devices.h" +#include "hw/devices.h" #define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10))) diff --git a/hw/tsc210x.c b/hw/tsc210x.c index 2076c355d2..b93e502e05 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -19,12 +19,12 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "audio/audio.h" #include "qemu/timer.h" #include "ui/console.h" -#include "omap.h" /* For I2SCodec and uWireSlave */ -#include "devices.h" +#include "hw/omap.h" /* For I2SCodec and uWireSlave */ +#include "hw/devices.h" #define TSC_DATA_REGISTERS_PAGE 0x0 #define TSC_CONTROL_REGISTERS_PAGE 0x1 diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 2c7d033651..a5251a34ac 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -20,11 +20,11 @@ */ #include "qemu-common.h" #include "qemu/timer.h" -#include "usb.h" -#include "omap.h" -#include "irq.h" -#include "devices.h" -#include "sysbus.h" +#include "hw/usb.h" +#include "hw/omap.h" +#include "hw/irq.h" +#include "hw/devices.h" +#include "hw/sysbus.h" typedef struct TUSBState { SysBusDevice busdev; diff --git a/hw/twl92230.c b/hw/twl92230.c index 70d9b03e55..7d020c4cba 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -19,9 +19,9 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "i2c.h" +#include "hw/i2c.h" #include "sysemu/sysemu.h" #include "ui/console.h" diff --git a/hw/unin_pci.c b/hw/unin_pci.c index f1c3c20f37..cb95ad1f5e 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" /* debug UniNorth */ //#define DEBUG_UNIN diff --git a/hw/usb.h b/hw/usb.h index 382496cf82..1b10684dde 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include "qdev.h" +#include "hw/qdev.h" #include "qemu/queue.h" /* Constants related to the USB / PCI interaction */ diff --git a/hw/versatile_i2c.c b/hw/versatile_i2c.c index ad71e9d92d..d0444aecac 100644 --- a/hw/versatile_i2c.c +++ b/hw/versatile_i2c.c @@ -21,8 +21,8 @@ * */ -#include "sysbus.h" -#include "bitbang_i2c.h" +#include "hw/sysbus.h" +#include "hw/bitbang_i2c.h" typedef struct { SysBusDevice busdev; diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 9d991599cf..0b97a4073d 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -7,9 +7,9 @@ * This code is licensed under the LGPL. */ -#include "sysbus.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "exec/address-spaces.h" typedef struct { diff --git a/hw/versatilepb.c b/hw/versatilepb.c index e0a28f08d3..baaa265888 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -7,17 +7,17 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "pci/pci.h" -#include "i2c.h" -#include "boards.h" +#include "hw/pci/pci.h" +#include "hw/i2c.h" +#include "hw/boards.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "flash.h" +#include "hw/flash.h" #define VERSATILE_FLASH_ADDR 0x34000000 #define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) diff --git a/hw/vexpress.c b/hw/vexpress.c index 741b044f1d..02922c38b3 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -21,16 +21,16 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "primecell.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/primecell.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" +#include "hw/boards.h" #include "exec/address-spaces.h" #include "sysemu/blockdev.h" -#include "flash.h" +#include "hw/flash.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index ad9ae360b2..288361d0fb 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -31,9 +31,9 @@ #include "exec/address-spaces.h" #include "sysemu/kvm.h" #include "exec/memory.h" -#include "pci/msi.h" -#include "pci/msix.h" -#include "pci/pci.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/pci/pci.h" #include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/queue.h" diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c index 311c966f77..4aa62bf35e 100644 --- a/hw/vga-isa-mm.c +++ b/hw/vga-isa-mm.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pc.h" -#include "vga_int.h" +#include "hw/pc.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" diff --git a/hw/vga-isa.c b/hw/vga-isa.c index 762e45aaeb..ffad5226fd 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -23,13 +23,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pc.h" -#include "vga_int.h" +#include "hw/pc.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" -#include "loader.h" +#include "hw/loader.h" typedef struct ISAVGAState { ISADevice dev; diff --git a/hw/vga-pci.c b/hw/vga-pci.c index c491af20e4..18018ff1c3 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -23,13 +23,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pci/pci.h" -#include "vga_int.h" +#include "hw/pci/pci.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" -#include "loader.h" +#include "hw/loader.h" #define PCI_VGA_IOPORT_OFFSET 0x400 #define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0) diff --git a/hw/vga.c b/hw/vga.c index 1caf23d7b6..2213bc1a88 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -21,15 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "vga.h" +#include "hw/hw.h" +#include "hw/vga.h" #include "ui/console.h" -#include "pc.h" -#include "pci/pci.h" -#include "vga_int.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" -#include "xen.h" +#include "hw/xen.h" #include "trace.h" //#define DEBUG_VGA @@ -986,28 +986,28 @@ typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d, const uint8_t *s, int width); #define DEPTH 8 -#include "vga_template.h" +#include "hw/vga_template.h" #define DEPTH 15 -#include "vga_template.h" +#include "hw/vga_template.h" #define BGR_FORMAT #define DEPTH 15 -#include "vga_template.h" +#include "hw/vga_template.h" #define DEPTH 16 -#include "vga_template.h" +#include "hw/vga_template.h" #define BGR_FORMAT #define DEPTH 16 -#include "vga_template.h" +#include "hw/vga_template.h" #define DEPTH 32 -#include "vga_template.h" +#include "hw/vga_template.h" #define BGR_FORMAT #define DEPTH 32 -#include "vga_template.h" +#include "hw/vga_template.h" static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) { diff --git a/hw/vhost.c b/hw/vhost.c index 8d41fdb53f..2d25d7e300 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -14,7 +14,7 @@ */ #include -#include "vhost.h" +#include "hw/vhost.h" #include "hw/hw.h" #include "qemu/range.h" #include diff --git a/hw/vhost_net.c b/hw/vhost_net.c index d1df0e2447..d3218a07f4 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -16,8 +16,8 @@ #include "net/net.h" #include "net/tap.h" -#include "virtio-net.h" -#include "vhost_net.h" +#include "hw/virtio-net.h" +#include "hw/vhost_net.h" #include "qemu/error-report.h" #include "config.h" @@ -36,7 +36,7 @@ #include -#include "vhost.h" +#include "hw/vhost.h" struct vhost_net { struct vhost_dev dev; diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 8c4e8e4313..41eab1697c 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -22,25 +22,25 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" -#include "serial.h" -#include "flash.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/serial.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" +#include "hw/devices.h" +#include "hw/boards.h" #include "sysemu/device_tree.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" #include "qemu/log.h" #include "exec/address-spaces.h" -#include "ppc.h" -#include "ppc4xx.h" -#include "ppc405.h" +#include "hw/ppc.h" +#include "hw/ppc4xx.h" +#include "hw/ppc405.h" #include "sysemu/blockdev.h" -#include "xilinx.h" +#include "hw/xilinx.h" #define EPAPR_MAGIC (0x45504150) #define FLASH_SIZE (16 * 1024 * 1024) diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index c0a790264c..6bfcddc379 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -16,11 +16,11 @@ #include "qemu/iov.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "virtio.h" -#include "pc.h" +#include "hw/virtio.h" +#include "hw/pc.h" #include "cpu.h" #include "sysemu/balloon.h" -#include "virtio-balloon.h" +#include "hw/virtio-balloon.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" #include "qapi/visitor.h" diff --git a/hw/virtio-balloon.h b/hw/virtio-balloon.h index b1828f4a48..f37f31b4d7 100644 --- a/hw/virtio-balloon.h +++ b/hw/virtio-balloon.h @@ -15,8 +15,8 @@ #ifndef _QEMU_VIRTIO_BALLOON_H #define _QEMU_VIRTIO_BALLOON_H -#include "virtio.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/pci/pci.h" /* from Linux's linux/virtio_balloon.h */ diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 34913ee40e..248a966357 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -16,11 +16,11 @@ #include "trace.h" #include "hw/block-common.h" #include "sysemu/blockdev.h" -#include "virtio-blk.h" +#include "hw/virtio-blk.h" #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE -#include "hw/dataplane/virtio-blk.h" +#include "dataplane/virtio-blk.h" #endif -#include "scsi-defs.h" +#include "hw/scsi-defs.h" #ifdef __linux__ # include #endif diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 43ca492080..7ef2f35852 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -14,7 +14,7 @@ #ifndef _QEMU_VIRTIO_BLK_H #define _QEMU_VIRTIO_BLK_H -#include "virtio.h" +#include "hw/virtio.h" #include "hw/block-common.h" /* from Linux's linux/virtio_blk.h */ diff --git a/hw/virtio-bus.c b/hw/virtio-bus.c index 6045d8ad86..6c2aab00eb 100644 --- a/hw/virtio-bus.c +++ b/hw/virtio-bus.c @@ -22,11 +22,11 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/error-report.h" -#include "qdev.h" -#include "virtio-bus.h" -#include "virtio.h" +#include "hw/qdev.h" +#include "hw/virtio-bus.h" +#include "hw/virtio.h" /* #define DEBUG_VIRTIO_BUS */ diff --git a/hw/virtio-bus.h b/hw/virtio-bus.h index 7584a0e6ae..ae0f7078b4 100644 --- a/hw/virtio-bus.h +++ b/hw/virtio-bus.h @@ -25,9 +25,9 @@ #ifndef VIRTIO_BUS_H #define VIRTIO_BUS_H -#include "qdev.h" +#include "hw/qdev.h" #include "sysemu/sysemu.h" -#include "virtio.h" +#include "hw/virtio.h" #define TYPE_VIRTIO_BUS "virtio-bus" #define VIRTIO_BUS_GET_CLASS(obj) \ diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 46072a086f..b10f5f08d4 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -13,7 +13,7 @@ #include "char/char.h" #include "qemu/error-report.h" #include "trace.h" -#include "virtio-serial.h" +#include "hw/virtio-serial.h" typedef struct VirtConsole { VirtIOSerialPort port; diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 573c669d15..0ad96eefd6 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -12,14 +12,14 @@ */ #include "qemu/iov.h" -#include "virtio.h" +#include "hw/virtio.h" #include "net/net.h" #include "net/checksum.h" #include "net/tap.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "virtio-net.h" -#include "vhost_net.h" +#include "hw/virtio-net.h" +#include "hw/vhost_net.h" #define VIRTIO_NET_VM_VERSION 11 diff --git a/hw/virtio-net.h b/hw/virtio-net.h index e654c13a9f..0c83ca5cfe 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -14,8 +14,8 @@ #ifndef _QEMU_VIRTIO_NET_H #define _QEMU_VIRTIO_NET_H -#include "virtio.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/pci/pci.h" #define ETH_ALEN 6 diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index df1dd7744c..ba4d7d5424 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -17,21 +17,21 @@ #include -#include "virtio.h" -#include "virtio-blk.h" -#include "virtio-net.h" -#include "virtio-serial.h" -#include "virtio-scsi.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/virtio-blk.h" +#include "hw/virtio-net.h" +#include "hw/virtio-serial.h" +#include "hw/virtio-scsi.h" +#include "hw/pci/pci.h" #include "qemu/error-report.h" -#include "pci/msi.h" -#include "pci/msix.h" -#include "loader.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/loader.h" #include "sysemu/kvm.h" #include "sysemu/blockdev.h" -#include "virtio-pci.h" +#include "hw/virtio-pci.h" #include "qemu/range.h" -#include "virtio-bus.h" +#include "hw/virtio-bus.h" /* from Linux's linux/virtio_pci.h */ diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index d01db97e1e..2ae96f84d6 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -16,13 +16,13 @@ #define QEMU_VIRTIO_PCI_H #include "hw/pci/msi.h" -#include "virtio-blk.h" -#include "virtio-net.h" -#include "virtio-rng.h" -#include "virtio-serial.h" -#include "virtio-scsi.h" -#include "virtio-bus.h" -#include "9pfs/virtio-9p-device.h" +#include "hw/virtio-blk.h" +#include "hw/virtio-net.h" +#include "hw/virtio-rng.h" +#include "hw/virtio-serial.h" +#include "hw/virtio-scsi.h" +#include "hw/virtio-bus.h" +#include "hw/9pfs/virtio-9p-device.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c index 2cdf4ec052..54c1421f86 100644 --- a/hw/virtio-rng.c +++ b/hw/virtio-rng.c @@ -10,10 +10,10 @@ */ #include "qemu/iov.h" -#include "qdev.h" +#include "hw/qdev.h" #include "qapi/qmp/qerror.h" -#include "virtio.h" -#include "virtio-rng.h" +#include "hw/virtio.h" +#include "hw/virtio-rng.h" #include "qemu/rng.h" typedef struct VirtIORNG { diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 27070d1eea..72cc5198d4 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -13,7 +13,7 @@ * */ -#include "virtio-scsi.h" +#include "hw/virtio-scsi.h" #include "qemu/error-report.h" #include #include diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h index 8d9d15f093..81b3279a57 100644 --- a/hw/virtio-scsi.h +++ b/hw/virtio-scsi.h @@ -14,8 +14,8 @@ #ifndef _QEMU_VIRTIO_SCSI_H #define _QEMU_VIRTIO_SCSI_H -#include "virtio.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/pci/pci.h" /* The ID for virtio_scsi */ #define VIRTIO_ID_SCSI 8 diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index aa7d0d7fc7..ada1d0100b 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -21,9 +21,9 @@ #include "qemu/iov.h" #include "monitor/monitor.h" #include "qemu/queue.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" -#include "virtio-serial.h" +#include "hw/virtio-serial.h" /* The virtio-serial bus on top of which the ports will ride as devices */ struct VirtIOSerialBus { diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index 16e39820a2..d2d9fb773e 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -15,8 +15,8 @@ #ifndef _QEMU_VIRTIO_SERIAL_H #define _QEMU_VIRTIO_SERIAL_H -#include "qdev.h" -#include "virtio.h" +#include "hw/qdev.h" +#include "hw/virtio.h" /* == Interface shared between the guest kernel and qemu == */ diff --git a/hw/virtio.c b/hw/virtio.c index e259348518..26fbc790ec 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -15,9 +15,9 @@ #include "trace.h" #include "qemu/error-report.h" -#include "virtio.h" +#include "hw/virtio.h" #include "qemu/atomic.h" -#include "virtio-bus.h" +#include "hw/virtio-bus.h" /* The alignment to use between consumer and producer parts of vring. * x86 pagesize again. */ diff --git a/hw/virtio.h b/hw/virtio.h index 8cc71e99b6..ca43fd70cd 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -14,13 +14,13 @@ #ifndef _QEMU_VIRTIO_H #define _QEMU_VIRTIO_H -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" -#include "qdev.h" +#include "hw/qdev.h" #include "sysemu/sysemu.h" #include "qemu/event_notifier.h" #ifdef CONFIG_VIRTFS -#include "9pfs/virtio-9p-device.h" +#include "hw/9pfs/virtio-9p-device.h" #endif /* from Linux's linux/virtio_config.h */ diff --git a/hw/vmmouse.c b/hw/vmmouse.c index b9afc2c4e8..a9d227e17d 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "ps2.h" -#include "pc.h" -#include "qdev.h" +#include "hw/ps2.h" +#include "hw/pc.h" +#include "hw/qdev.h" /* debug only vmmouse */ //#define DEBUG_VMMOUSE diff --git a/hw/vmport.c b/hw/vmport.c index faead3a955..cc1466ae96 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/pc.h" #include "sysemu/kvm.h" -#include "qdev.h" +#include "hw/qdev.h" //#define VMPORT_DEBUG diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 8fc201bfb9..db2f187e56 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -21,17 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/loader.h" #include "ui/console.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #undef VERBOSE #define HW_RECT_ACCEL #define HW_FILL_ACCEL #define HW_MOUSE_ACCEL -#include "vga_int.h" +#include "hw/vga_int.h" /* See http://vmware-svga.sf.net/ for some documentation on VMWare SVGA */ diff --git a/hw/vt82c686.c b/hw/vt82c686.c index c2b1bfce10..452950826c 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -10,18 +10,18 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "vt82c686.h" -#include "i2c.h" -#include "smbus.h" -#include "pci/pci.h" -#include "isa.h" -#include "sysbus.h" -#include "mips.h" -#include "apm.h" -#include "acpi.h" -#include "pm_smbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/vt82c686.h" +#include "hw/i2c.h" +#include "hw/smbus.h" +#include "hw/pci/pci.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/mips.h" +#include "hw/apm.h" +#include "hw/acpi.h" +#include "hw/pm_smbus.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" #include "exec/address-spaces.h" diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 37ce362811..f13e507fcf 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -23,9 +23,9 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "watchdog.h" -#include "hw.h" -#include "pci/pci.h" +#include "hw/watchdog.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" /*#define I6300ESB_DEBUG 1*/ diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index 599a86f5f6..6c52808ac0 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -21,10 +21,10 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "watchdog.h" -#include "hw.h" -#include "isa.h" -#include "pc.h" +#include "hw/watchdog.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/pc.h" /*#define IB700_DEBUG 1*/ diff --git a/hw/wm8750.c b/hw/wm8750.c index d3ea5ba8f5..0904cf496d 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -7,8 +7,8 @@ * This file is licensed under GNU GPL. */ -#include "hw.h" -#include "i2c.h" +#include "hw/hw.h" +#include "hw/i2c.h" #include "audio/audio.h" #define IN_PORT_N 3 diff --git a/hw/xen-host-pci-device.c b/hw/xen-host-pci-device.c index 743b37b991..ff2e876b3d 100644 --- a/hw/xen-host-pci-device.c +++ b/hw/xen-host-pci-device.c @@ -7,7 +7,7 @@ */ #include "qemu-common.h" -#include "xen-host-pci-device.h" +#include "hw/xen-host-pci-device.h" #define XEN_HOST_PCI_MAX_EXT_CAP \ ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4)) diff --git a/hw/xen-host-pci-device.h b/hw/xen-host-pci-device.h index 942b24dccc..c2486f0c19 100644 --- a/hw/xen-host-pci-device.h +++ b/hw/xen-host-pci-device.h @@ -1,7 +1,7 @@ #ifndef XEN_HOST_PCI_DEVICE_H #define XEN_HOST_PCI_DEVICE_H -#include "pci/pci.h" +#include "hw/pci/pci.h" enum { XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1, diff --git a/hw/xen_apic.c b/hw/xen_apic.c index 1d1d15c289..8f387b6403 100644 --- a/hw/xen_apic.c +++ b/hw/xen_apic.c @@ -11,7 +11,7 @@ */ #include "hw/apic_internal.h" #include "hw/pci/msi.h" -#include "xen.h" +#include "hw/xen.h" static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/xen_backend.c b/hw/xen_backend.c index 3fa30098ca..24381b55e5 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -34,10 +34,10 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" #include "qemu/log.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include diff --git a/hw/xen_backend.h b/hw/xen_backend.h index f37afb1f05..6d5c699c51 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_XEN_BACKEND_H #define QEMU_HW_XEN_BACKEND_H 1 -#include "xen_common.h" +#include "hw/xen_common.h" #include "sysemu/sysemu.h" #include "net/net.h" diff --git a/hw/xen_common.h b/hw/xen_common.h index 95bc9a7825..c37bde3f7e 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -14,8 +14,8 @@ #endif #include -#include "hw.h" -#include "xen.h" +#include "hw/hw.h" +#include "hw/xen.h" #include "qemu/queue.h" /* diff --git a/hw/xen_console.c b/hw/xen_console.c index 44141f8692..a8db6f8d8f 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -29,9 +29,9 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c index e2ba741d54..cdcaf62f26 100644 --- a/hw/xen_devconfig.c +++ b/hw/xen_devconfig.c @@ -1,4 +1,4 @@ -#include "xen_backend.h" +#include "hw/xen_backend.h" #include "sysemu/blockdev.h" /* ------------------------------------------------------------- */ diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 7fea87156d..cc09a2f1fa 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -35,9 +35,9 @@ #include #include -#include "hw.h" -#include "xen_backend.h" -#include "xen_blkif.h" +#include "hw/hw.h" +#include "hw/xen_backend.h" +#include "hw/xen_blkif.h" #include "sysemu/blockdev.h" /* ------------------------------------------------------------- */ diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index a4272f0680..d477061545 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -1,6 +1,6 @@ #include -#include "xen_backend.h" -#include "xen_domainbuild.h" +#include "hw/xen_backend.h" +#include "hw/xen_domainbuild.h" #include "qemu/timer.h" #include "qemu/log.h" diff --git a/hw/xen_domainbuild.h b/hw/xen_domainbuild.h index dea0121868..681cbe5fd8 100644 --- a/hw/xen_domainbuild.h +++ b/hw/xen_domainbuild.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_XEN_DOMAINBUILD_H #define QEMU_HW_XEN_DOMAINBUILD_H 1 -#include "xen_common.h" +#include "hw/xen_common.h" int xenstore_domain_init1(const char *kernel, const char *ramdisk, const char *cmdline); diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 66e898123e..a8177b6340 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "boards.h" -#include "xen_backend.h" -#include "xen_domainbuild.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/boards.h" +#include "hw/xen_backend.h" +#include "hw/xen_domainbuild.h" #include "sysemu/blockdev.h" static void xen_init_pv(QEMUMachineInitArgs *args) diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 34961c287a..b6d36793b3 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -35,11 +35,11 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" #include "net/checksum.h" #include "net/util.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include diff --git a/hw/xen_platform.c b/hw/xen_platform.c index 8866468c99..5e11c950ab 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -25,12 +25,12 @@ #include -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "irq.h" -#include "xen_common.h" -#include "xen_backend.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/irq.h" +#include "hw/xen_common.h" +#include "hw/xen_backend.h" #include "trace.h" #include "exec/address-spaces.h" diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 9db5f6e964..ce695d0e64 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -54,10 +54,10 @@ #include -#include "pci/pci.h" -#include "xen.h" -#include "xen_backend.h" -#include "xen_pt.h" +#include "hw/pci/pci.h" +#include "hw/xen.h" +#include "hw/xen_backend.h" +#include "hw/xen_pt.h" #include "qemu/range.h" #include "exec/address-spaces.h" diff --git a/hw/xen_pt.h b/hw/xen_pt.h index e3497302cf..1cd9f44704 100644 --- a/hw/xen_pt.h +++ b/hw/xen_pt.h @@ -2,9 +2,9 @@ #define XEN_PT_H #include "qemu-common.h" -#include "xen_common.h" -#include "pci/pci.h" -#include "xen-host-pci-device.h" +#include "hw/xen_common.h" +#include "hw/pci/pci.h" +#include "hw/xen-host-pci-device.h" void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3); diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c index 54a179af90..55838216d9 100644 --- a/hw/xen_pt_config_init.c +++ b/hw/xen_pt_config_init.c @@ -13,8 +13,8 @@ */ #include "qemu/timer.h" -#include "xen_backend.h" -#include "xen_pt.h" +#include "hw/xen_backend.h" +#include "hw/xen_pt.h" #define XEN_PT_MERGE_VALUE(value, data, val_mask) \ (((value) & (val_mask)) | ((data) & ~(val_mask))) diff --git a/hw/xen_pt_msi.c b/hw/xen_pt_msi.c index db757cd1f1..a54ee2bfd9 100644 --- a/hw/xen_pt_msi.c +++ b/hw/xen_pt_msi.c @@ -11,9 +11,9 @@ #include -#include "xen_backend.h" -#include "xen_pt.h" -#include "apic-msidef.h" +#include "hw/xen_backend.h" +#include "hw/xen_pt.h" +#include "hw/apic-msidef.h" #define XEN_PT_AUTO_ASSIGN -1 diff --git a/hw/xenfb.c b/hw/xenfb.c index 7f1f6b4643..3462ded619 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -35,10 +35,10 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" #include "char/char.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include #include diff --git a/hw/xgmac.c b/hw/xgmac.c index 50722988b9..5275f4810d 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "qemu/log.h" #include "net/net.h" diff --git a/hw/xics.c b/hw/xics.c index 9ef0d61377..c3ef12fff4 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -25,7 +25,7 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "trace.h" #include "hw/spapr.h" #include "hw/xics.h" diff --git a/hw/xilinx.h b/hw/xilinx.h index a78281f730..6c1ee21c54 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -4,7 +4,7 @@ #include "qemu-common.h" #include "qapi/qmp/qerror.h" -#include "stream.h" +#include "hw/stream.h" #include "net/net.h" static inline DeviceState * diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index cc51584dfc..8db1a74acf 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -22,13 +22,13 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/log.h" -#include "qdev-addr.h" +#include "hw/qdev-addr.h" -#include "stream.h" +#include "hw/stream.h" #define D(x) diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 66b9ec1cc5..5785290224 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -22,13 +22,13 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/log.h" #include "net/net.h" #include "net/checksum.h" #include "qapi/qmp/qerror.h" -#include "stream.h" +#include "hw/stream.h" #define DPHY(x) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 21c6f8c49c..b2e35237f8 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #include "net/net.h" #define D(x) diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index 0c34149c27..b106e724ab 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #define D(x) diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c index e73c9bd79b..f6bd3bac23 100644 --- a/hw/xilinx_spi.c +++ b/hw/xilinx_spi.c @@ -24,12 +24,12 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/log.h" #include "qemu/fifo8.h" -#include "ssi.h" +#include "hw/ssi.h" #ifdef XILINX_SPI_ERR_DEBUG #define DB_PRINT(...) do { \ diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 915eb96a48..6c21b9668b 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -22,12 +22,12 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/log.h" #include "qemu/fifo8.h" -#include "ssi.h" +#include "hw/ssi.h" #include "qemu/bitops.h" #ifdef XILINX_SPIPS_ERR_DEBUG diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index aa162efaad..0c39cff089 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "ptimer.h" +#include "hw/sysbus.h" +#include "hw/ptimer.h" #include "qemu/log.h" #define D(x) diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index 9963982ef6..079f4d4e1a 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #define DUART(x) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 2f67d90ee1..f78c47e43e 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -15,16 +15,16 @@ * with this program; if not, see . */ -#include "sysbus.h" -#include "arm-misc.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" #include "net/net.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "flash.h" +#include "hw/boards.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" -#include "loader.h" -#include "ssi.h" +#include "hw/loader.h" +#include "hw/ssi.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 7f00bc8256..4bccd0ddcd 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -19,10 +19,10 @@ * with this program; if not, see . */ -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/pcie.h" -#include "xio3130_downstream.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/xio3130_downstream.h" #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ #define XIO3130_REVISION 0x1 diff --git a/hw/xio3130_downstream.h b/hw/xio3130_downstream.h index 559dff6565..8426d9ffa6 100644 --- a/hw/xio3130_downstream.h +++ b/hw/xio3130_downstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_DOWNSTREAM_H #define QEMU_XIO3130_DOWNSTREAM_H -#include "pci/pcie_port.h" +#include "hw/pci/pcie_port.h" PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 70b15d37c8..82556aaadc 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -19,10 +19,10 @@ * with this program; if not, see . */ -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/pcie.h" -#include "xio3130_upstream.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/xio3130_upstream.h" #define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */ #define XIO3130_REVISION 0x2 diff --git a/hw/xio3130_upstream.h b/hw/xio3130_upstream.h index fa09656b35..08c1d5f75b 100644 --- a/hw/xio3130_upstream.h +++ b/hw/xio3130_upstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_UPSTREAM_H #define QEMU_XIO3130_UPSTREAM_H -#include "pci/pcie_port.h" +#include "hw/pci/pcie_port.h" PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index a810b9eae0..f2a63d82da 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -26,18 +26,18 @@ */ #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/memory.h" #include "exec/address-spaces.h" -#include "serial.h" +#include "hw/serial.h" #include "net/net.h" -#include "sysbus.h" -#include "flash.h" +#include "hw/sysbus.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "char/char.h" -#include "xtensa_bootparam.h" +#include "hw/xtensa_bootparam.h" typedef struct LxBoardDesc { size_t flash_size; diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c index 97d36be272..f485a1465c 100644 --- a/hw/xtensa_pic.c +++ b/hw/xtensa_pic.c @@ -25,7 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/log.h" #include "qemu/timer.h" diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c index 864e57c52c..5241f8d734 100644 --- a/hw/xtensa_sim.c +++ b/hw/xtensa_sim.c @@ -26,8 +26,8 @@ */ #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/memory.h" #include "exec/address-spaces.h" diff --git a/hw/z2.c b/hw/z2.c index 731550f2d8..cbb6d8085e 100644 --- a/hw/z2.c +++ b/hw/z2.c @@ -11,15 +11,15 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" -#include "devices.h" -#include "i2c.h" -#include "ssi.h" -#include "boards.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "hw/boards.h" #include "sysemu/sysemu.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "ui/console.h" #include "audio/audio.h" diff --git a/hw/zaurus.c b/hw/zaurus.c index 2defe3b48d..7d3258cc66 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -15,9 +15,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "sharpsl.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sharpsl.h" +#include "hw/sysbus.h" #undef REG_FMT #define REG_FMT "0x%02lx" diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 27b00f07d4..8418327261 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -14,9 +14,9 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #ifdef ZYNQ_ARM_SLCR_ERR_DEBUG -- cgit v1.2.3 From 320ba5fe494c0ef59080eac33801ec1e453663fa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:36:30 +0100 Subject: build: always link device_tree.o into emulators if libfdt available Signed-off-by: Paolo Bonzini --- Makefile.target | 1 + configure | 7 +------ hw/arm/Makefile.objs | 1 - hw/microblaze/Makefile.objs | 1 - hw/ppc/Makefile.objs | 1 - 5 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Makefile.target b/Makefile.target index ca657b325a..2bd6d1471c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -111,6 +111,7 @@ CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y) obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o obj-y += qtest.o obj-y += hw/ +obj-$(CONFIG_FDT) += device_tree.o obj-$(CONFIG_KVM) += kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-y += memory.o savevm.o cputlb.o diff --git a/configure b/configure index 19738ac968..8fdc2cf68d 100755 --- a/configure +++ b/configure @@ -2416,6 +2416,7 @@ int main(void) { return 0; } EOF if compile_prog "" "$fdt_libs" ; then fdt=yes + libs_softmmu="$libs_softmmu $fdt_libs" else if test "$fdt" = "yes" ; then feature_not_found "fdt" @@ -3981,7 +3982,6 @@ case "$target_arch2" in target_nptl="yes" gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" target_llong_alignment=4 - target_libs_softmmu="$fdt_libs" ;; cris) target_nptl="yes" @@ -4000,7 +4000,6 @@ case "$target_arch2" in TARGET_ARCH=microblaze bflt="yes" target_nptl="yes" - target_libs_softmmu="$fdt_libs" ;; mips|mipsel) TARGET_ARCH=mips @@ -4025,21 +4024,18 @@ case "$target_arch2" in ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_nptl="yes" - target_libs_softmmu="$fdt_libs" ;; ppcemb) TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_nptl="yes" - target_libs_softmmu="$fdt_libs" ;; ppc64) TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_long_alignment=8 - target_libs_softmmu="$fdt_libs" ;; ppc64abi32) TARGET_ARCH=ppc64 @@ -4047,7 +4043,6 @@ case "$target_arch2" in TARGET_ABI_DIR=ppc echo "TARGET_ABI32=y" >> $config_target_mak gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml" - target_libs_softmmu="$fdt_libs" ;; sh4|sh4eb) TARGET_ARCH=sh4 diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 4c109858fd..3eb1366aee 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -31,6 +31,5 @@ obj-y += strongarm.o obj-y += collie.o obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o obj-y += kzm.o -obj-$(CONFIG_FDT) += ../device_tree.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index 3028e651c8..2ff8048a98 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -5,6 +5,5 @@ obj-y += xilinx_spi.o obj-y += microblaze_pic_cpu.o obj-y += xilinx_ethlite.o -obj-$(CONFIG_FDT) += ../device_tree.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index f7620509a9..bbbe78e1f5 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -16,7 +16,6 @@ obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o obj-y += virtex_ml507.o # PowerPC OpenPIC obj-y += openpic.o -obj-$(CONFIG_FDT) += ../device_tree.o # Xilinx PPC peripherals obj-y += xilinx_ethlite.o -- cgit v1.2.3 From e4c8b28cde12d01ada8fe869567dc5717a2dfcb7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:52:23 +0100 Subject: ppc: express FDT dependency of pSeries and e500 boards via default-configs/ Signed-off-by: Paolo Bonzini --- configure | 3 --- default-configs/ppc-softmmu.mak | 1 + default-configs/ppc64-softmmu.mak | 2 ++ default-configs/ppcemb-softmmu.mak | 1 + hw/ppc/Makefile.objs | 4 ++-- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 8fdc2cf68d..ae3d9c5378 100755 --- a/configure +++ b/configure @@ -4144,9 +4144,6 @@ case "$target_arch2" in i386|x86_64) echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak esac -if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then - echo "CONFIG_PSERIES=y" >> $config_target_mak -fi if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak fi diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index f9f8a8159b..c209a8da65 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -40,3 +40,4 @@ CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y CONFIG_XILINX=y +CONFIG_E500=$(CONFIG_FDT) diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index dc44294378..8d490bd72e 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -40,3 +40,5 @@ CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y CONFIG_XILINX=y +CONFIG_PSERIES=$(CONFIG_FDT) +CONFIG_E500=$(CONFIG_FDT) diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 1c6bcf93fc..7f13421d93 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -35,3 +35,4 @@ CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y CONFIG_XILINX=y +CONFIG_E500=$(CONFIG_FDT) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index bbbe78e1f5..9141373f40 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -11,7 +11,7 @@ obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-y += ppc440_bamboo.o # PowerPC E500 boards -obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o +obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o # PowerPC 440 Xilinx ML507 reference board. obj-y += virtex_ml507.o # PowerPC OpenPIC @@ -29,4 +29,4 @@ obj-y += mac_oldworld.o # NewWorld PowerMac obj-y += mac_newworld.o # e500 -obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o +obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o -- cgit v1.2.3 From 530182169e897c0e401b245552a4c58dc6846912 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:03:15 +0100 Subject: hw: move boards and other isolated files to hw/ARCH Signed-off-by: Paolo Bonzini --- hw/Makefile.objs | 1 - hw/alpha/Makefile.objs | 4 +- hw/alpha/dp264.c | 182 +++ hw/alpha/pci.c | 109 ++ hw/alpha_dp264.c | 182 --- hw/alpha_pci.c | 109 -- hw/an5206.c | 100 -- hw/arm/Makefile.objs | 31 +- hw/arm/boot.c | 480 ++++++ hw/arm/collie.c | 73 + hw/arm/exynos4_boards.c | 170 ++ hw/arm/gumstix.c | 141 ++ hw/arm/highbank.c | 342 ++++ hw/arm/integratorcp.c | 566 +++++++ hw/arm/kzm.c | 157 ++ hw/arm/mainstone.c | 190 +++ hw/arm/musicpal.c | 1697 ++++++++++++++++++++ hw/arm/nseries.c | 1430 +++++++++++++++++ hw/arm/omap_sx1.c | 238 +++ hw/arm/palm.c | 291 ++++ hw/arm/pic_cpu.c | 40 + hw/arm/realview.c | 404 +++++ hw/arm/spitz.c | 1138 +++++++++++++ hw/arm/stellaris.c | 1401 ++++++++++++++++ hw/arm/tosa.c | 302 ++++ hw/arm/versatilepb.c | 403 +++++ hw/arm/vexpress.c | 500 ++++++ hw/arm/xilinx_zynq.c | 224 +++ hw/arm/z2.c | 384 +++++ hw/arm_boot.c | 480 ------ hw/arm_pic.c | 40 - hw/axis_dev88.c | 366 ----- hw/collie.c | 73 - hw/cris-boot.c | 98 -- hw/cris/Makefile.objs | 10 +- hw/cris/axis_dev88.c | 366 +++++ hw/cris/boot.c | 98 ++ hw/cris/pic_cpu.c | 45 + hw/cris_pic_cpu.c | 45 - hw/dummy_m68k.c | 84 - hw/exynos4_boards.c | 170 -- hw/gumstix.c | 141 -- hw/highbank.c | 342 ---- hw/i386/Makefile.objs | 13 +- hw/i386/multiboot.c | 349 ++++ hw/i386/pc.c | 1161 ++++++++++++++ hw/i386/pc_piix.c | 713 +++++++++ hw/i386/pc_q35.c | 239 +++ hw/i386/smbios.c | 241 +++ hw/i386/xen_domainbuild.c | 299 ++++ hw/i386/xen_machine_pv.c | 126 ++ hw/integratorcp.c | 566 ------- hw/kzm.c | 157 -- hw/leon3.c | 223 --- hw/lm32/Makefile.objs | 8 +- hw/lm32/lm32_boards.c | 308 ++++ hw/lm32/milkymist.c | 218 +++ hw/lm32_boards.c | 308 ---- hw/m68k/Makefile.objs | 7 +- hw/m68k/an5206.c | 100 ++ hw/m68k/dummy_m68k.c | 84 + hw/m68k/mcf5208.c | 306 ++++ hw/mainstone.c | 190 --- hw/mcf5208.c | 306 ---- hw/microblaze/Makefile.objs | 10 +- hw/microblaze/boot.c | 177 +++ hw/microblaze/petalogix_ml605_mmu.c | 186 +++ hw/microblaze/petalogix_s3adsp1800_mmu.c | 127 ++ hw/microblaze/pic_cpu.c | 44 + hw/microblaze_boot.c | 177 --- hw/microblaze_pic_cpu.c | 44 - hw/milkymist.c | 218 --- hw/mips/Makefile.objs | 8 +- hw/mips/addr.c | 34 + hw/mips/cputimer.c | 147 ++ hw/mips/mips_fulong2e.c | 411 +++++ hw/mips/mips_int.c | 65 + hw/mips/mips_jazz.c | 345 ++++ hw/mips/mips_malta.c | 1037 ++++++++++++ hw/mips/mips_mipssim.c | 240 +++ hw/mips/mips_r4k.c | 313 ++++ hw/mips_addr.c | 34 - hw/mips_fulong2e.c | 411 ----- hw/mips_int.c | 65 - hw/mips_jazz.c | 345 ---- hw/mips_malta.c | 1037 ------------ hw/mips_mipssim.c | 240 --- hw/mips_r4k.c | 313 ---- hw/mips_timer.c | 147 -- hw/multiboot.c | 349 ---- hw/musicpal.c | 1697 -------------------- hw/nseries.c | 1430 ----------------- hw/omap_sx1.c | 238 --- hw/openrisc/Makefile.objs | 5 +- hw/openrisc/cputimer.c | 101 ++ hw/openrisc/openrisc_sim.c | 150 ++ hw/openrisc/pic_cpu.c | 60 + hw/openrisc_pic.c | 60 - hw/openrisc_sim.c | 150 -- hw/openrisc_timer.c | 101 -- hw/palm.c | 291 ---- hw/pc.c | 1161 -------------- hw/pc_piix.c | 713 --------- hw/pc_q35.c | 239 --- hw/petalogix_ml605_mmu.c | 186 --- hw/petalogix_s3adsp1800_mmu.c | 127 -- hw/ppc.c | 1356 ---------------- hw/ppc/Makefile.objs | 17 +- hw/ppc/ppc.c | 1356 ++++++++++++++++ hw/ppc/ppc405_boards.c | 662 ++++++++ hw/ppc/ppc405_uc.c | 2548 ++++++++++++++++++++++++++++++ hw/ppc/ppc440_bamboo.c | 306 ++++ hw/ppc/ppc_booke.c | 273 ++++ hw/ppc/spapr.c | 963 +++++++++++ hw/ppc/virtex_ml507.c | 274 ++++ hw/ppc405_boards.c | 662 -------- hw/ppc405_uc.c | 2548 ------------------------------ hw/ppc440_bamboo.c | 306 ---- hw/ppc_booke.c | 273 ---- hw/puv3.c | 135 -- hw/r2d.c | 364 ----- hw/realview.c | 404 ----- hw/sh4/Makefile.objs | 4 +- hw/sh4/r2d.c | 364 +++++ hw/sh4/shix.c | 103 ++ hw/shix.c | 103 -- hw/smbios.c | 241 --- hw/spapr.c | 963 ----------- hw/sparc/Makefile.objs | 6 +- hw/sparc/leon3.c | 223 +++ hw/sparc/sun4m.c | 1936 +++++++++++++++++++++++ hw/sparc64/Makefile.objs | 4 +- hw/sparc64/sun4u.c | 1014 ++++++++++++ hw/spitz.c | 1138 ------------- hw/stellaris.c | 1401 ---------------- hw/sun4m.c | 1936 ----------------------- hw/sun4u.c | 1014 ------------ hw/tosa.c | 302 ---- hw/unicore32/Makefile.objs | 2 - hw/unicore32/puv3.c | 135 ++ hw/versatilepb.c | 403 ----- hw/vexpress.c | 500 ------ hw/virtex_ml507.c | 274 ---- hw/xen_domainbuild.c | 299 ---- hw/xen_machine_pv.c | 126 -- hw/xilinx_zynq.c | 224 --- hw/xtensa/Makefile.objs | 4 +- hw/xtensa/pic_cpu.c | 164 ++ hw/xtensa/xtensa_lx60.c | 315 ++++ hw/xtensa/xtensa_sim.c | 117 ++ hw/xtensa_lx60.c | 315 ---- hw/xtensa_pic.c | 164 -- hw/xtensa_sim.c | 117 -- hw/z2.c | 384 ----- 154 files changed, 29777 insertions(+), 29767 deletions(-) create mode 100644 hw/alpha/dp264.c create mode 100644 hw/alpha/pci.c delete mode 100644 hw/alpha_dp264.c delete mode 100644 hw/alpha_pci.c delete mode 100644 hw/an5206.c create mode 100644 hw/arm/boot.c create mode 100644 hw/arm/collie.c create mode 100644 hw/arm/exynos4_boards.c create mode 100644 hw/arm/gumstix.c create mode 100644 hw/arm/highbank.c create mode 100644 hw/arm/integratorcp.c create mode 100644 hw/arm/kzm.c create mode 100644 hw/arm/mainstone.c create mode 100644 hw/arm/musicpal.c create mode 100644 hw/arm/nseries.c create mode 100644 hw/arm/omap_sx1.c create mode 100644 hw/arm/palm.c create mode 100644 hw/arm/pic_cpu.c create mode 100644 hw/arm/realview.c create mode 100644 hw/arm/spitz.c create mode 100644 hw/arm/stellaris.c create mode 100644 hw/arm/tosa.c create mode 100644 hw/arm/versatilepb.c create mode 100644 hw/arm/vexpress.c create mode 100644 hw/arm/xilinx_zynq.c create mode 100644 hw/arm/z2.c delete mode 100644 hw/arm_boot.c delete mode 100644 hw/arm_pic.c delete mode 100644 hw/axis_dev88.c delete mode 100644 hw/collie.c delete mode 100644 hw/cris-boot.c create mode 100644 hw/cris/axis_dev88.c create mode 100644 hw/cris/boot.c create mode 100644 hw/cris/pic_cpu.c delete mode 100644 hw/cris_pic_cpu.c delete mode 100644 hw/dummy_m68k.c delete mode 100644 hw/exynos4_boards.c delete mode 100644 hw/gumstix.c delete mode 100644 hw/highbank.c create mode 100644 hw/i386/multiboot.c create mode 100644 hw/i386/pc.c create mode 100644 hw/i386/pc_piix.c create mode 100644 hw/i386/pc_q35.c create mode 100644 hw/i386/smbios.c create mode 100644 hw/i386/xen_domainbuild.c create mode 100644 hw/i386/xen_machine_pv.c delete mode 100644 hw/integratorcp.c delete mode 100644 hw/kzm.c delete mode 100644 hw/leon3.c create mode 100644 hw/lm32/lm32_boards.c create mode 100644 hw/lm32/milkymist.c delete mode 100644 hw/lm32_boards.c create mode 100644 hw/m68k/an5206.c create mode 100644 hw/m68k/dummy_m68k.c create mode 100644 hw/m68k/mcf5208.c delete mode 100644 hw/mainstone.c delete mode 100644 hw/mcf5208.c create mode 100644 hw/microblaze/boot.c create mode 100644 hw/microblaze/petalogix_ml605_mmu.c create mode 100644 hw/microblaze/petalogix_s3adsp1800_mmu.c create mode 100644 hw/microblaze/pic_cpu.c delete mode 100644 hw/microblaze_boot.c delete mode 100644 hw/microblaze_pic_cpu.c delete mode 100644 hw/milkymist.c create mode 100644 hw/mips/addr.c create mode 100644 hw/mips/cputimer.c create mode 100644 hw/mips/mips_fulong2e.c create mode 100644 hw/mips/mips_int.c create mode 100644 hw/mips/mips_jazz.c create mode 100644 hw/mips/mips_malta.c create mode 100644 hw/mips/mips_mipssim.c create mode 100644 hw/mips/mips_r4k.c delete mode 100644 hw/mips_addr.c delete mode 100644 hw/mips_fulong2e.c delete mode 100644 hw/mips_int.c delete mode 100644 hw/mips_jazz.c delete mode 100644 hw/mips_malta.c delete mode 100644 hw/mips_mipssim.c delete mode 100644 hw/mips_r4k.c delete mode 100644 hw/mips_timer.c delete mode 100644 hw/multiboot.c delete mode 100644 hw/musicpal.c delete mode 100644 hw/nseries.c delete mode 100644 hw/omap_sx1.c create mode 100644 hw/openrisc/cputimer.c create mode 100644 hw/openrisc/openrisc_sim.c create mode 100644 hw/openrisc/pic_cpu.c delete mode 100644 hw/openrisc_pic.c delete mode 100644 hw/openrisc_sim.c delete mode 100644 hw/openrisc_timer.c delete mode 100644 hw/palm.c delete mode 100644 hw/pc.c delete mode 100644 hw/pc_piix.c delete mode 100644 hw/pc_q35.c delete mode 100644 hw/petalogix_ml605_mmu.c delete mode 100644 hw/petalogix_s3adsp1800_mmu.c delete mode 100644 hw/ppc.c create mode 100644 hw/ppc/ppc.c create mode 100644 hw/ppc/ppc405_boards.c create mode 100644 hw/ppc/ppc405_uc.c create mode 100644 hw/ppc/ppc440_bamboo.c create mode 100644 hw/ppc/ppc_booke.c create mode 100644 hw/ppc/spapr.c create mode 100644 hw/ppc/virtex_ml507.c delete mode 100644 hw/ppc405_boards.c delete mode 100644 hw/ppc405_uc.c delete mode 100644 hw/ppc440_bamboo.c delete mode 100644 hw/ppc_booke.c delete mode 100644 hw/puv3.c delete mode 100644 hw/r2d.c delete mode 100644 hw/realview.c create mode 100644 hw/sh4/r2d.c create mode 100644 hw/sh4/shix.c delete mode 100644 hw/shix.c delete mode 100644 hw/smbios.c delete mode 100644 hw/spapr.c create mode 100644 hw/sparc/leon3.c create mode 100644 hw/sparc/sun4m.c create mode 100644 hw/sparc64/sun4u.c delete mode 100644 hw/spitz.c delete mode 100644 hw/stellaris.c delete mode 100644 hw/sun4m.c delete mode 100644 hw/sun4u.c delete mode 100644 hw/tosa.c create mode 100644 hw/unicore32/puv3.c delete mode 100644 hw/versatilepb.c delete mode 100644 hw/vexpress.c delete mode 100644 hw/virtex_ml507.c delete mode 100644 hw/xen_domainbuild.c delete mode 100644 hw/xen_machine_pv.c delete mode 100644 hw/xilinx_zynq.c create mode 100644 hw/xtensa/pic_cpu.c create mode 100644 hw/xtensa/xtensa_lx60.c create mode 100644 hw/xtensa/xtensa_sim.c delete mode 100644 hw/xtensa_lx60.c delete mode 100644 hw/xtensa_pic.c delete mode 100644 hw/xtensa_sim.c delete mode 100644 hw/z2.c diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 43f467a1ee..eb7eb31a19 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -206,7 +206,6 @@ obj-$(CONFIG_SOFTMMU) += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ obj-$(CONFIG_VGA) += vga.o -obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o # Inter-VM PCI shared memory & VFIO PCI device assignment ifeq ($(CONFIG_PCI), y) diff --git a/hw/alpha/Makefile.objs b/hw/alpha/Makefile.objs index af1c07fa7c..db868d2ea6 100644 --- a/hw/alpha/Makefile.objs +++ b/hw/alpha/Makefile.objs @@ -1,4 +1,6 @@ obj-y = mc146818rtc.o -obj-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o +obj-y += alpha_typhoon.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += dp264.o pci.o diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c new file mode 100644 index 0000000000..13aaa57b90 --- /dev/null +++ b/hw/alpha/dp264.c @@ -0,0 +1,182 @@ +/* + * QEMU Alpha DP264/CLIPPER hardware system emulator. + * + * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK + * variants because CLIPPER doesn't have an SMC669 SuperIO controller + * that we need to emulate as well. + */ + +#include "hw/hw.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/boards.h" +#include "hw/alpha_sys.h" +#include "sysemu/sysemu.h" +#include "hw/mc146818rtc.h" +#include "hw/ide.h" +#include "hw/i8254.h" +#include "hw/serial.h" + +#define MAX_IDE_BUS 2 + +static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) +{ + if (((addr >> 41) & 3) == 2) { + addr &= 0xffffffffffull; + } + return addr; +} + +/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems. + (0) The dev_irq_n lines into the cpu, which we totally ignore, + (1) The DRIR lines in the typhoon chipset, + (2) The "vector" aka mangled interrupt number reported by SRM PALcode, + (3) The interrupt number assigned by the kernel. + The following function is concerned with (1) only. */ + +static int clipper_pci_map_irq(PCIDevice *d, int irq_num) +{ + int slot = d->devfn >> 3; + + assert(irq_num >= 0 && irq_num <= 3); + + return (slot + 1) * 4 + irq_num; +} + +static void clipper_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + AlphaCPU *cpus[4]; + PCIBus *pci_bus; + ISABus *isa_bus; + qemu_irq rtc_irq; + long size, i; + const char *palcode_filename; + uint64_t palcode_entry, palcode_low, palcode_high; + uint64_t kernel_entry, kernel_low, kernel_high; + + /* Create up to 4 cpus. */ + memset(cpus, 0, sizeof(cpus)); + for (i = 0; i < smp_cpus; ++i) { + cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67"); + } + + cpus[0]->env.trap_arg0 = ram_size; + cpus[0]->env.trap_arg1 = 0; + cpus[0]->env.trap_arg2 = smp_cpus; + + /* Init the chipset. */ + pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, + clipper_pci_map_irq); + + rtc_init(isa_bus, 1980, rtc_irq); + pit_init(isa_bus, 0x40, 0, NULL); + isa_create_simple(isa_bus, "i8042"); + + /* VGA setup. Don't bother loading the bios. */ + pci_vga_init(pci_bus); + + /* Serial code setup. */ + for (i = 0; i < MAX_SERIAL_PORTS; ++i) { + if (serial_hds[i]) { + serial_isa_init(isa_bus, i, serial_hds[i]); + } + } + + /* Network setup. e1000 is good enough, failing Tulip support. */ + for (i = 0; i < nb_nics; i++) { + pci_nic_init_nofail(&nd_table[i], "e1000", NULL); + } + + /* IDE disk setup. */ + { + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + ide_drive_get(hd, MAX_IDE_BUS); + + pci_cmd646_ide_init(pci_bus, hd, 0); + } + + /* Load PALcode. Given that this is not "real" cpu palcode, + but one explicitly written for the emulation, we might as + well load it directly from and ELF image. */ + palcode_filename = (bios_name ? bios_name : "palcode-clipper"); + palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename); + if (palcode_filename == NULL) { + hw_error("no palcode provided\n"); + exit(1); + } + size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys, + NULL, &palcode_entry, &palcode_low, &palcode_high, + 0, EM_ALPHA, 0); + if (size < 0) { + hw_error("could not load palcode '%s'\n", palcode_filename); + exit(1); + } + + /* Start all cpus at the PALcode RESET entry point. */ + for (i = 0; i < smp_cpus; ++i) { + cpus[i]->env.pal_mode = 1; + cpus[i]->env.pc = palcode_entry; + cpus[i]->env.palbr = palcode_entry; + } + + /* Load a kernel. */ + if (kernel_filename) { + uint64_t param_offset; + + size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys, + NULL, &kernel_entry, &kernel_low, &kernel_high, + 0, EM_ALPHA, 0); + if (size < 0) { + hw_error("could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + cpus[0]->env.trap_arg1 = kernel_entry; + + param_offset = kernel_low - 0x6000; + + if (kernel_cmdline) { + pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline); + } + + if (initrd_filename) { + long initrd_base, initrd_size; + + initrd_size = get_image_size(initrd_filename); + if (initrd_size < 0) { + hw_error("could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + + /* Put the initrd image as high in memory as possible. */ + initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; + load_image_targphys(initrd_filename, initrd_base, + ram_size - initrd_base); + + stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL); + stq_phys(param_offset + 0x108, initrd_size); + } + } +} + +static QEMUMachine clipper_machine = { + .name = "clipper", + .desc = "Alpha DP264/CLIPPER", + .init = clipper_init, + .max_cpus = 4, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void clipper_machine_init(void) +{ + qemu_register_machine(&clipper_machine); +} + +machine_init(clipper_machine_init); diff --git a/hw/alpha/pci.c b/hw/alpha/pci.c new file mode 100644 index 0000000000..84628686ad --- /dev/null +++ b/hw/alpha/pci.c @@ -0,0 +1,109 @@ +/* + * QEMU Alpha PCI support functions. + * + * Some of this isn't very Alpha specific at all. + * + * ??? Sparse memory access not implemented. + */ + +#include "config.h" +#include "hw/alpha_sys.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" + + +/* PCI IO reads/writes, to byte-word addressable memory. */ +/* ??? Doesn't handle multiple PCI busses. */ + +static uint64_t bw_io_read(void *opaque, hwaddr addr, unsigned size) +{ + switch (size) { + case 1: + return cpu_inb(addr); + case 2: + return cpu_inw(addr); + case 4: + return cpu_inl(addr); + } + abort(); +} + +static void bw_io_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + switch (size) { + case 1: + cpu_outb(addr, val); + break; + case 2: + cpu_outw(addr, val); + break; + case 4: + cpu_outl(addr, val); + break; + default: + abort(); + } +} + +const MemoryRegionOps alpha_pci_bw_io_ops = { + .read = bw_io_read, + .write = bw_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +/* PCI config space reads/writes, to byte-word addressable memory. */ +static uint64_t bw_conf1_read(void *opaque, hwaddr addr, + unsigned size) +{ + PCIBus *b = opaque; + return pci_data_read(b, addr, size); +} + +static void bw_conf1_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PCIBus *b = opaque; + pci_data_write(b, addr, val, size); +} + +const MemoryRegionOps alpha_pci_conf1_ops = { + .read = bw_conf1_read, + .write = bw_conf1_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +/* PCI/EISA Interrupt Acknowledge Cycle. */ + +static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size) +{ + return pic_read_irq(isa_pic); +} + +static void special_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + qemu_log("pci: special write cycle"); +} + +const MemoryRegionOps alpha_pci_iack_ops = { + .read = iack_read, + .write = special_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c deleted file mode 100644 index 13aaa57b90..0000000000 --- a/hw/alpha_dp264.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * QEMU Alpha DP264/CLIPPER hardware system emulator. - * - * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK - * variants because CLIPPER doesn't have an SMC669 SuperIO controller - * that we need to emulate as well. - */ - -#include "hw/hw.h" -#include "elf.h" -#include "hw/loader.h" -#include "hw/boards.h" -#include "hw/alpha_sys.h" -#include "sysemu/sysemu.h" -#include "hw/mc146818rtc.h" -#include "hw/ide.h" -#include "hw/i8254.h" -#include "hw/serial.h" - -#define MAX_IDE_BUS 2 - -static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) -{ - if (((addr >> 41) & 3) == 2) { - addr &= 0xffffffffffull; - } - return addr; -} - -/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems. - (0) The dev_irq_n lines into the cpu, which we totally ignore, - (1) The DRIR lines in the typhoon chipset, - (2) The "vector" aka mangled interrupt number reported by SRM PALcode, - (3) The interrupt number assigned by the kernel. - The following function is concerned with (1) only. */ - -static int clipper_pci_map_irq(PCIDevice *d, int irq_num) -{ - int slot = d->devfn >> 3; - - assert(irq_num >= 0 && irq_num <= 3); - - return (slot + 1) * 4 + irq_num; -} - -static void clipper_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - AlphaCPU *cpus[4]; - PCIBus *pci_bus; - ISABus *isa_bus; - qemu_irq rtc_irq; - long size, i; - const char *palcode_filename; - uint64_t palcode_entry, palcode_low, palcode_high; - uint64_t kernel_entry, kernel_low, kernel_high; - - /* Create up to 4 cpus. */ - memset(cpus, 0, sizeof(cpus)); - for (i = 0; i < smp_cpus; ++i) { - cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67"); - } - - cpus[0]->env.trap_arg0 = ram_size; - cpus[0]->env.trap_arg1 = 0; - cpus[0]->env.trap_arg2 = smp_cpus; - - /* Init the chipset. */ - pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, - clipper_pci_map_irq); - - rtc_init(isa_bus, 1980, rtc_irq); - pit_init(isa_bus, 0x40, 0, NULL); - isa_create_simple(isa_bus, "i8042"); - - /* VGA setup. Don't bother loading the bios. */ - pci_vga_init(pci_bus); - - /* Serial code setup. */ - for (i = 0; i < MAX_SERIAL_PORTS; ++i) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - - /* Network setup. e1000 is good enough, failing Tulip support. */ - for (i = 0; i < nb_nics; i++) { - pci_nic_init_nofail(&nd_table[i], "e1000", NULL); - } - - /* IDE disk setup. */ - { - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - ide_drive_get(hd, MAX_IDE_BUS); - - pci_cmd646_ide_init(pci_bus, hd, 0); - } - - /* Load PALcode. Given that this is not "real" cpu palcode, - but one explicitly written for the emulation, we might as - well load it directly from and ELF image. */ - palcode_filename = (bios_name ? bios_name : "palcode-clipper"); - palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename); - if (palcode_filename == NULL) { - hw_error("no palcode provided\n"); - exit(1); - } - size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys, - NULL, &palcode_entry, &palcode_low, &palcode_high, - 0, EM_ALPHA, 0); - if (size < 0) { - hw_error("could not load palcode '%s'\n", palcode_filename); - exit(1); - } - - /* Start all cpus at the PALcode RESET entry point. */ - for (i = 0; i < smp_cpus; ++i) { - cpus[i]->env.pal_mode = 1; - cpus[i]->env.pc = palcode_entry; - cpus[i]->env.palbr = palcode_entry; - } - - /* Load a kernel. */ - if (kernel_filename) { - uint64_t param_offset; - - size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys, - NULL, &kernel_entry, &kernel_low, &kernel_high, - 0, EM_ALPHA, 0); - if (size < 0) { - hw_error("could not load kernel '%s'\n", kernel_filename); - exit(1); - } - - cpus[0]->env.trap_arg1 = kernel_entry; - - param_offset = kernel_low - 0x6000; - - if (kernel_cmdline) { - pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline); - } - - if (initrd_filename) { - long initrd_base, initrd_size; - - initrd_size = get_image_size(initrd_filename); - if (initrd_size < 0) { - hw_error("could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - - /* Put the initrd image as high in memory as possible. */ - initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; - load_image_targphys(initrd_filename, initrd_base, - ram_size - initrd_base); - - stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL); - stq_phys(param_offset + 0x108, initrd_size); - } - } -} - -static QEMUMachine clipper_machine = { - .name = "clipper", - .desc = "Alpha DP264/CLIPPER", - .init = clipper_init, - .max_cpus = 4, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void clipper_machine_init(void) -{ - qemu_register_machine(&clipper_machine); -} - -machine_init(clipper_machine_init); diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c deleted file mode 100644 index 84628686ad..0000000000 --- a/hw/alpha_pci.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * QEMU Alpha PCI support functions. - * - * Some of this isn't very Alpha specific at all. - * - * ??? Sparse memory access not implemented. - */ - -#include "config.h" -#include "hw/alpha_sys.h" -#include "qemu/log.h" -#include "sysemu/sysemu.h" - - -/* PCI IO reads/writes, to byte-word addressable memory. */ -/* ??? Doesn't handle multiple PCI busses. */ - -static uint64_t bw_io_read(void *opaque, hwaddr addr, unsigned size) -{ - switch (size) { - case 1: - return cpu_inb(addr); - case 2: - return cpu_inw(addr); - case 4: - return cpu_inl(addr); - } - abort(); -} - -static void bw_io_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - switch (size) { - case 1: - cpu_outb(addr, val); - break; - case 2: - cpu_outw(addr, val); - break; - case 4: - cpu_outl(addr, val); - break; - default: - abort(); - } -} - -const MemoryRegionOps alpha_pci_bw_io_ops = { - .read = bw_io_read, - .write = bw_io_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -/* PCI config space reads/writes, to byte-word addressable memory. */ -static uint64_t bw_conf1_read(void *opaque, hwaddr addr, - unsigned size) -{ - PCIBus *b = opaque; - return pci_data_read(b, addr, size); -} - -static void bw_conf1_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - PCIBus *b = opaque; - pci_data_write(b, addr, val, size); -} - -const MemoryRegionOps alpha_pci_conf1_ops = { - .read = bw_conf1_read, - .write = bw_conf1_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -/* PCI/EISA Interrupt Acknowledge Cycle. */ - -static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size) -{ - return pic_read_irq(isa_pic); -} - -static void special_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - qemu_log("pci: special write cycle"); -} - -const MemoryRegionOps alpha_pci_iack_ops = { - .read = iack_read, - .write = special_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; diff --git a/hw/an5206.c b/hw/an5206.c deleted file mode 100644 index 7c21c66cde..0000000000 --- a/hw/an5206.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Arnewsh 5206 ColdFire system emulation. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ - -#include "hw/hw.h" -#include "hw/mcf.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "exec/address-spaces.h" - -#define KERNEL_LOAD_ADDR 0x10000 -#define AN5206_MBAR_ADDR 0x10000000 -#define AN5206_RAMBAR_ADDR 0x20000000 - -/* Board init. */ - -static void an5206_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - M68kCPU *cpu; - CPUM68KState *env; - int kernel_size; - uint64_t elf_entry; - hwaddr entry; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - - if (!cpu_model) { - cpu_model = "m5206"; - } - cpu = cpu_m68k_init(cpu_model); - if (!cpu) { - hw_error("Unable to find m68k CPU definition\n"); - } - env = &cpu->env; - - /* Initialize CPU registers. */ - env->vbr = 0; - /* TODO: allow changing MBAR and RAMBAR. */ - env->mbar = AN5206_MBAR_ADDR | 1; - env->rambar0 = AN5206_RAMBAR_ADDR | 1; - - /* DRAM at address zero */ - memory_region_init_ram(ram, "an5206.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space_mem, 0, ram); - - /* Internal SRAM. */ - memory_region_init_ram(sram, "an5206.sram", 512); - vmstate_register_ram_global(sram); - memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram); - - mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, cpu); - - /* Load kernel. */ - if (!kernel_filename) { - fprintf(stderr, "Kernel image must be specified\n"); - exit(1); - } - - kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, - NULL, NULL, 1, ELF_MACHINE, 0); - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); - } - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, - ram_size - KERNEL_LOAD_ADDR); - entry = KERNEL_LOAD_ADDR; - } - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } - - env->pc = entry; -} - -static QEMUMachine an5206_machine = { - .name = "an5206", - .desc = "Arnewsh 5206", - .init = an5206_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void an5206_machine_init(void) -{ - qemu_register_machine(&an5206_machine); -} - -machine_init(an5206_machine_init); diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 3eb1366aee..c09cc3aae8 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -1,35 +1,32 @@ -obj-y = integratorcp.o versatilepb.o arm_pic.o -obj-y += arm_boot.o -obj-y += xilinx_zynq.o zynq_slcr.o +obj-y += zynq_slcr.o obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += a9scu.o -obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o +obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o -obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o +obj-y += exynos4210_uart.o exynos4210_pwm.o obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o obj-y += exynos4210_rtc.o exynos4210_i2c.o obj-y += arm_mptimer.o a15mpcore.o -obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o -obj-y += highbank.o +obj-y += armv7m.o armv7m_nvic.o stellaris_enet.o obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o -obj-y += gumstix.o -obj-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o +obj-y += zaurus.o ide/microdrive.o tc6393xb.o obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ omap_gpio.o omap_intc.o omap_uart.o obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o -obj-y += omap_sx1.o palm.o tsc210x.o -obj-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o -obj-y += mst_fpga.o mainstone.o -obj-y += z2.o -obj-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o +obj-y += tsc210x.o +obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o +obj-y += mst_fpga.o +obj-y += bitbang_i2c.o marvell_88w8618_audio.o obj-y += framebuffer.o -obj-y += vexpress.o obj-y += strongarm.o -obj-y += collie.o obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o -obj-y += kzm.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o +obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o +obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o +obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o diff --git a/hw/arm/boot.c b/hw/arm/boot.c new file mode 100644 index 0000000000..43253fd34a --- /dev/null +++ b/hw/arm/boot.c @@ -0,0 +1,480 @@ +/* + * ARM kernel loader. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL. + */ + +#include "config.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "sysemu/device_tree.h" +#include "qemu/config-file.h" + +#define KERNEL_ARGS_ADDR 0x100 +#define KERNEL_LOAD_ADDR 0x00010000 + +/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ +static uint32_t bootloader[] = { + 0xe3a00000, /* mov r0, #0 */ + 0xe59f1004, /* ldr r1, [pc, #4] */ + 0xe59f2004, /* ldr r2, [pc, #4] */ + 0xe59ff004, /* ldr pc, [pc, #4] */ + 0, /* Board ID */ + 0, /* Address of kernel args. Set by integratorcp_init. */ + 0 /* Kernel entry point. Set by integratorcp_init. */ +}; + +/* Handling for secondary CPU boot in a multicore system. + * Unlike the uniprocessor/primary CPU boot, this is platform + * dependent. The default code here is based on the secondary + * CPU boot protocol used on realview/vexpress boards, with + * some parameterisation to increase its flexibility. + * QEMU platform models for which this code is not appropriate + * should override write_secondary_boot and secondary_cpu_reset_hook + * instead. + * + * This code enables the interrupt controllers for the secondary + * CPUs and then puts all the secondary CPUs into a loop waiting + * for an interprocessor interrupt and polling a configurable + * location for the kernel secondary CPU entry point. + */ +#define DSB_INSN 0xf57ff04f +#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */ + +static uint32_t smpboot[] = { + 0xe59f2028, /* ldr r2, gic_cpu_if */ + 0xe59f0028, /* ldr r0, startaddr */ + 0xe3a01001, /* mov r1, #1 */ + 0xe5821000, /* str r1, [r2] - set GICC_CTLR.Enable */ + 0xe3a010ff, /* mov r1, #0xff */ + 0xe5821004, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */ + DSB_INSN, /* dsb */ + 0xe320f003, /* wfi */ + 0xe5901000, /* ldr r1, [r0] */ + 0xe1110001, /* tst r1, r1 */ + 0x0afffffb, /* beq */ + 0xe12fff11, /* bx r1 */ + 0, /* gic_cpu_if: base address of GIC CPU interface */ + 0 /* bootreg: Boot register address is held here */ +}; + +static void default_write_secondary(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + int n; + smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; + smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + /* Replace DSB with the pre-v7 DSB if necessary. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_V7) && + smpboot[n] == DSB_INSN) { + smpboot[n] = CP15_DSB_INSN; + } + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start); +} + +static void default_reset_secondary(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + CPUARMState *env = &cpu->env; + + stl_phys_notdirty(info->smp_bootreg_addr, 0); + env->regs[15] = info->smp_loader_start; +} + +#define WRITE_WORD(p, value) do { \ + stl_phys_notdirty(p, value); \ + p += 4; \ +} while (0) + +static void set_kernel_args(const struct arm_boot_info *info) +{ + int initrd_size = info->initrd_size; + hwaddr base = info->loader_start; + hwaddr p; + + p = base + KERNEL_ARGS_ADDR; + /* ATAG_CORE */ + WRITE_WORD(p, 5); + WRITE_WORD(p, 0x54410001); + WRITE_WORD(p, 1); + WRITE_WORD(p, 0x1000); + WRITE_WORD(p, 0); + /* ATAG_MEM */ + /* TODO: handle multiple chips on one ATAG list */ + WRITE_WORD(p, 4); + WRITE_WORD(p, 0x54410002); + WRITE_WORD(p, info->ram_size); + WRITE_WORD(p, info->loader_start); + if (initrd_size) { + /* ATAG_INITRD2 */ + WRITE_WORD(p, 4); + WRITE_WORD(p, 0x54420005); + WRITE_WORD(p, info->initrd_start); + WRITE_WORD(p, initrd_size); + } + if (info->kernel_cmdline && *info->kernel_cmdline) { + /* ATAG_CMDLINE */ + int cmdline_size; + + cmdline_size = strlen(info->kernel_cmdline); + cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline, + cmdline_size + 1); + cmdline_size = (cmdline_size >> 2) + 1; + WRITE_WORD(p, cmdline_size + 2); + WRITE_WORD(p, 0x54410009); + p += cmdline_size * 4; + } + if (info->atag_board) { + /* ATAG_BOARD */ + int atag_board_len; + uint8_t atag_board_buf[0x1000]; + + atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3; + WRITE_WORD(p, (atag_board_len + 8) >> 2); + WRITE_WORD(p, 0x414f4d50); + cpu_physical_memory_write(p, atag_board_buf, atag_board_len); + p += atag_board_len; + } + /* ATAG_END */ + WRITE_WORD(p, 0); + WRITE_WORD(p, 0); +} + +static void set_kernel_args_old(const struct arm_boot_info *info) +{ + hwaddr p; + const char *s; + int initrd_size = info->initrd_size; + hwaddr base = info->loader_start; + + /* see linux/include/asm-arm/setup.h */ + p = base + KERNEL_ARGS_ADDR; + /* page_size */ + WRITE_WORD(p, 4096); + /* nr_pages */ + WRITE_WORD(p, info->ram_size / 4096); + /* ramdisk_size */ + WRITE_WORD(p, 0); +#define FLAG_READONLY 1 +#define FLAG_RDLOAD 4 +#define FLAG_RDPROMPT 8 + /* flags */ + WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT); + /* rootdev */ + WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */ + /* video_num_cols */ + WRITE_WORD(p, 0); + /* video_num_rows */ + WRITE_WORD(p, 0); + /* video_x */ + WRITE_WORD(p, 0); + /* video_y */ + WRITE_WORD(p, 0); + /* memc_control_reg */ + WRITE_WORD(p, 0); + /* unsigned char sounddefault */ + /* unsigned char adfsdrives */ + /* unsigned char bytes_per_char_h */ + /* unsigned char bytes_per_char_v */ + WRITE_WORD(p, 0); + /* pages_in_bank[4] */ + WRITE_WORD(p, 0); + WRITE_WORD(p, 0); + WRITE_WORD(p, 0); + WRITE_WORD(p, 0); + /* pages_in_vram */ + WRITE_WORD(p, 0); + /* initrd_start */ + if (initrd_size) { + WRITE_WORD(p, info->initrd_start); + } else { + WRITE_WORD(p, 0); + } + /* initrd_size */ + WRITE_WORD(p, initrd_size); + /* rd_start */ + WRITE_WORD(p, 0); + /* system_rev */ + WRITE_WORD(p, 0); + /* system_serial_low */ + WRITE_WORD(p, 0); + /* system_serial_high */ + WRITE_WORD(p, 0); + /* mem_fclk_21285 */ + WRITE_WORD(p, 0); + /* zero unused fields */ + while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) { + WRITE_WORD(p, 0); + } + s = info->kernel_cmdline; + if (s) { + cpu_physical_memory_write(p, (void *)s, strlen(s) + 1); + } else { + WRITE_WORD(p, 0); + } +} + +static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) +{ +#ifdef CONFIG_FDT + uint32_t *mem_reg_property; + uint32_t mem_reg_propsize; + void *fdt = NULL; + char *filename; + int size, rc; + uint32_t acells, scells, hival; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename); + if (!filename) { + fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename); + return -1; + } + + fdt = load_device_tree(filename, &size); + if (!fdt) { + fprintf(stderr, "Couldn't open dtb file %s\n", filename); + g_free(filename); + return -1; + } + g_free(filename); + + acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells"); + scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells"); + if (acells == 0 || scells == 0) { + fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n"); + return -1; + } + + mem_reg_propsize = acells + scells; + mem_reg_property = g_new0(uint32_t, mem_reg_propsize); + mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start); + hival = cpu_to_be32(binfo->loader_start >> 32); + if (acells > 1) { + mem_reg_property[acells - 2] = hival; + } else if (hival != 0) { + fprintf(stderr, "qemu: dtb file not compatible with " + "RAM start address > 4GB\n"); + exit(1); + } + mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size); + hival = cpu_to_be32(binfo->ram_size >> 32); + if (scells > 1) { + mem_reg_property[acells + scells - 2] = hival; + } else if (hival != 0) { + fprintf(stderr, "qemu: dtb file not compatible with " + "RAM size > 4GB\n"); + exit(1); + } + + rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, + mem_reg_propsize * sizeof(uint32_t)); + if (rc < 0) { + fprintf(stderr, "couldn't set /memory/reg\n"); + } + + if (binfo->kernel_cmdline && *binfo->kernel_cmdline) { + rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", + binfo->kernel_cmdline); + if (rc < 0) { + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + } + } + + if (binfo->initrd_size) { + rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", + binfo->initrd_start); + if (rc < 0) { + fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); + } + + rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", + binfo->initrd_start + binfo->initrd_size); + if (rc < 0) { + fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); + } + } + + cpu_physical_memory_write(addr, fdt, size); + + return 0; + +#else + fprintf(stderr, "Device tree requested, " + "but qemu was compiled without fdt support\n"); + return -1; +#endif +} + +static void do_cpu_reset(void *opaque) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + const struct arm_boot_info *info = env->boot_info; + + cpu_reset(CPU(cpu)); + if (info) { + if (!info->is_linux) { + /* Jump to the entry point. */ + env->regs[15] = info->entry & 0xfffffffe; + env->thumb = info->entry & 1; + } else { + if (env == first_cpu) { + env->regs[15] = info->loader_start; + if (!info->dtb_filename) { + if (old_param) { + set_kernel_args_old(info); + } else { + set_kernel_args(info); + } + } + } else { + info->secondary_cpu_reset_hook(cpu, info); + } + } + } +} + +void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) +{ + CPUARMState *env = &cpu->env; + int kernel_size; + int initrd_size; + int n; + int is_linux = 0; + uint64_t elf_entry; + hwaddr entry; + int big_endian; + QemuOpts *machine_opts; + + /* Load the kernel. */ + if (!info->kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + info->dtb_filename = qemu_opt_get(machine_opts, "dtb"); + } else { + info->dtb_filename = NULL; + } + + if (!info->secondary_cpu_reset_hook) { + info->secondary_cpu_reset_hook = default_reset_secondary; + } + if (!info->write_secondary_boot) { + info->write_secondary_boot = default_write_secondary; + } + + if (info->nb_cpus == 0) + info->nb_cpus = 1; + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + + /* We want to put the initrd far enough into RAM that when the + * kernel is uncompressed it will not clobber the initrd. However + * on boards without much RAM we must ensure that we still leave + * enough room for a decent sized initrd, and on boards with large + * amounts of RAM we must avoid the initrd being so far up in RAM + * that it is outside lowmem and inaccessible to the kernel. + * So for boards with less than 256MB of RAM we put the initrd + * halfway into RAM, and for boards with 256MB of RAM or more we put + * the initrd at 128MB. + */ + info->initrd_start = info->loader_start + + MIN(info->ram_size / 2, 128 * 1024 * 1024); + + /* Assume that raw images are linux kernels, and ELF images are not. */ + kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry, + NULL, NULL, big_endian, ELF_MACHINE, 1); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(info->kernel_filename, &entry, NULL, + &is_linux); + } + if (kernel_size < 0) { + entry = info->loader_start + KERNEL_LOAD_ADDR; + kernel_size = load_image_targphys(info->kernel_filename, entry, + info->ram_size - KERNEL_LOAD_ADDR); + is_linux = 1; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + info->kernel_filename); + exit(1); + } + info->entry = entry; + if (is_linux) { + if (info->initrd_filename) { + initrd_size = load_image_targphys(info->initrd_filename, + info->initrd_start, + info->ram_size - + info->initrd_start); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", + info->initrd_filename); + exit(1); + } + } else { + initrd_size = 0; + } + info->initrd_size = initrd_size; + + bootloader[4] = info->board_id; + + /* for device tree boot, we pass the DTB directly in r2. Otherwise + * we point to the kernel args. + */ + if (info->dtb_filename) { + /* Place the DTB after the initrd in memory. Note that some + * kernels will trash anything in the 4K page the initrd + * ends in, so make sure the DTB isn't caught up in that. + */ + hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, + 4096); + if (load_dtb(dtb_start, info)) { + exit(1); + } + bootloader[5] = dtb_start; + } else { + bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; + if (info->ram_size >= (1ULL << 32)) { + fprintf(stderr, "qemu: RAM size must be less than 4GB to boot" + " Linux kernel using ATAGS (try passing a device tree" + " using -dtb)\n"); + exit(1); + } + } + bootloader[6] = entry; + for (n = 0; n < sizeof(bootloader) / 4; n++) { + bootloader[n] = tswap32(bootloader[n]); + } + rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader), + info->loader_start); + if (info->nb_cpus > 1) { + info->write_secondary_boot(cpu, info); + } + } + info->is_linux = is_linux; + + for (; env; env = env->next_cpu) { + cpu = arm_env_get_cpu(env); + env->boot_info = info; + qemu_register_reset(do_cpu_reset, cpu); + } +} diff --git a/hw/arm/collie.c b/hw/arm/collie.c new file mode 100644 index 0000000000..17fddc8d5b --- /dev/null +++ b/hw/arm/collie.c @@ -0,0 +1,73 @@ +/* + * SA-1110-based Sharp Zaurus SL-5500 platform. + * + * Copyright (C) 2011 Dmitry Eremin-Solenikov + * + * This code is licensed under GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/devices.h" +#include "hw/strongarm.h" +#include "hw/arm-misc.h" +#include "hw/flash.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +static struct arm_boot_info collie_binfo = { + .loader_start = SA_SDCS0, + .ram_size = 0x20000000, +}; + +static void collie_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + StrongARMState *s; + DriveInfo *dinfo; + MemoryRegion *sysmem = get_system_memory(); + + if (!cpu_model) { + cpu_model = "sa1110"; + } + + s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model); + + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + + dinfo = drive_get(IF_PFLASH, 0, 1); + pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + + sysbus_create_simple("scoop", 0x40800000, NULL); + + collie_binfo.kernel_filename = kernel_filename; + collie_binfo.kernel_cmdline = kernel_cmdline; + collie_binfo.initrd_filename = initrd_filename; + collie_binfo.board_id = 0x208; + arm_load_kernel(s->cpu, &collie_binfo); +} + +static QEMUMachine collie_machine = { + .name = "collie", + .desc = "Collie PDA (SA-1110)", + .init = collie_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void collie_machine_init(void) +{ + qemu_register_machine(&collie_machine); +} + +machine_init(collie_machine_init) diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c new file mode 100644 index 0000000000..473da349bd --- /dev/null +++ b/hw/arm/exynos4_boards.c @@ -0,0 +1,170 @@ +/* + * Samsung exynos4 SoC based boards emulation + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. + * Maksim Kozlov + * Evgeny Voevodin + * Igor Mitsyanko + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "net/net.h" +#include "hw/arm-misc.h" +#include "exec/address-spaces.h" +#include "hw/exynos4210.h" +#include "hw/boards.h" + +#undef DEBUG + +//#define DEBUG + +#ifdef DEBUG + #undef PRINT_DEBUG + #define PRINT_DEBUG(fmt, args...) \ + do { \ + fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ + } while (0) +#else + #define PRINT_DEBUG(fmt, args...) do {} while (0) +#endif + +#define SMDK_LAN9118_BASE_ADDR 0x05000000 + +typedef enum Exynos4BoardType { + EXYNOS4_BOARD_NURI, + EXYNOS4_BOARD_SMDKC210, + EXYNOS4_NUM_OF_BOARDS +} Exynos4BoardType; + +static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = { + [EXYNOS4_BOARD_NURI] = 0xD33, + [EXYNOS4_BOARD_SMDKC210] = 0xB16, +}; + +static int exynos4_board_smp_bootreg_addr[EXYNOS4_NUM_OF_BOARDS] = { + [EXYNOS4_BOARD_NURI] = EXYNOS4210_SECOND_CPU_BOOTREG, + [EXYNOS4_BOARD_SMDKC210] = EXYNOS4210_SECOND_CPU_BOOTREG, +}; + +static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = { + [EXYNOS4_BOARD_NURI] = 0x40000000, + [EXYNOS4_BOARD_SMDKC210] = 0x40000000, +}; + +static struct arm_boot_info exynos4_board_binfo = { + .loader_start = EXYNOS4210_BASE_BOOT_ADDR, + .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR, + .nb_cpus = EXYNOS4210_NCPUS, + .write_secondary_boot = exynos4210_write_secondary, +}; + +static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS]; + +static void lan9215_init(uint32_t base, qemu_irq irq) +{ + DeviceState *dev; + SysBusDevice *s; + + /* This should be a 9215 but the 9118 is close enough */ + if (nd_table[0].used) { + qemu_check_nic_model(&nd_table[0], "lan9118"); + dev = qdev_create(NULL, "lan9118"); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_prop_set_uint32(dev, "mode_16bit", 1); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(s, 0, base); + sysbus_connect_irq(s, 0, irq); + } +} + +static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, + Exynos4BoardType board_type) +{ + if (smp_cpus != EXYNOS4210_NCPUS) { + fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus" + " value.\n", + exynos4_machines[board_type].name, + exynos4_machines[board_type].max_cpus); + } + + exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type]; + exynos4_board_binfo.board_id = exynos4_board_id[board_type]; + exynos4_board_binfo.smp_bootreg_addr = + exynos4_board_smp_bootreg_addr[board_type]; + exynos4_board_binfo.kernel_filename = args->kernel_filename; + exynos4_board_binfo.initrd_filename = args->initrd_filename; + exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline; + exynos4_board_binfo.gic_cpu_if_addr = + EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; + + PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n" + " kernel_filename: %s\n" + " kernel_cmdline: %s\n" + " initrd_filename: %s\n", + exynos4_board_ram_size[board_type] / 1048576, + exynos4_board_ram_size[board_type], + args->kernel_filename, + args->kernel_cmdline, + args->initrd_filename); + + return exynos4210_init(get_system_memory(), + exynos4_board_ram_size[board_type]); +} + +static void nuri_init(QEMUMachineInitArgs *args) +{ + exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI); + + arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); +} + +static void smdkc210_init(QEMUMachineInitArgs *args) +{ + Exynos4210State *s = exynos4_boards_init_common(args, + EXYNOS4_BOARD_SMDKC210); + + lan9215_init(SMDK_LAN9118_BASE_ADDR, + qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); + arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); +} + +static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = { + [EXYNOS4_BOARD_NURI] = { + .name = "nuri", + .desc = "Samsung NURI board (Exynos4210)", + .init = nuri_init, + .max_cpus = EXYNOS4210_NCPUS, + DEFAULT_MACHINE_OPTIONS, + }, + [EXYNOS4_BOARD_SMDKC210] = { + .name = "smdkc210", + .desc = "Samsung SMDKC210 board (Exynos4210)", + .init = smdkc210_init, + .max_cpus = EXYNOS4210_NCPUS, + DEFAULT_MACHINE_OPTIONS, + }, +}; + +static void exynos4_machine_init(void) +{ + qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_NURI]); + qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_SMDKC210]); +} + +machine_init(exynos4_machine_init); diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c new file mode 100644 index 0000000000..8859b7392f --- /dev/null +++ b/hw/arm/gumstix.c @@ -0,0 +1,141 @@ +/* + * Gumstix Platforms + * + * Copyright (c) 2007 by Thorsten Zitterell + * + * Code based on spitz platform by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +/* + * Example usage: + * + * connex: + * ======= + * create image: + * # dd of=flash bs=1k count=16k if=/dev/zero + * # dd of=flash bs=1k conv=notrunc if=u-boot.bin + * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 + * start it: + * # qemu-system-arm -M connex -pflash flash -monitor null -nographic + * + * verdex: + * ======= + * create image: + * # dd of=flash bs=1k count=32k if=/dev/zero + * # dd of=flash bs=1k conv=notrunc if=u-boot.bin + * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 + * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage + * start it: + * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289 + */ + +#include "hw/hw.h" +#include "hw/pxa.h" +#include "net/net.h" +#include "hw/flash.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +static const int sector_len = 128 * 1024; + +static void connex_init(QEMUMachineInitArgs *args) +{ + PXA2xxState *cpu; + DriveInfo *dinfo; + int be; + MemoryRegion *address_space_mem = get_system_memory(); + + uint32_t connex_rom = 0x01000000; + uint32_t connex_ram = 0x04000000; + + cpu = pxa255_init(address_space_mem, connex_ram); + + dinfo = drive_get(IF_PFLASH, 0, 0); + if (!dinfo) { + fprintf(stderr, "A flash image must be given with the " + "'pflash' parameter\n"); + exit(1); + } + +#ifdef TARGET_WORDS_BIGENDIAN + be = 1; +#else + be = 0; +#endif + if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom, + dinfo->bdrv, sector_len, connex_rom / sector_len, + 2, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + exit(1); + } + + /* Interrupt line of NIC is connected to GPIO line 36 */ + smc91c111_init(&nd_table[0], 0x04000300, + qdev_get_gpio_in(cpu->gpio, 36)); +} + +static void verdex_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + PXA2xxState *cpu; + DriveInfo *dinfo; + int be; + MemoryRegion *address_space_mem = get_system_memory(); + + uint32_t verdex_rom = 0x02000000; + uint32_t verdex_ram = 0x10000000; + + cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0"); + + dinfo = drive_get(IF_PFLASH, 0, 0); + if (!dinfo) { + fprintf(stderr, "A flash image must be given with the " + "'pflash' parameter\n"); + exit(1); + } + +#ifdef TARGET_WORDS_BIGENDIAN + be = 1; +#else + be = 0; +#endif + if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom, + dinfo->bdrv, sector_len, verdex_rom / sector_len, + 2, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + exit(1); + } + + /* Interrupt line of NIC is connected to GPIO line 99 */ + smc91c111_init(&nd_table[0], 0x04000300, + qdev_get_gpio_in(cpu->gpio, 99)); +} + +static QEMUMachine connex_machine = { + .name = "connex", + .desc = "Gumstix Connex (PXA255)", + .init = connex_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine verdex_machine = { + .name = "verdex", + .desc = "Gumstix Verdex (PXA270)", + .init = verdex_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void gumstix_machine_init(void) +{ + qemu_register_machine(&connex_machine); + qemu_register_machine(&verdex_machine); +} + +machine_init(gumstix_machine_init); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c new file mode 100644 index 0000000000..a622224dcc --- /dev/null +++ b/hw/arm/highbank.c @@ -0,0 +1,342 @@ +/* + * Calxeda Highbank SoC emulation + * + * Copyright (c) 2010-2012 Calxeda + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + */ + +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/loader.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/sysbus.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#define SMP_BOOT_ADDR 0x100 +#define SMP_BOOT_REG 0x40 +#define GIC_BASE_ADDR 0xfff10000 + +#define NIRQ_GIC 160 + +/* Board init. */ + +static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) +{ + int n; + uint32_t smpboot[] = { + 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */ + 0xe210000f, /* ands r0, r0, #0x0f */ + 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */ + 0xe0830200, /* add r0, r3, r0, lsl #4 */ + 0xe59f2024, /* ldr r2, privbase */ + 0xe3a01001, /* mov r1, #1 */ + 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */ + 0xe3a010ff, /* mov r1, #0xff */ + 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */ + 0xf57ff04f, /* dsb */ + 0xe320f003, /* wfi */ + 0xe5901000, /* ldr r1, [r0] */ + 0xe1110001, /* tst r1, r1 */ + 0x0afffffb, /* beq */ + 0xe12fff11, /* bx r1 */ + GIC_BASE_ADDR /* privbase: gic address. */ + }; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); +} + +static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) +{ + CPUARMState *env = &cpu->env; + + switch (info->nb_cpus) { + case 4: + stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0); + case 3: + stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0); + case 2: + stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0); + env->regs[15] = SMP_BOOT_ADDR; + break; + default: + break; + } +} + +#define NUM_REGS 0x200 +static void hb_regs_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + uint32_t *regs = opaque; + + if (offset == 0xf00) { + if (value == 1 || value == 2) { + qemu_system_reset_request(); + } else if (value == 3) { + qemu_system_shutdown_request(); + } + } + + regs[offset/4] = value; +} + +static uint64_t hb_regs_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint32_t *regs = opaque; + uint32_t value = regs[offset/4]; + + if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) { + value |= 0x30000000; + } + + return value; +} + +static const MemoryRegionOps hb_mem_ops = { + .read = hb_regs_read, + .write = hb_regs_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +typedef struct { + SysBusDevice busdev; + MemoryRegion *iomem; + uint32_t regs[NUM_REGS]; +} HighbankRegsState; + +static VMStateDescription vmstate_highbank_regs = { + .name = "highbank-regs", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + +static void highbank_regs_reset(DeviceState *dev) +{ + SysBusDevice *sys_dev = SYS_BUS_DEVICE(dev); + HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev); + + s->regs[0x40] = 0x05F20121; + s->regs[0x41] = 0x2; + s->regs[0x42] = 0x05F30121; + s->regs[0x43] = 0x05F40121; +} + +static int highbank_regs_init(SysBusDevice *dev) +{ + HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev); + + s->iomem = g_new(MemoryRegion, 1); + memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs", + 0x1000); + sysbus_init_mmio(dev, s->iomem); + + return 0; +} + +static void highbank_regs_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + sbc->init = highbank_regs_init; + dc->desc = "Calxeda Highbank registers"; + dc->vmsd = &vmstate_highbank_regs; + dc->reset = highbank_regs_reset; +} + +static const TypeInfo highbank_regs_info = { + .name = "highbank-regs", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(HighbankRegsState), + .class_init = highbank_regs_class_init, +}; + +static void highbank_regs_register_types(void) +{ + type_register_static(&highbank_regs_info); +} + +type_init(highbank_regs_register_types) + +static struct arm_boot_info highbank_binfo; + +/* ram_size must be set to match the upper bound of memory in the + * device tree (linux/arch/arm/boot/dts/highbank.dts), which is + * normally 0xff900000 or -m 4089. When running this board on a + * 32-bit host, set the reg value of memory to 0xf7ff00000 in the + * device tree and pass -m 2047 to QEMU. + */ +static void highbank_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + DeviceState *dev; + SysBusDevice *busdev; + qemu_irq *irqp; + qemu_irq pic[128]; + int n; + qemu_irq cpu_irq[4]; + MemoryRegion *sysram; + MemoryRegion *dram; + MemoryRegion *sysmem; + char *sysboot_filename; + + if (!cpu_model) { + cpu_model = "cortex-a9"; + } + + for (n = 0; n < smp_cpus; n++) { + ARMCPU *cpu; + cpu = cpu_arm_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + + /* This will become a QOM property eventually */ + cpu->reset_cbar = GIC_BASE_ADDR; + irqp = arm_pic_init_cpu(cpu); + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + } + + sysmem = get_system_memory(); + dram = g_new(MemoryRegion, 1); + memory_region_init_ram(dram, "highbank.dram", ram_size); + /* SDRAM at address zero. */ + memory_region_add_subregion(sysmem, 0, dram); + + sysram = g_new(MemoryRegion, 1); + memory_region_init_ram(sysram, "highbank.sysram", 0x8000); + memory_region_add_subregion(sysmem, 0xfff88000, sysram); + if (bios_name != NULL) { + sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (sysboot_filename != NULL) { + uint32_t filesize = get_image_size(sysboot_filename); + if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) { + hw_error("Unable to load %s\n", bios_name); + } + } else { + hw_error("Unable to find %s\n", bios_name); + } + } + + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } + + for (n = 0; n < 128; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + dev = qdev_create(NULL, "l2x0"); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0xfff12000); + + dev = qdev_create(NULL, "sp804"); + qdev_prop_set_uint32(dev, "freq0", 150000000); + qdev_prop_set_uint32(dev, "freq1", 150000000); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0xfff34000); + sysbus_connect_irq(busdev, 0, pic[18]); + sysbus_create_simple("pl011", 0xfff36000, pic[20]); + + dev = qdev_create(NULL, "highbank-regs"); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0xfff3c000); + + sysbus_create_simple("pl061", 0xfff30000, pic[14]); + sysbus_create_simple("pl061", 0xfff31000, pic[15]); + sysbus_create_simple("pl061", 0xfff32000, pic[16]); + sysbus_create_simple("pl061", 0xfff33000, pic[17]); + sysbus_create_simple("pl031", 0xfff35000, pic[19]); + sysbus_create_simple("pl022", 0xfff39000, pic[23]); + + sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]); + + if (nd_table[0].used) { + qemu_check_nic_model(&nd_table[0], "xgmac"); + dev = qdev_create(NULL, "xgmac"); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]); + + qemu_check_nic_model(&nd_table[1], "xgmac"); + dev = qdev_create(NULL, "xgmac"); + qdev_set_nic_properties(dev, &nd_table[1]); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]); + } + + highbank_binfo.ram_size = ram_size; + highbank_binfo.kernel_filename = kernel_filename; + highbank_binfo.kernel_cmdline = kernel_cmdline; + highbank_binfo.initrd_filename = initrd_filename; + /* highbank requires a dtb in order to boot, and the dtb will override + * the board ID. The following value is ignored, so set it to -1 to be + * clear that the value is meaningless. + */ + highbank_binfo.board_id = -1; + highbank_binfo.nb_cpus = smp_cpus; + highbank_binfo.loader_start = 0; + highbank_binfo.write_secondary_boot = hb_write_secondary; + highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary; + arm_load_kernel(arm_env_get_cpu(first_cpu), &highbank_binfo); +} + +static QEMUMachine highbank_machine = { + .name = "highbank", + .desc = "Calxeda Highbank (ECX-1000)", + .init = highbank_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static void highbank_machine_init(void) +{ + qemu_register_machine(&highbank_machine); +} + +machine_init(highbank_machine_init); diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c new file mode 100644 index 0000000000..e0ba327a55 --- /dev/null +++ b/hw/arm/integratorcp.c @@ -0,0 +1,566 @@ +/* + * ARM Integrator CP System emulation. + * + * Copyright (c) 2005-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL + */ + +#include "hw/sysbus.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" +#include "net/net.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t memsz; + MemoryRegion flash; + 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 +}; + +static uint64_t integratorcm_read(void *opaque, hwaddr offset, + unsigned size) +{ + 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. */ + hw_error("integratorcm_read: CM_LMBUSCNT"); + 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. */ + hw_error("integratorcm_read: CM_REFCT"); + 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: + hw_error("integratorcm_read: Unimplemented offset 0x%x\n", + (int)offset); + return 0; + } +} + +static void integratorcm_do_remap(integratorcm_state *s) +{ + /* Sync memory region state with CM_CTRL REMAP bit: + * bit 0 => flash at address 0; bit 1 => RAM + */ + memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4)); +} + +static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) +{ + if (value & 8) { + qemu_system_reset_request(); + } + if ((s->cm_ctrl ^ value) & 1) { + /* (value & 1) != 0 means the green "MISC LED" is lit. + * We don't have any nice place to display LEDs. printf is a bad + * idea because Linux uses the LED as a heartbeat and the output + * will swamp anything else on the terminal. + */ + } + /* Note that the RESET bit [3] always reads as zero */ + s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5); + integratorcm_do_remap(s); +} + +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)) + hw_error("Core module interrupt\n"); +} + +static void integratorcm_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + 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: + hw_error("integratorcm_write: Unimplemented offset 0x%x\n", + (int)offset); + break; + } +} + +/* Integrator/CM control registers. */ + +static const MemoryRegionOps integratorcm_ops = { + .read = integratorcm_read, + .write = integratorcm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int integratorcm_init(SysBusDevice *dev) +{ + integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev); + + s->cm_osc = 0x01000048; + /* ??? What should the high bits of this value be? */ + s->cm_auxosc = 0x0007feff; + s->cm_sdram = 0x00011122; + if (s->memsz >= 256) { + integrator_spd[31] = 64; + s->cm_sdram |= 0x10; + } else if (s->memsz >= 128) { + integrator_spd[31] = 32; + s->cm_sdram |= 0x0c; + } else if (s->memsz >= 64) { + integrator_spd[31] = 16; + s->cm_sdram |= 0x08; + } else if (s->memsz >= 32) { + integrator_spd[31] = 4; + s->cm_sdram |= 0x04; + } else { + integrator_spd[31] = 2; + } + memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); + s->cm_init = 0x00000112; + memory_region_init_ram(&s->flash, "integrator.flash", 0x100000); + vmstate_register_ram_global(&s->flash); + + memory_region_init_io(&s->iomem, &integratorcm_ops, s, + "integratorcm", 0x00800000); + sysbus_init_mmio(dev, &s->iomem); + + integratorcm_do_remap(s); + /* ??? Save/restore. */ + return 0; +} + +/* Integrator/CP hardware emulation. */ +/* Primary interrupt controller. */ + +typedef struct icp_pic_state +{ + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t level; + uint32_t irq_enabled; + uint32_t fiq_enabled; + qemu_irq parent_irq; + qemu_irq parent_fiq; +} icp_pic_state; + +static void icp_pic_update(icp_pic_state *s) +{ + uint32_t flags; + + 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); +} + +static void icp_pic_set_irq(void *opaque, int irq, int level) +{ + icp_pic_state *s = (icp_pic_state *)opaque; + if (level) + s->level |= 1 << irq; + else + s->level &= ~(1 << irq); + icp_pic_update(s); +} + +static uint64_t icp_pic_read(void *opaque, hwaddr offset, + unsigned size) +{ + 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: + printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); + return 0; + } +} + +static void icp_pic_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + 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) + icp_pic_set_irq(s, 0, 1); + break; + case 5: /* INT_SOFTCLR */ + if (value & 1) + icp_pic_set_irq(s, 0, 0); + 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: + printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); + return; + } + icp_pic_update(s); +} + +static const MemoryRegionOps icp_pic_ops = { + .read = icp_pic_read, + .write = icp_pic_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int icp_pic_init(SysBusDevice *dev) +{ + icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev); + + qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32); + sysbus_init_irq(dev, &s->parent_irq); + sysbus_init_irq(dev, &s->parent_fiq); + memory_region_init_io(&s->iomem, &icp_pic_ops, s, "icp-pic", 0x00800000); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +/* CP control registers. */ + +static uint64_t icp_control_read(void *opaque, hwaddr offset, + unsigned size) +{ + 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: + hw_error("icp_control_read: Bad offset %x\n", (int)offset); + return 0; + } +} + +static void icp_control_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + switch (offset >> 2) { + case 1: /* CP_FLASHPROG */ + case 2: /* CP_INTREG */ + case 3: /* CP_DECODE */ + /* Nothing interesting implemented yet. */ + break; + default: + hw_error("icp_control_write: Bad offset %x\n", (int)offset); + } +} + +static const MemoryRegionOps icp_control_ops = { + .read = icp_control_read, + .write = icp_control_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void icp_control_init(hwaddr base) +{ + MemoryRegion *io; + + io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion)); + memory_region_init_io(io, &icp_control_ops, NULL, + "control", 0x00800000); + memory_region_add_subregion(get_system_memory(), base, io); + /* ??? Save/restore. */ +} + + +/* Board init. */ + +static struct arm_boot_info integrator_binfo = { + .loader_start = 0x0, + .board_id = 0x113, +}; + +static void integratorcp_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + ARMCPU *cpu; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *ram_alias = g_new(MemoryRegion, 1); + qemu_irq pic[32]; + qemu_irq *cpu_pic; + DeviceState *dev; + int i; + + if (!cpu_model) { + cpu_model = "arm926"; + } + cpu = cpu_arm_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + + memory_region_init_ram(ram, "integrator.ram", ram_size); + vmstate_register_ram_global(ram); + /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ + /* ??? RAM should repeat to fill physical memory space. */ + /* SDRAM at address zero*/ + memory_region_add_subregion(address_space_mem, 0, ram); + /* And again at address 0x80000000 */ + memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size); + memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias); + + dev = qdev_create(NULL, "integrator_core"); + qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); + qdev_init_nofail(dev); + sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); + + cpu_pic = arm_pic_init_cpu(cpu); + 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++) { + pic[i] = qdev_get_gpio_in(dev, i); + } + sysbus_create_simple("integrator_pic", 0xca000000, pic[26]); + sysbus_create_varargs("integrator_pit", 0x13000000, + pic[5], pic[6], pic[7], NULL); + sysbus_create_simple("pl031", 0x15000000, pic[8]); + sysbus_create_simple("pl011", 0x16000000, pic[1]); + sysbus_create_simple("pl011", 0x17000000, pic[2]); + icp_control_init(0xcb000000); + sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); + sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]); + sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL); + if (nd_table[0].used) + smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); + + sysbus_create_simple("pl110", 0xc0000000, pic[22]); + + 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(cpu, &integrator_binfo); +} + +static QEMUMachine integratorcp_machine = { + .name = "integratorcp", + .desc = "ARM Integrator/CP (ARM926EJ-S)", + .init = integratorcp_init, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void integratorcp_machine_init(void) +{ + qemu_register_machine(&integratorcp_machine); +} + +machine_init(integratorcp_machine_init); + +static Property core_properties[] = { + DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void core_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = integratorcm_init; + dc->props = core_properties; +} + +static const TypeInfo core_info = { + .name = "integrator_core", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(integratorcm_state), + .class_init = core_class_init, +}; + +static void icp_pic_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = icp_pic_init; +} + +static const TypeInfo icp_pic_info = { + .name = "integrator_pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(icp_pic_state), + .class_init = icp_pic_class_init, +}; + +static void integratorcp_register_types(void) +{ + type_register_static(&icp_pic_info); + type_register_static(&core_info); +} + +type_init(integratorcp_register_types) diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c new file mode 100644 index 0000000000..ec50a319ac --- /dev/null +++ b/hw/arm/kzm.c @@ -0,0 +1,157 @@ +/* + * KZM Board System emulation. + * + * Copyright (c) 2008 OKL and 2011 NICTA + * Written by Hans at OK-Labs + * Updated by Peter Chubb. + * + * This code is licensed under the GPL, version 2 or later. + * See the file `COPYING' in the top level directory. + * + * It (partially) emulates a Kyoto Microcomputer + * KZM-ARM11-01 evaluation board, with a Freescale + * i.MX31 SoC + */ + +#include "hw/sysbus.h" +#include "exec/address-spaces.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/serial.h" +#include "hw/imx.h" + + /* Memory map for Kzm Emulation Baseboard: + * 0x00000000-0x00003fff 16k secure ROM IGNORED + * 0x00004000-0x00407fff Reserved IGNORED + * 0x00404000-0x00407fff ROM IGNORED + * 0x00408000-0x0fffffff Reserved IGNORED + * 0x10000000-0x1fffbfff RAM aliasing IGNORED + * 0x1fffc000-0x1fffffff RAM EMULATED + * 0x20000000-0x2fffffff Reserved IGNORED + * 0x30000000-0x7fffffff I.MX31 Internal Register Space + * 0x43f00000 IO_AREA0 + * 0x43f90000 UART1 EMULATED + * 0x43f94000 UART2 EMULATED + * 0x68000000 AVIC EMULATED + * 0x53f80000 CCM EMULATED + * 0x53f94000 PIT 1 EMULATED + * 0x53f98000 PIT 2 EMULATED + * 0x53f90000 GPT EMULATED + * 0x80000000-0x87ffffff RAM EMULATED + * 0x88000000-0x8fffffff RAM Aliasing EMULATED + * 0xa0000000-0xafffffff NAND Flash IGNORED + * 0xb0000000-0xb3ffffff Unavailable IGNORED + * 0xb4000000-0xb4000fff 8-bit free space IGNORED + * 0xb4001000-0xb400100f Board control IGNORED + * 0xb4001003 DIP switch + * 0xb4001010-0xb400101f 7-segment LED IGNORED + * 0xb4001020-0xb400102f LED IGNORED + * 0xb4001030-0xb400103f LED IGNORED + * 0xb4001040-0xb400104f FPGA, UART EMULATED + * 0xb4001050-0xb400105f FPGA, UART EMULATED + * 0xb4001060-0xb40fffff FPGA IGNORED + * 0xb6000000-0xb61fffff LAN controller EMULATED + * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED + * 0xb6300000-0xb7ffffff Free IGNORED + * 0xb8000000-0xb8004fff Memory control registers IGNORED + * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED + * 0xc4000000-0xffffffff Reserved IGNORED + */ + +#define KZM_RAMADDRESS (0x80000000) +#define KZM_FPGA (0xb4001040) + +static struct arm_boot_info kzm_binfo = { + .loader_start = KZM_RAMADDRESS, + .board_id = 1722, +}; + +static void kzm_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + ARMCPU *cpu; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); + MemoryRegion *ram_alias = g_new(MemoryRegion, 1); + qemu_irq *cpu_pic; + DeviceState *dev; + DeviceState *ccm; + + if (!cpu_model) { + cpu_model = "arm1136"; + } + + cpu = cpu_arm_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + + /* On a real system, the first 16k is a `secure boot rom' */ + + memory_region_init_ram(ram, "kzm.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram); + + memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size); + memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias); + + memory_region_init_ram(sram, "kzm.sram", 0x4000); + memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram); + + cpu_pic = arm_pic_init_cpu(cpu); + dev = sysbus_create_varargs("imx_avic", 0x68000000, + cpu_pic[ARM_PIC_CPU_IRQ], + cpu_pic[ARM_PIC_CPU_FIQ], NULL); + + + imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45)); + imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32)); + + ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL); + + imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm); + imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm); + imx_timerg_create(0x53f90000, qdev_get_gpio_in(dev, 29), ccm); + + if (nd_table[0].used) { + lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 52)); + } + + if (serial_hds[2]) { /* touchscreen */ + serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0, + qdev_get_gpio_in(dev, 52), + 14745600, serial_hds[2], + DEVICE_NATIVE_ENDIAN); + } + + kzm_binfo.ram_size = ram_size; + kzm_binfo.kernel_filename = kernel_filename; + kzm_binfo.kernel_cmdline = kernel_cmdline; + kzm_binfo.initrd_filename = initrd_filename; + kzm_binfo.nb_cpus = 1; + arm_load_kernel(cpu, &kzm_binfo); +} + +static QEMUMachine kzm_machine = { + .name = "kzm", + .desc = "ARM KZM Emulation Baseboard (ARM1136)", + .init = kzm_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void kzm_machine_init(void) +{ + qemu_register_machine(&kzm_machine); +} + +machine_init(kzm_machine_init) diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c new file mode 100644 index 0000000000..aea908f036 --- /dev/null +++ b/hw/arm/mainstone.c @@ -0,0 +1,190 @@ +/* + * PXA270-based Intel Mainstone platforms. + * + * Copyright (c) 2007 by Armin Kuster or + * + * + * Code based on spitz platform by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "net/net.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/flash.h" +#include "sysemu/blockdev.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + +/* Device addresses */ +#define MST_FPGA_PHYS 0x08000000 +#define MST_ETH_PHYS 0x10000300 +#define MST_FLASH_0 0x00000000 +#define MST_FLASH_1 0x04000000 + +/* IRQ definitions */ +#define MMC_IRQ 0 +#define USIM_IRQ 1 +#define USBC_IRQ 2 +#define ETHERNET_IRQ 3 +#define AC97_IRQ 4 +#define PEN_IRQ 5 +#define MSINS_IRQ 6 +#define EXBRD_IRQ 7 +#define S0_CD_IRQ 9 +#define S0_STSCHG_IRQ 10 +#define S0_IRQ 11 +#define S1_CD_IRQ 13 +#define S1_STSCHG_IRQ 14 +#define S1_IRQ 15 + +static struct keymap map[0xE0] = { + [0 ... 0xDF] = { -1, -1 }, + [0x1e] = {0,0}, /* a */ + [0x30] = {0,1}, /* b */ + [0x2e] = {0,2}, /* c */ + [0x20] = {0,3}, /* d */ + [0x12] = {0,4}, /* e */ + [0x21] = {0,5}, /* f */ + [0x22] = {1,0}, /* g */ + [0x23] = {1,1}, /* h */ + [0x17] = {1,2}, /* i */ + [0x24] = {1,3}, /* j */ + [0x25] = {1,4}, /* k */ + [0x26] = {1,5}, /* l */ + [0x32] = {2,0}, /* m */ + [0x31] = {2,1}, /* n */ + [0x18] = {2,2}, /* o */ + [0x19] = {2,3}, /* p */ + [0x10] = {2,4}, /* q */ + [0x13] = {2,5}, /* r */ + [0x1f] = {3,0}, /* s */ + [0x14] = {3,1}, /* t */ + [0x16] = {3,2}, /* u */ + [0x2f] = {3,3}, /* v */ + [0x11] = {3,4}, /* w */ + [0x2d] = {3,5}, /* x */ + [0x15] = {4,2}, /* y */ + [0x2c] = {4,3}, /* z */ + [0xc7] = {5,0}, /* Home */ + [0x2a] = {5,1}, /* shift */ + [0x39] = {5,2}, /* space */ + [0x39] = {5,3}, /* space */ + [0x1c] = {5,5}, /* enter */ + [0xc8] = {6,0}, /* up */ + [0xd0] = {6,1}, /* down */ + [0xcb] = {6,2}, /* left */ + [0xcd] = {6,3}, /* right */ +}; + +enum mainstone_model_e { mainstone }; + +#define MAINSTONE_RAM 0x04000000 +#define MAINSTONE_ROM 0x00800000 +#define MAINSTONE_FLASH 0x02000000 + +static struct arm_boot_info mainstone_binfo = { + .loader_start = PXA2XX_SDRAM_BASE, + .ram_size = 0x04000000, +}; + +static void mainstone_common_init(MemoryRegion *address_space_mem, + QEMUMachineInitArgs *args, + enum mainstone_model_e model, int arm_id) +{ + uint32_t sector_len = 256 * 1024; + hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; + PXA2xxState *mpu; + DeviceState *mst_irq; + DriveInfo *dinfo; + int i; + int be; + MemoryRegion *rom = g_new(MemoryRegion, 1); + const char *cpu_model = args->cpu_model; + + if (!cpu_model) + cpu_model = "pxa270-c5"; + + /* Setup CPU & memory */ + mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); + memory_region_init_ram(rom, "mainstone.rom", MAINSTONE_ROM); + vmstate_register_ram_global(rom); + memory_region_set_readonly(rom, true); + memory_region_add_subregion(address_space_mem, 0, rom); + +#ifdef TARGET_WORDS_BIGENDIAN + be = 1; +#else + be = 0; +#endif + /* There are two 32MiB flash devices on the board */ + for (i = 0; i < 2; i ++) { + dinfo = drive_get(IF_PFLASH, 0, i); + if (!dinfo) { + fprintf(stderr, "Two flash images must be given with the " + "'pflash' parameter\n"); + exit(1); + } + + if (!pflash_cfi01_register(mainstone_flash_base[i], NULL, + i ? "mainstone.flash1" : "mainstone.flash0", + MAINSTONE_FLASH, + dinfo->bdrv, sector_len, + MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0, + be)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + exit(1); + } + } + + mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS, + qdev_get_gpio_in(mpu->gpio, 0)); + + /* setup keypad */ + printf("map addr %p\n", &map); + pxa27x_register_keypad(mpu->kp, map, 0xe0); + + /* MMC/SD host */ + pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); + + pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0], + qdev_get_gpio_in(mst_irq, S0_IRQ), + qdev_get_gpio_in(mst_irq, S0_CD_IRQ)); + pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1], + qdev_get_gpio_in(mst_irq, S1_IRQ), + qdev_get_gpio_in(mst_irq, S1_CD_IRQ)); + + smc91c111_init(&nd_table[0], MST_ETH_PHYS, + qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); + + mainstone_binfo.kernel_filename = args->kernel_filename; + mainstone_binfo.kernel_cmdline = args->kernel_cmdline; + mainstone_binfo.initrd_filename = args->initrd_filename; + mainstone_binfo.board_id = arm_id; + arm_load_kernel(mpu->cpu, &mainstone_binfo); +} + +static void mainstone_init(QEMUMachineInitArgs *args) +{ + mainstone_common_init(get_system_memory(), args, mainstone, 0x196); +} + +static QEMUMachine mainstone2_machine = { + .name = "mainstone", + .desc = "Mainstone II (PXA27x)", + .init = mainstone_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void mainstone_machine_init(void) +{ + qemu_register_machine(&mainstone2_machine); +} + +machine_init(mainstone_machine_init); diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c new file mode 100644 index 0000000000..a37dbd7961 --- /dev/null +++ b/hw/arm/musicpal.c @@ -0,0 +1,1697 @@ +/* + * Marvell MV88W8618 / Freecom MusicPal emulation. + * + * Copyright (c) 2008 Jan Kiszka + * + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/serial.h" +#include "qemu/timer.h" +#include "hw/ptimer.h" +#include "block/block.h" +#include "hw/flash.h" +#include "ui/console.h" +#include "hw/i2c.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" +#include "ui/pixel_ops.h" + +#define MP_MISC_BASE 0x80002000 +#define MP_MISC_SIZE 0x00001000 + +#define MP_ETH_BASE 0x80008000 +#define MP_ETH_SIZE 0x00001000 + +#define MP_WLAN_BASE 0x8000C000 +#define MP_WLAN_SIZE 0x00000800 + +#define MP_UART1_BASE 0x8000C840 +#define MP_UART2_BASE 0x8000C940 + +#define MP_GPIO_BASE 0x8000D000 +#define MP_GPIO_SIZE 0x00001000 + +#define MP_FLASHCFG_BASE 0x90006000 +#define MP_FLASHCFG_SIZE 0x00001000 + +#define MP_AUDIO_BASE 0x90007000 + +#define MP_PIC_BASE 0x90008000 +#define MP_PIC_SIZE 0x00001000 + +#define MP_PIT_BASE 0x90009000 +#define MP_PIT_SIZE 0x00001000 + +#define MP_LCD_BASE 0x9000c000 +#define MP_LCD_SIZE 0x00001000 + +#define MP_SRAM_BASE 0xC0000000 +#define MP_SRAM_SIZE 0x00020000 + +#define MP_RAM_DEFAULT_SIZE 32*1024*1024 +#define MP_FLASH_SIZE_MAX 32*1024*1024 + +#define MP_TIMER1_IRQ 4 +#define MP_TIMER2_IRQ 5 +#define MP_TIMER3_IRQ 6 +#define MP_TIMER4_IRQ 7 +#define MP_EHCI_IRQ 8 +#define MP_ETH_IRQ 9 +#define MP_UART1_IRQ 11 +#define MP_UART2_IRQ 11 +#define MP_GPIO_IRQ 12 +#define MP_RTC_IRQ 28 +#define MP_AUDIO_IRQ 30 + +/* Wolfson 8750 I2C address */ +#define MP_WM_ADDR 0x1A + +/* Ethernet register offsets */ +#define MP_ETH_SMIR 0x010 +#define MP_ETH_PCXR 0x408 +#define MP_ETH_SDCMR 0x448 +#define MP_ETH_ICR 0x450 +#define MP_ETH_IMR 0x458 +#define MP_ETH_FRDP0 0x480 +#define MP_ETH_FRDP1 0x484 +#define MP_ETH_FRDP2 0x488 +#define MP_ETH_FRDP3 0x48C +#define MP_ETH_CRDP0 0x4A0 +#define MP_ETH_CRDP1 0x4A4 +#define MP_ETH_CRDP2 0x4A8 +#define MP_ETH_CRDP3 0x4AC +#define MP_ETH_CTDP0 0x4E0 +#define MP_ETH_CTDP1 0x4E4 +#define MP_ETH_CTDP2 0x4E8 +#define MP_ETH_CTDP3 0x4EC + +/* MII PHY access */ +#define MP_ETH_SMIR_DATA 0x0000FFFF +#define MP_ETH_SMIR_ADDR 0x03FF0000 +#define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */ +#define MP_ETH_SMIR_RDVALID (1 << 27) + +/* PHY registers */ +#define MP_ETH_PHY1_BMSR 0x00210000 +#define MP_ETH_PHY1_PHYSID1 0x00410000 +#define MP_ETH_PHY1_PHYSID2 0x00610000 + +#define MP_PHY_BMSR_LINK 0x0004 +#define MP_PHY_BMSR_AUTONEG 0x0008 + +#define MP_PHY_88E3015 0x01410E20 + +/* TX descriptor status */ +#define MP_ETH_TX_OWN (1 << 31) + +/* RX descriptor status */ +#define MP_ETH_RX_OWN (1 << 31) + +/* Interrupt cause/mask bits */ +#define MP_ETH_IRQ_RX_BIT 0 +#define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT) +#define MP_ETH_IRQ_TXHI_BIT 2 +#define MP_ETH_IRQ_TXLO_BIT 3 + +/* Port config bits */ +#define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */ + +/* SDMA command bits */ +#define MP_ETH_CMD_TXHI (1 << 23) +#define MP_ETH_CMD_TXLO (1 << 22) + +typedef struct mv88w8618_tx_desc { + uint32_t cmdstat; + uint16_t res; + uint16_t bytes; + uint32_t buffer; + uint32_t next; +} mv88w8618_tx_desc; + +typedef struct mv88w8618_rx_desc { + uint32_t cmdstat; + uint16_t bytes; + uint16_t buffer_size; + uint32_t buffer; + uint32_t next; +} mv88w8618_rx_desc; + +typedef struct mv88w8618_eth_state { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq; + uint32_t smir; + uint32_t icr; + uint32_t imr; + int mmio_index; + uint32_t vlan_header; + uint32_t tx_queue[2]; + uint32_t rx_queue[4]; + uint32_t frx_queue[4]; + uint32_t cur_rx[4]; + NICState *nic; + NICConf conf; +} mv88w8618_eth_state; + +static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc) +{ + cpu_to_le32s(&desc->cmdstat); + cpu_to_le16s(&desc->bytes); + cpu_to_le16s(&desc->buffer_size); + cpu_to_le32s(&desc->buffer); + cpu_to_le32s(&desc->next); + cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc)); +} + +static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) +{ + cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc)); + le32_to_cpus(&desc->cmdstat); + le16_to_cpus(&desc->bytes); + le16_to_cpus(&desc->buffer_size); + le32_to_cpus(&desc->buffer); + le32_to_cpus(&desc->next); +} + +static int eth_can_receive(NetClientState *nc) +{ + return 1; +} + +static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) +{ + mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); + uint32_t desc_addr; + mv88w8618_rx_desc desc; + int i; + + for (i = 0; i < 4; i++) { + desc_addr = s->cur_rx[i]; + if (!desc_addr) { + continue; + } + do { + eth_rx_desc_get(desc_addr, &desc); + if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { + cpu_physical_memory_write(desc.buffer + s->vlan_header, + buf, size); + desc.bytes = size + s->vlan_header; + desc.cmdstat &= ~MP_ETH_RX_OWN; + s->cur_rx[i] = desc.next; + + s->icr |= MP_ETH_IRQ_RX; + if (s->icr & s->imr) { + qemu_irq_raise(s->irq); + } + eth_rx_desc_put(desc_addr, &desc); + return size; + } + desc_addr = desc.next; + } while (desc_addr != s->rx_queue[i]); + } + return size; +} + +static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc) +{ + cpu_to_le32s(&desc->cmdstat); + cpu_to_le16s(&desc->res); + cpu_to_le16s(&desc->bytes); + cpu_to_le32s(&desc->buffer); + cpu_to_le32s(&desc->next); + cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc)); +} + +static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc) +{ + cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc)); + le32_to_cpus(&desc->cmdstat); + le16_to_cpus(&desc->res); + le16_to_cpus(&desc->bytes); + le32_to_cpus(&desc->buffer); + le32_to_cpus(&desc->next); +} + +static void eth_send(mv88w8618_eth_state *s, int queue_index) +{ + uint32_t desc_addr = s->tx_queue[queue_index]; + mv88w8618_tx_desc desc; + uint32_t next_desc; + uint8_t buf[2048]; + int len; + + do { + eth_tx_desc_get(desc_addr, &desc); + next_desc = desc.next; + if (desc.cmdstat & MP_ETH_TX_OWN) { + len = desc.bytes; + if (len < 2048) { + cpu_physical_memory_read(desc.buffer, buf, len); + qemu_send_packet(qemu_get_queue(s->nic), buf, len); + } + desc.cmdstat &= ~MP_ETH_TX_OWN; + s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); + eth_tx_desc_put(desc_addr, &desc); + } + desc_addr = next_desc; + } while (desc_addr != s->tx_queue[queue_index]); +} + +static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset, + unsigned size) +{ + mv88w8618_eth_state *s = opaque; + + switch (offset) { + case MP_ETH_SMIR: + if (s->smir & MP_ETH_SMIR_OPCODE) { + switch (s->smir & MP_ETH_SMIR_ADDR) { + case MP_ETH_PHY1_BMSR: + return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG | + MP_ETH_SMIR_RDVALID; + case MP_ETH_PHY1_PHYSID1: + return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID; + case MP_ETH_PHY1_PHYSID2: + return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID; + default: + return MP_ETH_SMIR_RDVALID; + } + } + return 0; + + case MP_ETH_ICR: + return s->icr; + + case MP_ETH_IMR: + return s->imr; + + case MP_ETH_FRDP0 ... MP_ETH_FRDP3: + return s->frx_queue[(offset - MP_ETH_FRDP0)/4]; + + case MP_ETH_CRDP0 ... MP_ETH_CRDP3: + return s->rx_queue[(offset - MP_ETH_CRDP0)/4]; + + case MP_ETH_CTDP0 ... MP_ETH_CTDP3: + return s->tx_queue[(offset - MP_ETH_CTDP0)/4]; + + default: + return 0; + } +} + +static void mv88w8618_eth_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + mv88w8618_eth_state *s = opaque; + + switch (offset) { + case MP_ETH_SMIR: + s->smir = value; + break; + + case MP_ETH_PCXR: + s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2; + break; + + case MP_ETH_SDCMR: + if (value & MP_ETH_CMD_TXHI) { + eth_send(s, 1); + } + if (value & MP_ETH_CMD_TXLO) { + eth_send(s, 0); + } + if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) { + qemu_irq_raise(s->irq); + } + break; + + case MP_ETH_ICR: + s->icr &= value; + break; + + case MP_ETH_IMR: + s->imr = value; + if (s->icr & s->imr) { + qemu_irq_raise(s->irq); + } + break; + + case MP_ETH_FRDP0 ... MP_ETH_FRDP3: + s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value; + break; + + case MP_ETH_CRDP0 ... MP_ETH_CRDP3: + s->rx_queue[(offset - MP_ETH_CRDP0)/4] = + s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value; + break; + + case MP_ETH_CTDP0 ... MP_ETH_CTDP3: + s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value; + break; + } +} + +static const MemoryRegionOps mv88w8618_eth_ops = { + .read = mv88w8618_eth_read, + .write = mv88w8618_eth_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void eth_cleanup(NetClientState *nc) +{ + mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); + + s->nic = NULL; +} + +static NetClientInfo net_mv88w8618_info = { + .type = NET_CLIENT_OPTIONS_KIND_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_receive, + .receive = eth_receive, + .cleanup = eth_cleanup, +}; + +static int mv88w8618_eth_init(SysBusDevice *dev) +{ + mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev); + + sysbus_init_irq(dev, &s->irq); + s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->qdev.id, s); + memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth", + MP_ETH_SIZE); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static const VMStateDescription mv88w8618_eth_vmsd = { + .name = "mv88w8618_eth", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(smir, mv88w8618_eth_state), + VMSTATE_UINT32(icr, mv88w8618_eth_state), + VMSTATE_UINT32(imr, mv88w8618_eth_state), + VMSTATE_UINT32(vlan_header, mv88w8618_eth_state), + VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2), + VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4), + VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4), + VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4), + VMSTATE_END_OF_LIST() + } +}; + +static Property mv88w8618_eth_properties[] = { + DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_eth_init; + dc->vmsd = &mv88w8618_eth_vmsd; + dc->props = mv88w8618_eth_properties; +} + +static const TypeInfo mv88w8618_eth_info = { + .name = "mv88w8618_eth", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_eth_state), + .class_init = mv88w8618_eth_class_init, +}; + +/* LCD register offsets */ +#define MP_LCD_IRQCTRL 0x180 +#define MP_LCD_IRQSTAT 0x184 +#define MP_LCD_SPICTRL 0x1ac +#define MP_LCD_INST 0x1bc +#define MP_LCD_DATA 0x1c0 + +/* Mode magics */ +#define MP_LCD_SPI_DATA 0x00100011 +#define MP_LCD_SPI_CMD 0x00104011 +#define MP_LCD_SPI_INVALID 0x00000000 + +/* Commmands */ +#define MP_LCD_INST_SETPAGE0 0xB0 +/* ... */ +#define MP_LCD_INST_SETPAGE7 0xB7 + +#define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */ + +typedef struct musicpal_lcd_state { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t brightness; + uint32_t mode; + uint32_t irqctrl; + uint32_t page; + uint32_t page_off; + DisplayState *ds; + uint8_t video_ram[128*64/8]; +} musicpal_lcd_state; + +static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col) +{ + switch (s->brightness) { + case 7: + return col; + case 0: + return 0; + default: + return (col * s->brightness) / 7; + } +} + +#define SET_LCD_PIXEL(depth, type) \ +static inline void glue(set_lcd_pixel, depth) \ + (musicpal_lcd_state *s, int x, int y, type col) \ +{ \ + int dx, dy; \ + type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \ +\ + for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \ + for (dx = 0; dx < 3; dx++, pixel++) \ + *pixel = col; \ +} +SET_LCD_PIXEL(8, uint8_t) +SET_LCD_PIXEL(16, uint16_t) +SET_LCD_PIXEL(32, uint32_t) + +static void lcd_refresh(void *opaque) +{ + musicpal_lcd_state *s = opaque; + int x, y, col; + + switch (ds_get_bits_per_pixel(s->ds)) { + case 0: + return; +#define LCD_REFRESH(depth, func) \ + case depth: \ + col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \ + scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \ + scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \ + for (x = 0; x < 128; x++) { \ + for (y = 0; y < 64; y++) { \ + if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \ + glue(set_lcd_pixel, depth)(s, x, y, col); \ + } else { \ + glue(set_lcd_pixel, depth)(s, x, y, 0); \ + } \ + } \ + } \ + break; + LCD_REFRESH(8, rgb_to_pixel8) + LCD_REFRESH(16, rgb_to_pixel16) + LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ? + rgb_to_pixel32bgr : rgb_to_pixel32)) + default: + hw_error("unsupported colour depth %i\n", + ds_get_bits_per_pixel(s->ds)); + } + + dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3); +} + +static void lcd_invalidate(void *opaque) +{ +} + +static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level) +{ + musicpal_lcd_state *s = opaque; + s->brightness &= ~(1 << irq); + s->brightness |= level << irq; +} + +static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset, + unsigned size) +{ + musicpal_lcd_state *s = opaque; + + switch (offset) { + case MP_LCD_IRQCTRL: + return s->irqctrl; + + default: + return 0; + } +} + +static void musicpal_lcd_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + musicpal_lcd_state *s = opaque; + + switch (offset) { + case MP_LCD_IRQCTRL: + s->irqctrl = value; + break; + + case MP_LCD_SPICTRL: + if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) { + s->mode = value; + } else { + s->mode = MP_LCD_SPI_INVALID; + } + break; + + case MP_LCD_INST: + if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) { + s->page = value - MP_LCD_INST_SETPAGE0; + s->page_off = 0; + } + break; + + case MP_LCD_DATA: + if (s->mode == MP_LCD_SPI_CMD) { + if (value >= MP_LCD_INST_SETPAGE0 && + value <= MP_LCD_INST_SETPAGE7) { + s->page = value - MP_LCD_INST_SETPAGE0; + s->page_off = 0; + } + } else if (s->mode == MP_LCD_SPI_DATA) { + s->video_ram[s->page*128 + s->page_off] = value; + s->page_off = (s->page_off + 1) & 127; + } + break; + } +} + +static const MemoryRegionOps musicpal_lcd_ops = { + .read = musicpal_lcd_read, + .write = musicpal_lcd_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int musicpal_lcd_init(SysBusDevice *dev) +{ + musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev); + + s->brightness = 7; + + memory_region_init_io(&s->iomem, &musicpal_lcd_ops, s, + "musicpal-lcd", MP_LCD_SIZE); + sysbus_init_mmio(dev, &s->iomem); + + s->ds = graphic_console_init(lcd_refresh, lcd_invalidate, + NULL, NULL, s); + qemu_console_resize(s->ds, 128*3, 64*3); + + qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3); + + return 0; +} + +static const VMStateDescription musicpal_lcd_vmsd = { + .name = "musicpal_lcd", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(brightness, musicpal_lcd_state), + VMSTATE_UINT32(mode, musicpal_lcd_state), + VMSTATE_UINT32(irqctrl, musicpal_lcd_state), + VMSTATE_UINT32(page, musicpal_lcd_state), + VMSTATE_UINT32(page_off, musicpal_lcd_state), + VMSTATE_BUFFER(video_ram, musicpal_lcd_state), + VMSTATE_END_OF_LIST() + } +}; + +static void musicpal_lcd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = musicpal_lcd_init; + dc->vmsd = &musicpal_lcd_vmsd; +} + +static const TypeInfo musicpal_lcd_info = { + .name = "musicpal_lcd", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(musicpal_lcd_state), + .class_init = musicpal_lcd_class_init, +}; + +/* PIC register offsets */ +#define MP_PIC_STATUS 0x00 +#define MP_PIC_ENABLE_SET 0x08 +#define MP_PIC_ENABLE_CLR 0x0C + +typedef struct mv88w8618_pic_state +{ + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t level; + uint32_t enabled; + qemu_irq parent_irq; +} mv88w8618_pic_state; + +static void mv88w8618_pic_update(mv88w8618_pic_state *s) +{ + qemu_set_irq(s->parent_irq, (s->level & s->enabled)); +} + +static void mv88w8618_pic_set_irq(void *opaque, int irq, int level) +{ + mv88w8618_pic_state *s = opaque; + + if (level) { + s->level |= 1 << irq; + } else { + s->level &= ~(1 << irq); + } + mv88w8618_pic_update(s); +} + +static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset, + unsigned size) +{ + mv88w8618_pic_state *s = opaque; + + switch (offset) { + case MP_PIC_STATUS: + return s->level & s->enabled; + + default: + return 0; + } +} + +static void mv88w8618_pic_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + mv88w8618_pic_state *s = opaque; + + switch (offset) { + case MP_PIC_ENABLE_SET: + s->enabled |= value; + break; + + case MP_PIC_ENABLE_CLR: + s->enabled &= ~value; + s->level &= ~value; + break; + } + mv88w8618_pic_update(s); +} + +static void mv88w8618_pic_reset(DeviceState *d) +{ + mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, + SYS_BUS_DEVICE(d)); + + s->level = 0; + s->enabled = 0; +} + +static const MemoryRegionOps mv88w8618_pic_ops = { + .read = mv88w8618_pic_read, + .write = mv88w8618_pic_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int mv88w8618_pic_init(SysBusDevice *dev) +{ + mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev); + + qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32); + sysbus_init_irq(dev, &s->parent_irq); + memory_region_init_io(&s->iomem, &mv88w8618_pic_ops, s, + "musicpal-pic", MP_PIC_SIZE); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static const VMStateDescription mv88w8618_pic_vmsd = { + .name = "mv88w8618_pic", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(level, mv88w8618_pic_state), + VMSTATE_UINT32(enabled, mv88w8618_pic_state), + VMSTATE_END_OF_LIST() + } +}; + +static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_pic_init; + dc->reset = mv88w8618_pic_reset; + dc->vmsd = &mv88w8618_pic_vmsd; +} + +static const TypeInfo mv88w8618_pic_info = { + .name = "mv88w8618_pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_pic_state), + .class_init = mv88w8618_pic_class_init, +}; + +/* PIT register offsets */ +#define MP_PIT_TIMER1_LENGTH 0x00 +/* ... */ +#define MP_PIT_TIMER4_LENGTH 0x0C +#define MP_PIT_CONTROL 0x10 +#define MP_PIT_TIMER1_VALUE 0x14 +/* ... */ +#define MP_PIT_TIMER4_VALUE 0x20 +#define MP_BOARD_RESET 0x34 + +/* Magic board reset value (probably some watchdog behind it) */ +#define MP_BOARD_RESET_MAGIC 0x10000 + +typedef struct mv88w8618_timer_state { + ptimer_state *ptimer; + uint32_t limit; + int freq; + qemu_irq irq; +} mv88w8618_timer_state; + +typedef struct mv88w8618_pit_state { + SysBusDevice busdev; + MemoryRegion iomem; + mv88w8618_timer_state timer[4]; +} mv88w8618_pit_state; + +static void mv88w8618_timer_tick(void *opaque) +{ + mv88w8618_timer_state *s = opaque; + + qemu_irq_raise(s->irq); +} + +static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, + uint32_t freq) +{ + QEMUBH *bh; + + sysbus_init_irq(dev, &s->irq); + s->freq = freq; + + bh = qemu_bh_new(mv88w8618_timer_tick, s); + s->ptimer = ptimer_init(bh); +} + +static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, + unsigned size) +{ + mv88w8618_pit_state *s = opaque; + mv88w8618_timer_state *t; + + switch (offset) { + case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE: + t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2]; + return ptimer_get_count(t->ptimer); + + default: + return 0; + } +} + +static void mv88w8618_pit_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + mv88w8618_pit_state *s = opaque; + mv88w8618_timer_state *t; + int i; + + switch (offset) { + case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH: + t = &s->timer[offset >> 2]; + t->limit = value; + if (t->limit > 0) { + ptimer_set_limit(t->ptimer, t->limit, 1); + } else { + ptimer_stop(t->ptimer); + } + break; + + case MP_PIT_CONTROL: + for (i = 0; i < 4; i++) { + t = &s->timer[i]; + if (value & 0xf && t->limit > 0) { + ptimer_set_limit(t->ptimer, t->limit, 0); + ptimer_set_freq(t->ptimer, t->freq); + ptimer_run(t->ptimer, 0); + } else { + ptimer_stop(t->ptimer); + } + value >>= 4; + } + break; + + case MP_BOARD_RESET: + if (value == MP_BOARD_RESET_MAGIC) { + qemu_system_reset_request(); + } + break; + } +} + +static void mv88w8618_pit_reset(DeviceState *d) +{ + mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, + SYS_BUS_DEVICE(d)); + int i; + + for (i = 0; i < 4; i++) { + ptimer_stop(s->timer[i].ptimer); + s->timer[i].limit = 0; + } +} + +static const MemoryRegionOps mv88w8618_pit_ops = { + .read = mv88w8618_pit_read, + .write = mv88w8618_pit_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int mv88w8618_pit_init(SysBusDevice *dev) +{ + mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev); + int i; + + /* Letting them all run at 1 MHz is likely just a pragmatic + * simplification. */ + for (i = 0; i < 4; i++) { + mv88w8618_timer_init(dev, &s->timer[i], 1000000); + } + + memory_region_init_io(&s->iomem, &mv88w8618_pit_ops, s, + "musicpal-pit", MP_PIT_SIZE); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static const VMStateDescription mv88w8618_timer_vmsd = { + .name = "timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PTIMER(ptimer, mv88w8618_timer_state), + VMSTATE_UINT32(limit, mv88w8618_timer_state), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription mv88w8618_pit_vmsd = { + .name = "mv88w8618_pit", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1, + mv88w8618_timer_vmsd, mv88w8618_timer_state), + VMSTATE_END_OF_LIST() + } +}; + +static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_pit_init; + dc->reset = mv88w8618_pit_reset; + dc->vmsd = &mv88w8618_pit_vmsd; +} + +static const TypeInfo mv88w8618_pit_info = { + .name = "mv88w8618_pit", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_pit_state), + .class_init = mv88w8618_pit_class_init, +}; + +/* Flash config register offsets */ +#define MP_FLASHCFG_CFGR0 0x04 + +typedef struct mv88w8618_flashcfg_state { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t cfgr0; +} mv88w8618_flashcfg_state; + +static uint64_t mv88w8618_flashcfg_read(void *opaque, + hwaddr offset, + unsigned size) +{ + mv88w8618_flashcfg_state *s = opaque; + + switch (offset) { + case MP_FLASHCFG_CFGR0: + return s->cfgr0; + + default: + return 0; + } +} + +static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + mv88w8618_flashcfg_state *s = opaque; + + switch (offset) { + case MP_FLASHCFG_CFGR0: + s->cfgr0 = value; + break; + } +} + +static const MemoryRegionOps mv88w8618_flashcfg_ops = { + .read = mv88w8618_flashcfg_read, + .write = mv88w8618_flashcfg_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int mv88w8618_flashcfg_init(SysBusDevice *dev) +{ + mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev); + + s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ + memory_region_init_io(&s->iomem, &mv88w8618_flashcfg_ops, s, + "musicpal-flashcfg", MP_FLASHCFG_SIZE); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static const VMStateDescription mv88w8618_flashcfg_vmsd = { + .name = "mv88w8618_flashcfg", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state), + VMSTATE_END_OF_LIST() + } +}; + +static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_flashcfg_init; + dc->vmsd = &mv88w8618_flashcfg_vmsd; +} + +static const TypeInfo mv88w8618_flashcfg_info = { + .name = "mv88w8618_flashcfg", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_flashcfg_state), + .class_init = mv88w8618_flashcfg_class_init, +}; + +/* Misc register offsets */ +#define MP_MISC_BOARD_REVISION 0x18 + +#define MP_BOARD_REVISION 0x31 + +static uint64_t musicpal_misc_read(void *opaque, hwaddr offset, + unsigned size) +{ + switch (offset) { + case MP_MISC_BOARD_REVISION: + return MP_BOARD_REVISION; + + default: + return 0; + } +} + +static void musicpal_misc_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +} + +static const MemoryRegionOps musicpal_misc_ops = { + .read = musicpal_misc_read, + .write = musicpal_misc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void musicpal_misc_init(SysBusDevice *dev) +{ + MemoryRegion *iomem = g_new(MemoryRegion, 1); + + memory_region_init_io(iomem, &musicpal_misc_ops, NULL, + "musicpal-misc", MP_MISC_SIZE); + sysbus_add_memory(dev, MP_MISC_BASE, iomem); +} + +/* WLAN register offsets */ +#define MP_WLAN_MAGIC1 0x11c +#define MP_WLAN_MAGIC2 0x124 + +static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset, + unsigned size) +{ + switch (offset) { + /* Workaround to allow loading the binary-only wlandrv.ko crap + * from the original Freecom firmware. */ + case MP_WLAN_MAGIC1: + return ~3; + case MP_WLAN_MAGIC2: + return -1; + + default: + return 0; + } +} + +static void mv88w8618_wlan_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +} + +static const MemoryRegionOps mv88w8618_wlan_ops = { + .read = mv88w8618_wlan_read, + .write =mv88w8618_wlan_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int mv88w8618_wlan_init(SysBusDevice *dev) +{ + MemoryRegion *iomem = g_new(MemoryRegion, 1); + + memory_region_init_io(iomem, &mv88w8618_wlan_ops, NULL, + "musicpal-wlan", MP_WLAN_SIZE); + sysbus_init_mmio(dev, iomem); + return 0; +} + +/* GPIO register offsets */ +#define MP_GPIO_OE_LO 0x008 +#define MP_GPIO_OUT_LO 0x00c +#define MP_GPIO_IN_LO 0x010 +#define MP_GPIO_IER_LO 0x014 +#define MP_GPIO_IMR_LO 0x018 +#define MP_GPIO_ISR_LO 0x020 +#define MP_GPIO_OE_HI 0x508 +#define MP_GPIO_OUT_HI 0x50c +#define MP_GPIO_IN_HI 0x510 +#define MP_GPIO_IER_HI 0x514 +#define MP_GPIO_IMR_HI 0x518 +#define MP_GPIO_ISR_HI 0x520 + +/* GPIO bits & masks */ +#define MP_GPIO_LCD_BRIGHTNESS 0x00070000 +#define MP_GPIO_I2C_DATA_BIT 29 +#define MP_GPIO_I2C_CLOCK_BIT 30 + +/* LCD brightness bits in GPIO_OE_HI */ +#define MP_OE_LCD_BRIGHTNESS 0x0007 + +typedef struct musicpal_gpio_state { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t lcd_brightness; + uint32_t out_state; + uint32_t in_state; + uint32_t ier; + uint32_t imr; + uint32_t isr; + qemu_irq irq; + qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */ +} musicpal_gpio_state; + +static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) { + int i; + uint32_t brightness; + + /* compute brightness ratio */ + switch (s->lcd_brightness) { + case 0x00000007: + brightness = 0; + break; + + case 0x00020000: + brightness = 1; + break; + + case 0x00020001: + brightness = 2; + break; + + case 0x00040000: + brightness = 3; + break; + + case 0x00010006: + brightness = 4; + break; + + case 0x00020005: + brightness = 5; + break; + + case 0x00040003: + brightness = 6; + break; + + case 0x00030004: + default: + brightness = 7; + } + + /* set lcd brightness GPIOs */ + for (i = 0; i <= 2; i++) { + qemu_set_irq(s->out[i], (brightness >> i) & 1); + } +} + +static void musicpal_gpio_pin_event(void *opaque, int pin, int level) +{ + musicpal_gpio_state *s = opaque; + uint32_t mask = 1 << pin; + uint32_t delta = level << pin; + uint32_t old = s->in_state & mask; + + s->in_state &= ~mask; + s->in_state |= delta; + + if ((old ^ delta) && + ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) { + s->isr = mask; + qemu_irq_raise(s->irq); + } +} + +static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset, + unsigned size) +{ + musicpal_gpio_state *s = opaque; + + switch (offset) { + case MP_GPIO_OE_HI: /* used for LCD brightness control */ + return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS; + + case MP_GPIO_OUT_LO: + return s->out_state & 0xFFFF; + case MP_GPIO_OUT_HI: + return s->out_state >> 16; + + case MP_GPIO_IN_LO: + return s->in_state & 0xFFFF; + case MP_GPIO_IN_HI: + return s->in_state >> 16; + + case MP_GPIO_IER_LO: + return s->ier & 0xFFFF; + case MP_GPIO_IER_HI: + return s->ier >> 16; + + case MP_GPIO_IMR_LO: + return s->imr & 0xFFFF; + case MP_GPIO_IMR_HI: + return s->imr >> 16; + + case MP_GPIO_ISR_LO: + return s->isr & 0xFFFF; + case MP_GPIO_ISR_HI: + return s->isr >> 16; + + default: + return 0; + } +} + +static void musicpal_gpio_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + musicpal_gpio_state *s = opaque; + switch (offset) { + case MP_GPIO_OE_HI: /* used for LCD brightness control */ + s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) | + (value & MP_OE_LCD_BRIGHTNESS); + musicpal_gpio_brightness_update(s); + break; + + case MP_GPIO_OUT_LO: + s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF); + break; + case MP_GPIO_OUT_HI: + s->out_state = (s->out_state & 0xFFFF) | (value << 16); + s->lcd_brightness = (s->lcd_brightness & 0xFFFF) | + (s->out_state & MP_GPIO_LCD_BRIGHTNESS); + musicpal_gpio_brightness_update(s); + qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1); + qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); + break; + + case MP_GPIO_IER_LO: + s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF); + break; + case MP_GPIO_IER_HI: + s->ier = (s->ier & 0xFFFF) | (value << 16); + break; + + case MP_GPIO_IMR_LO: + s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF); + break; + case MP_GPIO_IMR_HI: + s->imr = (s->imr & 0xFFFF) | (value << 16); + break; + } +} + +static const MemoryRegionOps musicpal_gpio_ops = { + .read = musicpal_gpio_read, + .write = musicpal_gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void musicpal_gpio_reset(DeviceState *d) +{ + musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, + SYS_BUS_DEVICE(d)); + + s->lcd_brightness = 0; + s->out_state = 0; + s->in_state = 0xffffffff; + s->ier = 0; + s->imr = 0; + s->isr = 0; +} + +static int musicpal_gpio_init(SysBusDevice *dev) +{ + musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev); + + sysbus_init_irq(dev, &s->irq); + + memory_region_init_io(&s->iomem, &musicpal_gpio_ops, s, + "musicpal-gpio", MP_GPIO_SIZE); + sysbus_init_mmio(dev, &s->iomem); + + qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); + + qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32); + + return 0; +} + +static const VMStateDescription musicpal_gpio_vmsd = { + .name = "musicpal_gpio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state), + VMSTATE_UINT32(out_state, musicpal_gpio_state), + VMSTATE_UINT32(in_state, musicpal_gpio_state), + VMSTATE_UINT32(ier, musicpal_gpio_state), + VMSTATE_UINT32(imr, musicpal_gpio_state), + VMSTATE_UINT32(isr, musicpal_gpio_state), + VMSTATE_END_OF_LIST() + } +}; + +static void musicpal_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = musicpal_gpio_init; + dc->reset = musicpal_gpio_reset; + dc->vmsd = &musicpal_gpio_vmsd; +} + +static const TypeInfo musicpal_gpio_info = { + .name = "musicpal_gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(musicpal_gpio_state), + .class_init = musicpal_gpio_class_init, +}; + +/* Keyboard codes & masks */ +#define KEY_RELEASED 0x80 +#define KEY_CODE 0x7f + +#define KEYCODE_TAB 0x0f +#define KEYCODE_ENTER 0x1c +#define KEYCODE_F 0x21 +#define KEYCODE_M 0x32 + +#define KEYCODE_EXTENDED 0xe0 +#define KEYCODE_UP 0x48 +#define KEYCODE_DOWN 0x50 +#define KEYCODE_LEFT 0x4b +#define KEYCODE_RIGHT 0x4d + +#define MP_KEY_WHEEL_VOL (1 << 0) +#define MP_KEY_WHEEL_VOL_INV (1 << 1) +#define MP_KEY_WHEEL_NAV (1 << 2) +#define MP_KEY_WHEEL_NAV_INV (1 << 3) +#define MP_KEY_BTN_FAVORITS (1 << 4) +#define MP_KEY_BTN_MENU (1 << 5) +#define MP_KEY_BTN_VOLUME (1 << 6) +#define MP_KEY_BTN_NAVIGATION (1 << 7) + +typedef struct musicpal_key_state { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t kbd_extended; + uint32_t pressed_keys; + qemu_irq out[8]; +} musicpal_key_state; + +static void musicpal_key_event(void *opaque, int keycode) +{ + musicpal_key_state *s = opaque; + uint32_t event = 0; + int i; + + if (keycode == KEYCODE_EXTENDED) { + s->kbd_extended = 1; + return; + } + + if (s->kbd_extended) { + switch (keycode & KEY_CODE) { + case KEYCODE_UP: + event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV; + break; + + case KEYCODE_DOWN: + event = MP_KEY_WHEEL_NAV; + break; + + case KEYCODE_LEFT: + event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV; + break; + + case KEYCODE_RIGHT: + event = MP_KEY_WHEEL_VOL; + break; + } + } else { + switch (keycode & KEY_CODE) { + case KEYCODE_F: + event = MP_KEY_BTN_FAVORITS; + break; + + case KEYCODE_TAB: + event = MP_KEY_BTN_VOLUME; + break; + + case KEYCODE_ENTER: + event = MP_KEY_BTN_NAVIGATION; + break; + + case KEYCODE_M: + event = MP_KEY_BTN_MENU; + break; + } + /* Do not repeat already pressed buttons */ + if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { + event = 0; + } + } + + if (event) { + /* Raise GPIO pin first if repeating a key */ + if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { + for (i = 0; i <= 7; i++) { + if (event & (1 << i)) { + qemu_set_irq(s->out[i], 1); + } + } + } + for (i = 0; i <= 7; i++) { + if (event & (1 << i)) { + qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED)); + } + } + if (keycode & KEY_RELEASED) { + s->pressed_keys &= ~event; + } else { + s->pressed_keys |= event; + } + } + + s->kbd_extended = 0; +} + +static int musicpal_key_init(SysBusDevice *dev) +{ + musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev); + + memory_region_init(&s->iomem, "dummy", 0); + sysbus_init_mmio(dev, &s->iomem); + + s->kbd_extended = 0; + s->pressed_keys = 0; + + qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); + + qemu_add_kbd_event_handler(musicpal_key_event, s); + + return 0; +} + +static const VMStateDescription musicpal_key_vmsd = { + .name = "musicpal_key", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(kbd_extended, musicpal_key_state), + VMSTATE_UINT32(pressed_keys, musicpal_key_state), + VMSTATE_END_OF_LIST() + } +}; + +static void musicpal_key_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = musicpal_key_init; + dc->vmsd = &musicpal_key_vmsd; +} + +static const TypeInfo musicpal_key_info = { + .name = "musicpal_key", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(musicpal_key_state), + .class_init = musicpal_key_class_init, +}; + +static struct arm_boot_info musicpal_binfo = { + .loader_start = 0x0, + .board_id = 0x20e, +}; + +static void musicpal_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + ARMCPU *cpu; + qemu_irq *cpu_pic; + qemu_irq pic[32]; + DeviceState *dev; + DeviceState *i2c_dev; + DeviceState *lcd_dev; + DeviceState *key_dev; + DeviceState *wm8750_dev; + SysBusDevice *s; + i2c_bus *i2c; + int i; + unsigned long flash_size; + DriveInfo *dinfo; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); + + if (!cpu_model) { + cpu_model = "arm926"; + } + cpu = cpu_arm_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + cpu_pic = arm_pic_init_cpu(cpu); + + /* For now we use a fixed - the original - RAM size */ + memory_region_init_ram(ram, "musicpal.ram", MP_RAM_DEFAULT_SIZE); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, 0, ram); + + memory_region_init_ram(sram, "musicpal.sram", MP_SRAM_SIZE); + vmstate_register_ram_global(sram); + memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram); + + dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE, + cpu_pic[ARM_PIC_CPU_IRQ]); + for (i = 0; i < 32; i++) { + pic[i] = qdev_get_gpio_in(dev, i); + } + sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ], + pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ], + pic[MP_TIMER4_IRQ], NULL); + + if (serial_hds[0]) { + serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ], + 1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN); + } + if (serial_hds[1]) { + serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ], + 1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN); + } + + /* Register flash */ + dinfo = drive_get(IF_PFLASH, 0, 0); + if (dinfo) { + flash_size = bdrv_getlength(dinfo->bdrv); + if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 && + flash_size != 32*1024*1024) { + fprintf(stderr, "Invalid flash image size\n"); + exit(1); + } + + /* + * The original U-Boot accesses the flash at 0xFE000000 instead of + * 0xFF800000 (if there is 8 MB flash). So remap flash access if the + * image is smaller than 32 MB. + */ +#ifdef TARGET_WORDS_BIGENDIAN + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, + "musicpal.flash", flash_size, + dinfo->bdrv, 0x10000, + (flash_size + 0xffff) >> 16, + MP_FLASH_SIZE_MAX / flash_size, + 2, 0x00BF, 0x236D, 0x0000, 0x0000, + 0x5555, 0x2AAA, 1); +#else + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, + "musicpal.flash", flash_size, + dinfo->bdrv, 0x10000, + (flash_size + 0xffff) >> 16, + MP_FLASH_SIZE_MAX / flash_size, + 2, 0x00BF, 0x236D, 0x0000, 0x0000, + 0x5555, 0x2AAA, 0); +#endif + + } + sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL); + + qemu_check_nic_model(&nd_table[0], "mv88w8618"); + dev = qdev_create(NULL, "mv88w8618_eth"); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]); + + sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); + + musicpal_misc_init(SYS_BUS_DEVICE(dev)); + + dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); + i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); + i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"); + + lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); + key_dev = sysbus_create_simple("musicpal_key", -1, NULL); + + /* I2C read data */ + qdev_connect_gpio_out(i2c_dev, 0, + qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT)); + /* I2C data */ + qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0)); + /* I2C clock */ + qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1)); + + for (i = 0; i < 3; i++) { + qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i)); + } + for (i = 0; i < 4; i++) { + qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8)); + } + for (i = 4; i < 8; i++) { + qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); + } + + wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR); + dev = qdev_create(NULL, "mv88w8618_audio"); + s = SYS_BUS_DEVICE(dev); + qdev_prop_set_ptr(dev, "wm8750", wm8750_dev); + qdev_init_nofail(dev); + sysbus_mmio_map(s, 0, MP_AUDIO_BASE); + sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); + + musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; + musicpal_binfo.kernel_filename = kernel_filename; + musicpal_binfo.kernel_cmdline = kernel_cmdline; + musicpal_binfo.initrd_filename = initrd_filename; + arm_load_kernel(cpu, &musicpal_binfo); +} + +static QEMUMachine musicpal_machine = { + .name = "musicpal", + .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)", + .init = musicpal_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void musicpal_machine_init(void) +{ + qemu_register_machine(&musicpal_machine); +} + +machine_init(musicpal_machine_init); + +static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = mv88w8618_wlan_init; +} + +static const TypeInfo mv88w8618_wlan_info = { + .name = "mv88w8618_wlan", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = mv88w8618_wlan_class_init, +}; + +static void musicpal_register_types(void) +{ + type_register_static(&mv88w8618_pic_info); + type_register_static(&mv88w8618_pit_info); + type_register_static(&mv88w8618_flashcfg_info); + type_register_static(&mv88w8618_eth_info); + type_register_static(&mv88w8618_wlan_info); + type_register_static(&musicpal_lcd_info); + type_register_static(&musicpal_gpio_info); + type_register_static(&musicpal_key_info); +} + +type_init(musicpal_register_types) diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c new file mode 100644 index 0000000000..c5bf9f95b3 --- /dev/null +++ b/hw/arm/nseries.c @@ -0,0 +1,1430 @@ +/* + * Nokia N-series internet tablets. + * + * Copyright (C) 2007 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu-common.h" +#include "sysemu/sysemu.h" +#include "hw/omap.h" +#include "hw/arm-misc.h" +#include "hw/irq.h" +#include "ui/console.h" +#include "hw/boards.h" +#include "hw/i2c.h" +#include "hw/devices.h" +#include "hw/flash.h" +#include "hw/hw.h" +#include "hw/bt.h" +#include "hw/loader.h" +#include "sysemu/blockdev.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + +/* Nokia N8x0 support */ +struct n800_s { + struct omap_mpu_state_s *mpu; + + struct rfbi_chip_s blizzard; + struct { + void *opaque; + uint32_t (*txrx)(void *opaque, uint32_t value, int len); + uWireSlave *chip; + } ts; + + int keymap[0x80]; + DeviceState *kbd; + + DeviceState *usb; + void *retu; + void *tahvo; + DeviceState *nand; +}; + +/* GPIO pins */ +#define N8X0_TUSB_ENABLE_GPIO 0 +#define N800_MMC2_WP_GPIO 8 +#define N800_UNKNOWN_GPIO0 9 /* out */ +#define N810_MMC2_VIOSD_GPIO 9 +#define N810_HEADSET_AMP_GPIO 10 +#define N800_CAM_TURN_GPIO 12 +#define N810_GPS_RESET_GPIO 12 +#define N800_BLIZZARD_POWERDOWN_GPIO 15 +#define N800_MMC1_WP_GPIO 23 +#define N810_MMC2_VSD_GPIO 23 +#define N8X0_ONENAND_GPIO 26 +#define N810_BLIZZARD_RESET_GPIO 30 +#define N800_UNKNOWN_GPIO2 53 /* out */ +#define N8X0_TUSB_INT_GPIO 58 +#define N8X0_BT_WKUP_GPIO 61 +#define N8X0_STI_GPIO 62 +#define N8X0_CBUS_SEL_GPIO 64 +#define N8X0_CBUS_DAT_GPIO 65 +#define N8X0_CBUS_CLK_GPIO 66 +#define N8X0_WLAN_IRQ_GPIO 87 +#define N8X0_BT_RESET_GPIO 92 +#define N8X0_TEA5761_CS_GPIO 93 +#define N800_UNKNOWN_GPIO 94 +#define N810_TSC_RESET_GPIO 94 +#define N800_CAM_ACT_GPIO 95 +#define N810_GPS_WAKEUP_GPIO 95 +#define N8X0_MMC_CS_GPIO 96 +#define N8X0_WLAN_PWR_GPIO 97 +#define N8X0_BT_HOST_WKUP_GPIO 98 +#define N810_SPEAKER_AMP_GPIO 101 +#define N810_KB_LOCK_GPIO 102 +#define N800_TSC_TS_GPIO 103 +#define N810_TSC_TS_GPIO 106 +#define N8X0_HEADPHONE_GPIO 107 +#define N8X0_RETU_GPIO 108 +#define N800_TSC_KP_IRQ_GPIO 109 +#define N810_KEYBOARD_GPIO 109 +#define N800_BAT_COVER_GPIO 110 +#define N810_SLIDE_GPIO 110 +#define N8X0_TAHVO_GPIO 111 +#define N800_UNKNOWN_GPIO4 112 /* out */ +#define N810_SLEEPX_LED_GPIO 112 +#define N800_TSC_RESET_GPIO 118 /* ? */ +#define N810_AIC33_RESET_GPIO 118 +#define N800_TSC_UNKNOWN_GPIO 119 /* out */ +#define N8X0_TMP105_GPIO 125 + +/* Config */ +#define BT_UART 0 +#define XLDR_LL_UART 1 + +/* Addresses on the I2C bus 0 */ +#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */ +#define N8X0_TCM825x_ADDR 0x29 /* Camera */ +#define N810_LP5521_ADDR 0x32 /* LEDs */ +#define N810_TSL2563_ADDR 0x3d /* Light sensor */ +#define N810_LM8323_ADDR 0x45 /* Keyboard */ +/* Addresses on the I2C bus 1 */ +#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */ +#define N8X0_MENELAUS_ADDR 0x72 /* Power management */ + +/* Chipselects on GPMC NOR interface */ +#define N8X0_ONENAND_CS 0 +#define N8X0_USB_ASYNC_CS 1 +#define N8X0_USB_SYNC_CS 4 + +#define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81 + +static void n800_mmc_cs_cb(void *opaque, int line, int level) +{ + /* TODO: this seems to actually be connected to the menelaus, to + * which also both MMC slots connect. */ + omap_mmc_enable((struct omap_mmc_s *) opaque, !level); + + printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1); +} + +static void n8x0_gpio_setup(struct n800_s *s) +{ + qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]); + + qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO)); +} + +#define MAEMO_CAL_HEADER(...) \ + 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \ + __VA_ARGS__, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +static const uint8_t n8x0_cal_wlan_mac[] = { + MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c') + 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3, + 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, + 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, +}; + +static const uint8_t n8x0_cal_bt_id[] = { + MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0) + 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96, + 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00, + N8X0_BD_ADDR, +}; + +static void n8x0_nand_setup(struct n800_s *s) +{ + char *otp_region; + DriveInfo *dinfo; + + s->nand = qdev_create(NULL, "onenand"); + qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG); + /* Either 0x40 or 0x48 are OK for the device ID */ + qdev_prop_set_uint16(s->nand, "device_id", 0x48); + qdev_prop_set_uint16(s->nand, "version_id", 0); + qdev_prop_set_int32(s->nand, "shift", 1); + dinfo = drive_get(IF_MTD, 0, 0); + if (dinfo && dinfo->bdrv) { + qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv); + } + qdev_init_nofail(s->nand); + sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, + qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); + omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, + sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0)); + otp_region = onenand_raw_otp(s->nand); + + memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac)); + memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id)); + /* XXX: in theory should also update the OOB for both pages */ +} + +static qemu_irq n8x0_system_powerdown; + +static void n8x0_powerdown_req(Notifier *n, void *opaque) +{ + qemu_irq_raise(n8x0_system_powerdown); +} + +static Notifier n8x0_system_powerdown_notifier = { + .notify = n8x0_powerdown_req +}; + +static void n8x0_i2c_setup(struct n800_s *s) +{ + DeviceState *dev; + qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO); + i2c_bus *i2c = omap_i2c_bus(s->mpu->i2c[0]); + + /* Attach a menelaus PM chip */ + dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR); + qdev_connect_gpio_out(dev, 3, + qdev_get_gpio_in(s->mpu->ih[0], + OMAP_INT_24XX_SYS_NIRQ)); + + n8x0_system_powerdown = qdev_get_gpio_in(dev, 3); + qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier); + + /* Attach a TMP105 PM chip (A0 wired to ground) */ + dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR); + qdev_connect_gpio_out(dev, 0, tmp_irq); +} + +/* Touchscreen and keypad controller */ +static MouseTransformInfo n800_pointercal = { + .x = 800, + .y = 480, + .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, +}; + +static MouseTransformInfo n810_pointercal = { + .x = 800, + .y = 480, + .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 }, +}; + +#define RETU_KEYCODE 61 /* F3 */ + +static void n800_key_event(void *opaque, int keycode) +{ + struct n800_s *s = (struct n800_s *) opaque; + int code = s->keymap[keycode & 0x7f]; + + if (code == -1) { + if ((keycode & 0x7f) == RETU_KEYCODE) + retu_key_event(s->retu, !(keycode & 0x80)); + return; + } + + tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80)); +} + +static const int n800_keys[16] = { + -1, + 72, /* Up */ + 63, /* Home (F5) */ + -1, + 75, /* Left */ + 28, /* Enter */ + 77, /* Right */ + -1, + 1, /* Cycle (ESC) */ + 80, /* Down */ + 62, /* Menu (F4) */ + -1, + 66, /* Zoom- (F8) */ + 64, /* FullScreen (F6) */ + 65, /* Zoom+ (F7) */ + -1, +}; + +static void n800_tsc_kbd_setup(struct n800_s *s) +{ + int i; + + /* XXX: are the three pins inverted inside the chip between the + * tsc and the cpu (N4111)? */ + qemu_irq penirq = NULL; /* NC */ + qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO); + qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO); + + s->ts.chip = tsc2301_init(penirq, kbirq, dav); + s->ts.opaque = s->ts.chip->opaque; + s->ts.txrx = tsc210x_txrx; + + for (i = 0; i < 0x80; i ++) + s->keymap[i] = -1; + for (i = 0; i < 0x10; i ++) + if (n800_keys[i] >= 0) + s->keymap[n800_keys[i]] = i; + + qemu_add_kbd_event_handler(n800_key_event, s); + + tsc210x_set_transform(s->ts.chip, &n800_pointercal); +} + +static void n810_tsc_setup(struct n800_s *s) +{ + qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO); + + s->ts.opaque = tsc2005_init(pintdav); + s->ts.txrx = tsc2005_txrx; + + tsc2005_set_transform(s->ts.opaque, &n810_pointercal); +} + +/* N810 Keyboard controller */ +static void n810_key_event(void *opaque, int keycode) +{ + struct n800_s *s = (struct n800_s *) opaque; + int code = s->keymap[keycode & 0x7f]; + + if (code == -1) { + if ((keycode & 0x7f) == RETU_KEYCODE) + retu_key_event(s->retu, !(keycode & 0x80)); + return; + } + + lm832x_key_event(s->kbd, code, !(keycode & 0x80)); +} + +#define M 0 + +static int n810_keys[0x80] = { + [0x01] = 16, /* Q */ + [0x02] = 37, /* K */ + [0x03] = 24, /* O */ + [0x04] = 25, /* P */ + [0x05] = 14, /* Backspace */ + [0x06] = 30, /* A */ + [0x07] = 31, /* S */ + [0x08] = 32, /* D */ + [0x09] = 33, /* F */ + [0x0a] = 34, /* G */ + [0x0b] = 35, /* H */ + [0x0c] = 36, /* J */ + + [0x11] = 17, /* W */ + [0x12] = 62, /* Menu (F4) */ + [0x13] = 38, /* L */ + [0x14] = 40, /* ' (Apostrophe) */ + [0x16] = 44, /* Z */ + [0x17] = 45, /* X */ + [0x18] = 46, /* C */ + [0x19] = 47, /* V */ + [0x1a] = 48, /* B */ + [0x1b] = 49, /* N */ + [0x1c] = 42, /* Shift (Left shift) */ + [0x1f] = 65, /* Zoom+ (F7) */ + + [0x21] = 18, /* E */ + [0x22] = 39, /* ; (Semicolon) */ + [0x23] = 12, /* - (Minus) */ + [0x24] = 13, /* = (Equal) */ + [0x2b] = 56, /* Fn (Left Alt) */ + [0x2c] = 50, /* M */ + [0x2f] = 66, /* Zoom- (F8) */ + + [0x31] = 19, /* R */ + [0x32] = 29 | M, /* Right Ctrl */ + [0x34] = 57, /* Space */ + [0x35] = 51, /* , (Comma) */ + [0x37] = 72 | M, /* Up */ + [0x3c] = 82 | M, /* Compose (Insert) */ + [0x3f] = 64, /* FullScreen (F6) */ + + [0x41] = 20, /* T */ + [0x44] = 52, /* . (Dot) */ + [0x46] = 77 | M, /* Right */ + [0x4f] = 63, /* Home (F5) */ + [0x51] = 21, /* Y */ + [0x53] = 80 | M, /* Down */ + [0x55] = 28, /* Enter */ + [0x5f] = 1, /* Cycle (ESC) */ + + [0x61] = 22, /* U */ + [0x64] = 75 | M, /* Left */ + + [0x71] = 23, /* I */ +#if 0 + [0x75] = 28 | M, /* KP Enter (KP Enter) */ +#else + [0x75] = 15, /* KP Enter (Tab) */ +#endif +}; + +#undef M + +static void n810_kbd_setup(struct n800_s *s) +{ + qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO); + int i; + + for (i = 0; i < 0x80; i ++) + s->keymap[i] = -1; + for (i = 0; i < 0x80; i ++) + if (n810_keys[i] > 0) + s->keymap[n810_keys[i]] = i; + + qemu_add_kbd_event_handler(n810_key_event, s); + + /* Attach the LM8322 keyboard to the I2C bus, + * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ + s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]), + "lm8323", N810_LM8323_ADDR); + qdev_connect_gpio_out(s->kbd, 0, kbd_irq); +} + +/* LCD MIPI DBI-C controller (URAL) */ +struct mipid_s { + int resp[4]; + int param[4]; + int p; + int pm; + int cmd; + + int sleep; + int booster; + int te; + int selfcheck; + int partial; + int normal; + int vscr; + int invert; + int onoff; + int gamma; + uint32_t id; +}; + +static void mipid_reset(struct mipid_s *s) +{ + if (!s->sleep) + fprintf(stderr, "%s: Display off\n", __FUNCTION__); + + s->pm = 0; + s->cmd = 0; + + s->sleep = 1; + s->booster = 0; + s->selfcheck = + (1 << 7) | /* Register loading OK. */ + (1 << 5) | /* The chip is attached. */ + (1 << 4); /* Display glass still in one piece. */ + s->te = 0; + s->partial = 0; + s->normal = 1; + s->vscr = 0; + s->invert = 0; + s->onoff = 1; + s->gamma = 0; +} + +static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) +{ + struct mipid_s *s = (struct mipid_s *) opaque; + uint8_t ret; + + if (len > 9) + hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len); + + if (s->p >= ARRAY_SIZE(s->resp)) + ret = 0; + else + ret = s->resp[s->p ++]; + if (s->pm --> 0) + s->param[s->pm] = cmd; + else + s->cmd = cmd; + + switch (s->cmd) { + case 0x00: /* NOP */ + break; + + case 0x01: /* SWRESET */ + mipid_reset(s); + break; + + case 0x02: /* BSTROFF */ + s->booster = 0; + break; + case 0x03: /* BSTRON */ + s->booster = 1; + break; + + case 0x04: /* RDDID */ + s->p = 0; + s->resp[0] = (s->id >> 16) & 0xff; + s->resp[1] = (s->id >> 8) & 0xff; + s->resp[2] = (s->id >> 0) & 0xff; + break; + + case 0x06: /* RD_RED */ + case 0x07: /* RD_GREEN */ + /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so + * for the bootloader one needs to change this. */ + case 0x08: /* RD_BLUE */ + s->p = 0; + /* TODO: return first pixel components */ + s->resp[0] = 0x01; + break; + + case 0x09: /* RDDST */ + s->p = 0; + s->resp[0] = s->booster << 7; + s->resp[1] = (5 << 4) | (s->partial << 2) | + (s->sleep << 1) | s->normal; + s->resp[2] = (s->vscr << 7) | (s->invert << 5) | + (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2); + s->resp[3] = s->gamma << 6; + break; + + case 0x0a: /* RDDPM */ + s->p = 0; + s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) | + (s->partial << 5) | (s->sleep << 6) | (s->booster << 7); + break; + case 0x0b: /* RDDMADCTR */ + s->p = 0; + s->resp[0] = 0; + break; + case 0x0c: /* RDDCOLMOD */ + s->p = 0; + s->resp[0] = 5; /* 65K colours */ + break; + case 0x0d: /* RDDIM */ + s->p = 0; + s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma; + break; + case 0x0e: /* RDDSM */ + s->p = 0; + s->resp[0] = s->te << 7; + break; + case 0x0f: /* RDDSDR */ + s->p = 0; + s->resp[0] = s->selfcheck; + break; + + case 0x10: /* SLPIN */ + s->sleep = 1; + break; + case 0x11: /* SLPOUT */ + s->sleep = 0; + s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */ + break; + + case 0x12: /* PTLON */ + s->partial = 1; + s->normal = 0; + s->vscr = 0; + break; + case 0x13: /* NORON */ + s->partial = 0; + s->normal = 1; + s->vscr = 0; + break; + + case 0x20: /* INVOFF */ + s->invert = 0; + break; + case 0x21: /* INVON */ + s->invert = 1; + break; + + case 0x22: /* APOFF */ + case 0x23: /* APON */ + goto bad_cmd; + + case 0x25: /* WRCNTR */ + if (s->pm < 0) + s->pm = 1; + goto bad_cmd; + + case 0x26: /* GAMSET */ + if (!s->pm) + s->gamma = ffs(s->param[0] & 0xf) - 1; + else if (s->pm < 0) + s->pm = 1; + break; + + case 0x28: /* DISPOFF */ + s->onoff = 0; + fprintf(stderr, "%s: Display off\n", __FUNCTION__); + break; + case 0x29: /* DISPON */ + s->onoff = 1; + fprintf(stderr, "%s: Display on\n", __FUNCTION__); + break; + + case 0x2a: /* CASET */ + case 0x2b: /* RASET */ + case 0x2c: /* RAMWR */ + case 0x2d: /* RGBSET */ + case 0x2e: /* RAMRD */ + case 0x30: /* PTLAR */ + case 0x33: /* SCRLAR */ + goto bad_cmd; + + case 0x34: /* TEOFF */ + s->te = 0; + break; + case 0x35: /* TEON */ + if (!s->pm) + s->te = 1; + else if (s->pm < 0) + s->pm = 1; + break; + + case 0x36: /* MADCTR */ + goto bad_cmd; + + case 0x37: /* VSCSAD */ + s->partial = 0; + s->normal = 0; + s->vscr = 1; + break; + + case 0x38: /* IDMOFF */ + case 0x39: /* IDMON */ + case 0x3a: /* COLMOD */ + goto bad_cmd; + + case 0xb0: /* CLKINT / DISCTL */ + case 0xb1: /* CLKEXT */ + if (s->pm < 0) + s->pm = 2; + break; + + case 0xb4: /* FRMSEL */ + break; + + case 0xb5: /* FRM8SEL */ + case 0xb6: /* TMPRNG / INIESC */ + case 0xb7: /* TMPHIS / NOP2 */ + case 0xb8: /* TMPREAD / MADCTL */ + case 0xba: /* DISTCTR */ + case 0xbb: /* EPVOL */ + goto bad_cmd; + + case 0xbd: /* Unknown */ + s->p = 0; + s->resp[0] = 0; + s->resp[1] = 1; + break; + + case 0xc2: /* IFMOD */ + if (s->pm < 0) + s->pm = 2; + break; + + case 0xc6: /* PWRCTL */ + case 0xc7: /* PPWRCTL */ + case 0xd0: /* EPWROUT */ + case 0xd1: /* EPWRIN */ + case 0xd4: /* RDEV */ + case 0xd5: /* RDRR */ + goto bad_cmd; + + case 0xda: /* RDID1 */ + s->p = 0; + s->resp[0] = (s->id >> 16) & 0xff; + break; + case 0xdb: /* RDID2 */ + s->p = 0; + s->resp[0] = (s->id >> 8) & 0xff; + break; + case 0xdc: /* RDID3 */ + s->p = 0; + s->resp[0] = (s->id >> 0) & 0xff; + break; + + default: + bad_cmd: + fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd); + break; + } + + return ret; +} + +static void *mipid_init(void) +{ + struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s)); + + s->id = 0x838f03; + mipid_reset(s); + + return s; +} + +static void n8x0_spi_setup(struct n800_s *s) +{ + void *tsc = s->ts.opaque; + void *mipid = mipid_init(); + + omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0); + omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1); +} + +/* This task is normally performed by the bootloader. If we're loading + * a kernel directly, we need to enable the Blizzard ourselves. */ +static void n800_dss_init(struct rfbi_chip_s *chip) +{ + uint8_t *fb_blank; + + chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */ + chip->write(chip->opaque, 1, 0x64); + chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */ + chip->write(chip->opaque, 1, 0x1e); + chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */ + chip->write(chip->opaque, 1, 0xe0); + chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */ + chip->write(chip->opaque, 1, 0x01); + chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */ + chip->write(chip->opaque, 1, 0x06); + chip->write(chip->opaque, 0, 0x68); /* Display Mode register */ + chip->write(chip->opaque, 1, 1); /* Enable bit */ + + chip->write(chip->opaque, 0, 0x6c); + chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ + chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */ + chip->write(chip->opaque, 1, 0x03); /* Input X End Position */ + chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */ + chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */ + chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ + chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ + chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */ + chip->write(chip->opaque, 1, 0x03); /* Output X End Position */ + chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */ + chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */ + chip->write(chip->opaque, 1, 0x01); /* Input Data Format */ + chip->write(chip->opaque, 1, 0x01); /* Data Source Select */ + + fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2); + /* Display Memory Data Port */ + chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800); + g_free(fb_blank); +} + +static void n8x0_dss_setup(struct n800_s *s) +{ + s->blizzard.opaque = s1d13745_init(NULL); + s->blizzard.block = s1d13745_write_block; + s->blizzard.write = s1d13745_write; + s->blizzard.read = s1d13745_read; + + omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard); +} + +static void n8x0_cbus_setup(struct n800_s *s) +{ + qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO); + qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO); + qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO); + + CBus *cbus = cbus_init(dat_out); + + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel); + + cbus_attach(cbus, s->retu = retu_init(retu_irq, 1)); + cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1)); +} + +static void n8x0_uart_setup(struct n800_s *s) +{ + CharDriverState *radio = uart_hci_init( + qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); + + qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO, + csrhci_pins_get(radio)[csrhci_pin_reset]); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO, + csrhci_pins_get(radio)[csrhci_pin_wakeup]); + + omap_uart_attach(s->mpu->uart[BT_UART], radio); +} + +static void n8x0_usb_setup(struct n800_s *s) +{ + SysBusDevice *dev; + s->usb = qdev_create(NULL, "tusb6010"); + dev = SYS_BUS_DEVICE(s->usb); + qdev_init_nofail(s->usb); + sysbus_connect_irq(dev, 0, + qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); + /* Using the NOR interface */ + omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS, + sysbus_mmio_get_region(dev, 0)); + omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS, + sysbus_mmio_get_region(dev, 1)); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO, + qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */ +} + +/* Setup done before the main bootloader starts by some early setup code + * - used when we want to run the main bootloader in emulation. This + * isn't documented. */ +static uint32_t n800_pinout[104] = { + 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, + 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, + 0x08080808, 0x180800c4, 0x00b80000, 0x08080808, + 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128, + 0x01241800, 0x18181818, 0x000000f0, 0x01300000, + 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b, + 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080, + 0x007c0000, 0x00000000, 0x00000088, 0x00840000, + 0x00000000, 0x00000094, 0x00980300, 0x0f180003, + 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c, + 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008, + 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f, + 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc, + 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008, + 0x00000000, 0x00000038, 0x00340000, 0x00000000, + 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060, + 0x005c0808, 0x08080808, 0x08080058, 0x00540808, + 0x08080808, 0x0808006c, 0x00680808, 0x08080808, + 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0, + 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808, + 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff, + 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100, + 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a, + 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00, + 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118, + 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b, +}; + +static void n800_setup_nolo_tags(void *sram_base) +{ + int i; + uint32_t *p = sram_base + 0x8000; + uint32_t *v = sram_base + 0xa000; + + memset(p, 0, 0x3000); + + strcpy((void *) (p + 0), "QEMU N800"); + + strcpy((void *) (p + 8), "F5"); + + stl_raw(p + 10, 0x04f70000); + strcpy((void *) (p + 9), "RX-34"); + + /* RAM size in MB? */ + stl_raw(p + 12, 0x80); + + /* Pointer to the list of tags */ + stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000); + + /* The NOLO tags start here */ + p = sram_base + 0x9000; +#define ADD_TAG(tag, len) \ + stw_raw((uint16_t *) p + 0, tag); \ + stw_raw((uint16_t *) p + 1, len); p ++; \ + stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff)); + + /* OMAP STI console? Pin out settings? */ + ADD_TAG(0x6e01, 414); + for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++) + stl_raw(v ++, n800_pinout[i]); + + /* Kernel memsize? */ + ADD_TAG(0x6e05, 1); + stl_raw(v ++, 2); + + /* NOLO serial console */ + ADD_TAG(0x6e02, 4); + stl_raw(v ++, XLDR_LL_UART); /* UART number (1 - 3) */ + +#if 0 + /* CBUS settings (Retu/AVilma) */ + ADD_TAG(0x6e03, 6); + stw_raw((uint16_t *) v + 0, 65); /* CBUS GPIO0 */ + stw_raw((uint16_t *) v + 1, 66); /* CBUS GPIO1 */ + stw_raw((uint16_t *) v + 2, 64); /* CBUS GPIO2 */ + v += 2; +#endif + + /* Nokia ASIC BB5 (Retu/Tahvo) */ + ADD_TAG(0x6e0a, 4); + stw_raw((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */ + stw_raw((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */ + v ++; + + /* LCD console? */ + ADD_TAG(0x6e04, 4); + stw_raw((uint16_t *) v + 0, 30); /* ??? */ + stw_raw((uint16_t *) v + 1, 24); /* ??? */ + v ++; + +#if 0 + /* LCD settings */ + ADD_TAG(0x6e06, 2); + stw_raw((uint16_t *) (v ++), 15); /* ??? */ +#endif + + /* I^2C (Menelaus) */ + ADD_TAG(0x6e07, 4); + stl_raw(v ++, 0x00720000); /* ??? */ + + /* Unknown */ + ADD_TAG(0x6e0b, 6); + stw_raw((uint16_t *) v + 0, 94); /* ??? */ + stw_raw((uint16_t *) v + 1, 23); /* ??? */ + stw_raw((uint16_t *) v + 2, 0); /* ??? */ + v += 2; + + /* OMAP gpio switch info */ + ADD_TAG(0x6e0c, 80); + strcpy((void *) v, "bat_cover"); v += 3; + stw_raw((uint16_t *) v + 0, 110); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 1); /* GPIO num ??? */ + v += 2; + strcpy((void *) v, "cam_act"); v += 3; + stw_raw((uint16_t *) v + 0, 95); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 32); /* GPIO num ??? */ + v += 2; + strcpy((void *) v, "cam_turn"); v += 3; + stw_raw((uint16_t *) v + 0, 12); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 33); /* GPIO num ??? */ + v += 2; + strcpy((void *) v, "headphone"); v += 3; + stw_raw((uint16_t *) v + 0, 107); /* GPIO num ??? */ + stw_raw((uint16_t *) v + 1, 17); /* GPIO num ??? */ + v += 2; + + /* Bluetooth */ + ADD_TAG(0x6e0e, 12); + stl_raw(v ++, 0x5c623d01); /* ??? */ + stl_raw(v ++, 0x00000201); /* ??? */ + stl_raw(v ++, 0x00000000); /* ??? */ + + /* CX3110x WLAN settings */ + ADD_TAG(0x6e0f, 8); + stl_raw(v ++, 0x00610025); /* ??? */ + stl_raw(v ++, 0xffff0057); /* ??? */ + + /* MMC host settings */ + ADD_TAG(0x6e10, 12); + stl_raw(v ++, 0xffff000f); /* ??? */ + stl_raw(v ++, 0xffffffff); /* ??? */ + stl_raw(v ++, 0x00000060); /* ??? */ + + /* OneNAND chip select */ + ADD_TAG(0x6e11, 10); + stl_raw(v ++, 0x00000401); /* ??? */ + stl_raw(v ++, 0x0002003a); /* ??? */ + stl_raw(v ++, 0x00000002); /* ??? */ + + /* TEA5761 sensor settings */ + ADD_TAG(0x6e12, 2); + stl_raw(v ++, 93); /* GPIO num ??? */ + +#if 0 + /* Unknown tag */ + ADD_TAG(6e09, 0); + + /* Kernel UART / console */ + ADD_TAG(6e12, 0); +#endif + + /* End of the list */ + stl_raw(p ++, 0x00000000); + stl_raw(p ++, 0x00000000); +} + +/* This task is normally performed by the bootloader. If we're loading + * a kernel directly, we need to set up GPMC mappings ourselves. */ +static void n800_gpmc_init(struct n800_s *s) +{ + uint32_t config7 = + (0xf << 8) | /* MASKADDRESS */ + (1 << 6) | /* CSVALID */ + (4 << 0); /* BASEADDRESS */ + + cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */ + (void *) &config7, sizeof(config7)); +} + +/* Setup sequence done by the bootloader */ +static void n8x0_boot_init(void *opaque) +{ + struct n800_s *s = (struct n800_s *) opaque; + uint32_t buf; + + /* PRCM setup */ +#define omap_writel(addr, val) \ + buf = (val); \ + cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf)) + + omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */ + omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */ + omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */ + omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */ + omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */ + omap_writel(0x48008098, 0); /* PRCM_POLCTRL */ + omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */ + omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */ + omap_writel(0x48008158, 1); /* RM_RSTST_MPU */ + omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */ + omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */ + omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */ + omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */ + omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */ + omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */ + omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */ + omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */ + omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */ + omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */ + omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */ + omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */ + omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */ + omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */ + omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */ + omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */ + omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */ + omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */ + omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */ + omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */ + omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */ + omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */ + omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */ + omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */ + omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */ + omap_writel(0x48008540, /* CM_CLKSEL1_PLL */ + (0x78 << 12) | (6 << 8)); + omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */ + + /* GPMC setup */ + n800_gpmc_init(s); + + /* Video setup */ + n800_dss_init(&s->blizzard); + + /* CPU setup */ + s->mpu->cpu->env.GE = 0x5; + + /* If the machine has a slided keyboard, open it */ + if (s->kbd) + qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO)); +} + +#define OMAP_TAG_NOKIA_BT 0x4e01 +#define OMAP_TAG_WLAN_CX3110X 0x4e02 +#define OMAP_TAG_CBUS 0x4e03 +#define OMAP_TAG_EM_ASIC_BB5 0x4e04 + +static struct omap_gpiosw_info_s { + const char *name; + int line; + int type; +} n800_gpiosw_info[] = { + { + "bat_cover", N800_BAT_COVER_GPIO, + OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, + }, { + "cam_act", N800_CAM_ACT_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY, + }, { + "cam_turn", N800_CAM_TURN_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED, + }, { + "headphone", N8X0_HEADPHONE_GPIO, + OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, + }, + { NULL } +}, n810_gpiosw_info[] = { + { + "gps_reset", N810_GPS_RESET_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, + }, { + "gps_wakeup", N810_GPS_WAKEUP_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, + }, { + "headphone", N8X0_HEADPHONE_GPIO, + OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, + }, { + "kb_lock", N810_KB_LOCK_GPIO, + OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, + }, { + "sleepx_led", N810_SLEEPX_LED_GPIO, + OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT, + }, { + "slide", N810_SLIDE_GPIO, + OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, + }, + { NULL } +}; + +static struct omap_partition_info_s { + uint32_t offset; + uint32_t size; + int mask; + const char *name; +} n800_part_info[] = { + { 0x00000000, 0x00020000, 0x3, "bootloader" }, + { 0x00020000, 0x00060000, 0x0, "config" }, + { 0x00080000, 0x00200000, 0x0, "kernel" }, + { 0x00280000, 0x00200000, 0x3, "initfs" }, + { 0x00480000, 0x0fb80000, 0x3, "rootfs" }, + + { 0, 0, 0, NULL } +}, n810_part_info[] = { + { 0x00000000, 0x00020000, 0x3, "bootloader" }, + { 0x00020000, 0x00060000, 0x0, "config" }, + { 0x00080000, 0x00220000, 0x0, "kernel" }, + { 0x002a0000, 0x00400000, 0x0, "initfs" }, + { 0x006a0000, 0x0f960000, 0x0, "rootfs" }, + + { 0, 0, 0, NULL } +}; + +static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }}; + +static int n8x0_atag_setup(void *p, int model) +{ + uint8_t *b; + uint16_t *w; + uint32_t *l; + struct omap_gpiosw_info_s *gpiosw; + struct omap_partition_info_s *partition; + const char *tag; + + w = p; + + stw_raw(w ++, OMAP_TAG_UART); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ + w ++; + +#if 0 + stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, XLDR_LL_UART + 1); /* u8 console_uart */ + stw_raw(w ++, 115200); /* u32 console_speed */ +#endif + + stw_raw(w ++, OMAP_TAG_LCD); /* u16 tag */ + stw_raw(w ++, 36); /* u16 len */ + strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */ + w += 8; + strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */ + w += 8; + stw_raw(w ++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */ + stw_raw(w ++, 24); /* u8 data_lines */ + + stw_raw(w ++, OMAP_TAG_CBUS); /* u16 tag */ + stw_raw(w ++, 8); /* u16 len */ + stw_raw(w ++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */ + stw_raw(w ++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */ + stw_raw(w ++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */ + w ++; + + stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */ + stw_raw(w ++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */ + + gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info; + for (; gpiosw->name; gpiosw ++) { + stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ + stw_raw(w ++, 20); /* u16 len */ + strcpy((void *) w, gpiosw->name); /* char name[12] */ + w += 6; + stw_raw(w ++, gpiosw->line); /* u16 gpio */ + stw_raw(w ++, gpiosw->type); + stw_raw(w ++, 0); + stw_raw(w ++, 0); + } + + stw_raw(w ++, OMAP_TAG_NOKIA_BT); /* u16 tag */ + stw_raw(w ++, 12); /* u16 len */ + b = (void *) w; + stb_raw(b ++, 0x01); /* u8 chip_type (CSR) */ + stb_raw(b ++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */ + stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */ + stb_raw(b ++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */ + stb_raw(b ++, BT_UART + 1); /* u8 bt_uart */ + memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */ + b += 6; + stb_raw(b ++, 0x02); /* u8 bt_sysclk (38.4) */ + w = (void *) b; + + stw_raw(w ++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */ + stw_raw(w ++, 8); /* u16 len */ + stw_raw(w ++, 0x25); /* u8 chip_type */ + stw_raw(w ++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */ + stw_raw(w ++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */ + stw_raw(w ++, -1); /* s16 spi_cs_gpio */ + + stw_raw(w ++, OMAP_TAG_MMC); /* u16 tag */ + stw_raw(w ++, 16); /* u16 len */ + if (model == 810) { + stw_raw(w ++, 0x23f); /* unsigned flags */ + stw_raw(w ++, -1); /* s16 power_pin */ + stw_raw(w ++, -1); /* s16 switch_pin */ + stw_raw(w ++, -1); /* s16 wp_pin */ + stw_raw(w ++, 0x240); /* unsigned flags */ + stw_raw(w ++, 0xc000); /* s16 power_pin */ + stw_raw(w ++, 0x0248); /* s16 switch_pin */ + stw_raw(w ++, 0xc000); /* s16 wp_pin */ + } else { + stw_raw(w ++, 0xf); /* unsigned flags */ + stw_raw(w ++, -1); /* s16 power_pin */ + stw_raw(w ++, -1); /* s16 switch_pin */ + stw_raw(w ++, -1); /* s16 wp_pin */ + stw_raw(w ++, 0); /* unsigned flags */ + stw_raw(w ++, 0); /* s16 power_pin */ + stw_raw(w ++, 0); /* s16 switch_pin */ + stw_raw(w ++, 0); /* s16 wp_pin */ + } + + stw_raw(w ++, OMAP_TAG_TEA5761); /* u16 tag */ + stw_raw(w ++, 4); /* u16 len */ + stw_raw(w ++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */ + w ++; + + partition = (model == 810) ? n810_part_info : n800_part_info; + for (; partition->name; partition ++) { + stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ + stw_raw(w ++, 28); /* u16 len */ + strcpy((void *) w, partition->name); /* char name[16] */ + l = (void *) (w + 8); + stl_raw(l ++, partition->size); /* unsigned int size */ + stl_raw(l ++, partition->offset); /* unsigned int offset */ + stl_raw(l ++, partition->mask); /* unsigned int mask_flags */ + w = (void *) l; + } + + stw_raw(w ++, OMAP_TAG_BOOT_REASON); /* u16 tag */ + stw_raw(w ++, 12); /* u16 len */ +#if 0 + strcpy((void *) w, "por"); /* char reason_str[12] */ + strcpy((void *) w, "charger"); /* char reason_str[12] */ + strcpy((void *) w, "32wd_to"); /* char reason_str[12] */ + strcpy((void *) w, "sw_rst"); /* char reason_str[12] */ + strcpy((void *) w, "mbus"); /* char reason_str[12] */ + strcpy((void *) w, "unknown"); /* char reason_str[12] */ + strcpy((void *) w, "swdg_to"); /* char reason_str[12] */ + strcpy((void *) w, "sec_vio"); /* char reason_str[12] */ + strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ + strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */ +#else + strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ +#endif + w += 6; + + tag = (model == 810) ? "RX-44" : "RX-34"; + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ + stw_raw(w ++, 24); /* u16 len */ + strcpy((void *) w, "product"); /* char component[12] */ + w += 6; + strcpy((void *) w, tag); /* char version[12] */ + w += 6; + + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ + stw_raw(w ++, 24); /* u16 len */ + strcpy((void *) w, "hw-build"); /* char component[12] */ + w += 6; + strcpy((void *) w, "QEMU "); + pstrcat((void *) w, 12, qemu_get_version()); /* char version[12] */ + w += 6; + + tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu"; + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ + stw_raw(w ++, 24); /* u16 len */ + strcpy((void *) w, "nolo"); /* char component[12] */ + w += 6; + strcpy((void *) w, tag); /* char version[12] */ + w += 6; + + return (void *) w - p; +} + +static int n800_atag_setup(const struct arm_boot_info *info, void *p) +{ + return n8x0_atag_setup(p, 800); +} + +static int n810_atag_setup(const struct arm_boot_info *info, void *p) +{ + return n8x0_atag_setup(p, 810); +} + +static void n8x0_init(QEMUMachineInitArgs *args, + struct arm_boot_info *binfo, int model) +{ + MemoryRegion *sysmem = get_system_memory(); + struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); + int sdram_size = binfo->ram_size; + DisplayState *ds; + + s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model); + + /* Setup peripherals + * + * Believed external peripherals layout in the N810: + * (spi bus 1) + * tsc2005 + * lcd_mipid + * (spi bus 2) + * Conexant cx3110x (WLAN) + * optional: pc2400m (WiMAX) + * (i2c bus 0) + * TLV320AIC33 (audio codec) + * TCM825x (camera by Toshiba) + * lp5521 (clever LEDs) + * tsl2563 (light sensor, hwmon, model 7, rev. 0) + * lm8323 (keypad, manf 00, rev 04) + * (i2c bus 1) + * tmp105 (temperature sensor, hwmon) + * menelaus (pm) + * (somewhere on i2c - maybe N800-only) + * tea5761 (FM tuner) + * (serial 0) + * GPS + * (some serial port) + * csr41814 (Bluetooth) + */ + n8x0_gpio_setup(s); + n8x0_nand_setup(s); + n8x0_i2c_setup(s); + if (model == 800) + n800_tsc_kbd_setup(s); + else if (model == 810) { + n810_tsc_setup(s); + n810_kbd_setup(s); + } + n8x0_spi_setup(s); + n8x0_dss_setup(s); + n8x0_cbus_setup(s); + n8x0_uart_setup(s); + if (usb_enabled(false)) { + n8x0_usb_setup(s); + } + + if (args->kernel_filename) { + /* Or at the linux loader. */ + binfo->kernel_filename = args->kernel_filename; + binfo->kernel_cmdline = args->kernel_cmdline; + binfo->initrd_filename = args->initrd_filename; + arm_load_kernel(s->mpu->cpu, binfo); + + qemu_register_reset(n8x0_boot_init, s); + } + + if (option_rom[0].name && + (args->boot_device[0] == 'n' || !args->kernel_filename)) { + int rom_size; + uint8_t nolo_tags[0x10000]; + /* No, wait, better start at the ROM. */ + s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; + + /* This is intended for loading the `secondary.bin' program from + * Nokia images (the NOLO bootloader). The entry point seems + * to be at OMAP2_Q2_BASE + 0x400000. + * + * The `2nd.bin' files contain some kind of earlier boot code and + * for them the entry point needs to be set to OMAP2_SRAM_BASE. + * + * The code above is for loading the `zImage' file from Nokia + * images. */ + rom_size = load_image_targphys(option_rom[0].name, + OMAP2_Q2_BASE + 0x400000, + sdram_size - 0x400000); + printf("%i bytes of image loaded\n", rom_size); + + n800_setup_nolo_tags(nolo_tags); + cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000); + } + /* FIXME: We shouldn't really be doing this here. The LCD controller + will set the size once configured, so this just sets an initial + size until the guest activates the display. */ + ds = get_displaystate(); + ds->surface = qemu_resize_displaysurface(ds, 800, 480); + dpy_gfx_resize(ds); +} + +static struct arm_boot_info n800_binfo = { + .loader_start = OMAP2_Q2_BASE, + /* Actually two chips of 0x4000000 bytes each */ + .ram_size = 0x08000000, + .board_id = 0x4f7, + .atag_board = n800_atag_setup, +}; + +static struct arm_boot_info n810_binfo = { + .loader_start = OMAP2_Q2_BASE, + /* Actually two chips of 0x4000000 bytes each */ + .ram_size = 0x08000000, + /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not + * used by some older versions of the bootloader and 5555 is used + * instead (including versions that shipped with many devices). */ + .board_id = 0x60c, + .atag_board = n810_atag_setup, +}; + +static void n800_init(QEMUMachineInitArgs *args) +{ + return n8x0_init(args, &n800_binfo, 800); +} + +static void n810_init(QEMUMachineInitArgs *args) +{ + return n8x0_init(args, &n810_binfo, 810); +} + +static QEMUMachine n800_machine = { + .name = "n800", + .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)", + .init = n800_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine n810_machine = { + .name = "n810", + .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)", + .init = n810_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void nseries_machine_init(void) +{ + qemu_register_machine(&n800_machine); + qemu_register_machine(&n810_machine); +} + +machine_init(nseries_machine_init); diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c new file mode 100644 index 0000000000..85982334bd --- /dev/null +++ b/hw/arm/omap_sx1.c @@ -0,0 +1,238 @@ +/* omap_sx1.c Support for the Siemens SX1 smartphone emulation. + * + * Copyright (C) 2008 + * Jean-Christophe PLAGNIOL-VILLARD + * Copyright (C) 2007 Vladimir Ananiev + * + * based on PalmOne's (TM) PDAs support (palm.c) + */ + +/* + * PalmOne's (TM) PDAs. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "hw/hw.h" +#include "ui/console.h" +#include "hw/omap.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" +#include "hw/flash.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +/*****************************************************************************/ +/* Siemens SX1 Cellphone V1 */ +/* - ARM OMAP310 processor + * - SRAM 192 kB + * - SDRAM 32 MB at 0x10000000 + * - Boot flash 16 MB at 0x00000000 + * - Application flash 8 MB at 0x04000000 + * - 3 serial ports + * - 1 SecureDigital + * - 1 LCD display + * - 1 RTC + */ + +/*****************************************************************************/ +/* Siemens SX1 Cellphone V2 */ +/* - ARM OMAP310 processor + * - SRAM 192 kB + * - SDRAM 32 MB at 0x10000000 + * - Boot flash 32 MB at 0x00000000 + * - 3 serial ports + * - 1 SecureDigital + * - 1 LCD display + * - 1 RTC + */ + +static uint64_t static_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint32_t *val = (uint32_t *) opaque; + uint32_t mask = (4 / size) - 1; + + return *val >> ((offset & mask) << 3); +} + +static void static_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +#ifdef SPY + printf("%s: value %" PRIx64 " %u bytes written at 0x%x\n", + __func__, value, size, (int)offset); +#endif +} + +static const MemoryRegionOps static_ops = { + .read = static_read, + .write = static_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +#define sdram_size 0x02000000 +#define sector_size (128 * 1024) +#define flash0_size (16 * 1024 * 1024) +#define flash1_size ( 8 * 1024 * 1024) +#define flash2_size (32 * 1024 * 1024) +#define total_ram_v1 (sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE) +#define total_ram_v2 (sdram_size + flash2_size + OMAP15XX_SRAM_SIZE) + +static struct arm_boot_info sx1_binfo = { + .loader_start = OMAP_EMIFF_BASE, + .ram_size = sdram_size, + .board_id = 0x265, +}; + +static void sx1_init(QEMUMachineInitArgs *args, const int version) +{ + struct omap_mpu_state_s *mpu; + MemoryRegion *address_space = get_system_memory(); + MemoryRegion *flash = g_new(MemoryRegion, 1); + MemoryRegion *flash_1 = g_new(MemoryRegion, 1); + MemoryRegion *cs = g_new(MemoryRegion, 4); + static uint32_t cs0val = 0x00213090; + static uint32_t cs1val = 0x00215070; + static uint32_t cs2val = 0x00001139; + static uint32_t cs3val = 0x00001139; + DriveInfo *dinfo; + int fl_idx; + uint32_t flash_size = flash0_size; + int be; + + if (version == 2) { + flash_size = flash2_size; + } + + mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model); + + /* External Flash (EMIFS) */ + memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size); + vmstate_register_ram_global(flash); + memory_region_set_readonly(flash, true); + memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash); + + memory_region_init_io(&cs[0], &static_ops, &cs0val, + "sx1.cs0", OMAP_CS0_SIZE - flash_size); + memory_region_add_subregion(address_space, + OMAP_CS0_BASE + flash_size, &cs[0]); + + + memory_region_init_io(&cs[2], &static_ops, &cs2val, + "sx1.cs2", OMAP_CS2_SIZE); + memory_region_add_subregion(address_space, + OMAP_CS2_BASE, &cs[2]); + + memory_region_init_io(&cs[3], &static_ops, &cs3val, + "sx1.cs3", OMAP_CS3_SIZE); + memory_region_add_subregion(address_space, + OMAP_CS2_BASE, &cs[3]); + + fl_idx = 0; +#ifdef TARGET_WORDS_BIGENDIAN + be = 1; +#else + be = 0; +#endif + + if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { + if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL, + "omap_sx1.flash0-1", flash_size, + dinfo->bdrv, sector_size, + flash_size / sector_size, + 4, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory %d.\n", + fl_idx); + } + fl_idx++; + } + + if ((version == 1) && + (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { + memory_region_init_ram(flash_1, "omap_sx1.flash1-0", flash1_size); + vmstate_register_ram_global(flash_1); + memory_region_set_readonly(flash_1, true); + memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1); + + memory_region_init_io(&cs[1], &static_ops, &cs1val, + "sx1.cs1", OMAP_CS1_SIZE - flash1_size); + memory_region_add_subregion(address_space, + OMAP_CS1_BASE + flash1_size, &cs[1]); + + if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL, + "omap_sx1.flash1-1", flash1_size, + dinfo->bdrv, sector_size, + flash1_size / sector_size, + 4, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory %d.\n", + fl_idx); + } + fl_idx++; + } else { + memory_region_init_io(&cs[1], &static_ops, &cs1val, + "sx1.cs1", OMAP_CS1_SIZE); + memory_region_add_subregion(address_space, + OMAP_CS1_BASE, &cs[1]); + } + + if (!args->kernel_filename && !fl_idx) { + fprintf(stderr, "Kernel or Flash image must be specified\n"); + exit(1); + } + + /* Load the kernel. */ + if (args->kernel_filename) { + sx1_binfo.kernel_filename = args->kernel_filename; + sx1_binfo.kernel_cmdline = args->kernel_cmdline; + sx1_binfo.initrd_filename = args->initrd_filename; + arm_load_kernel(mpu->cpu, &sx1_binfo); + } + + /* TODO: fix next line */ + //~ qemu_console_resize(ds, 640, 480); +} + +static void sx1_init_v1(QEMUMachineInitArgs *args) +{ + sx1_init(args, 1); +} + +static void sx1_init_v2(QEMUMachineInitArgs *args) +{ + sx1_init(args, 2); +} + +static QEMUMachine sx1_machine_v2 = { + .name = "sx1", + .desc = "Siemens SX1 (OMAP310) V2", + .init = sx1_init_v2, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine sx1_machine_v1 = { + .name = "sx1-v1", + .desc = "Siemens SX1 (OMAP310) V1", + .init = sx1_init_v1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void sx1_machine_init(void) +{ + qemu_register_machine(&sx1_machine_v2); + qemu_register_machine(&sx1_machine_v1); +} + +machine_init(sx1_machine_init); diff --git a/hw/arm/palm.c b/hw/arm/palm.c new file mode 100644 index 0000000000..91bc74af24 --- /dev/null +++ b/hw/arm/palm.c @@ -0,0 +1,291 @@ +/* + * PalmOne's (TM) PDAs. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "hw/hw.h" +#include "audio/audio.h" +#include "sysemu/sysemu.h" +#include "ui/console.h" +#include "hw/omap.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/loader.h" +#include "exec/address-spaces.h" + +static uint32_t static_readb(void *opaque, hwaddr offset) +{ + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 3) << 3); +} + +static uint32_t static_readh(void *opaque, hwaddr offset) +{ + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 1) << 3); +} + +static uint32_t static_readw(void *opaque, hwaddr offset) +{ + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 0) << 3); +} + +static void static_write(void *opaque, hwaddr offset, + uint32_t value) +{ +#ifdef SPY + printf("%s: value %08lx written at " PA_FMT "\n", + __FUNCTION__, value, offset); +#endif +} + +static const MemoryRegionOps static_ops = { + .old_mmio = { + .read = { static_readb, static_readh, static_readw, }, + .write = { static_write, static_write, static_write, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +/* Palm Tunsgten|E support */ + +/* Shared GPIOs */ +#define PALMTE_USBDETECT_GPIO 0 +#define PALMTE_USB_OR_DC_GPIO 1 +#define PALMTE_TSC_GPIO 4 +#define PALMTE_PINTDAV_GPIO 6 +#define PALMTE_MMC_WP_GPIO 8 +#define PALMTE_MMC_POWER_GPIO 9 +#define PALMTE_HDQ_GPIO 11 +#define PALMTE_HEADPHONES_GPIO 14 +#define PALMTE_SPEAKER_GPIO 15 +/* MPU private GPIOs */ +#define PALMTE_DC_GPIO 2 +#define PALMTE_MMC_SWITCH_GPIO 4 +#define PALMTE_MMC1_GPIO 6 +#define PALMTE_MMC2_GPIO 7 +#define PALMTE_MMC3_GPIO 11 + +static MouseTransformInfo palmte_pointercal = { + .x = 320, + .y = 320, + .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 }, +}; + +static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) +{ + uWireSlave *tsc; + + tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO)); + + omap_uwire_attach(cpu->microwire, tsc, 0); + omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc)); + + tsc210x_set_transform(tsc, &palmte_pointercal); +} + +static struct { + int row; + int column; +} palmte_keymap[0x80] = { + [0 ... 0x7f] = { -1, -1 }, + [0x3b] = { 0, 0 }, /* F1 -> Calendar */ + [0x3c] = { 1, 0 }, /* F2 -> Contacts */ + [0x3d] = { 2, 0 }, /* F3 -> Tasks List */ + [0x3e] = { 3, 0 }, /* F4 -> Note Pad */ + [0x01] = { 4, 0 }, /* Esc -> Power */ + [0x4b] = { 0, 1 }, /* Left */ + [0x50] = { 1, 1 }, /* Down */ + [0x48] = { 2, 1 }, /* Up */ + [0x4d] = { 3, 1 }, /* Right */ + [0x4c] = { 4, 1 }, /* Centre */ + [0x39] = { 4, 1 }, /* Spc -> Centre */ +}; + +static void palmte_button_event(void *opaque, int keycode) +{ + struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; + + if (palmte_keymap[keycode & 0x7f].row != -1) + omap_mpuio_key(cpu->mpuio, + palmte_keymap[keycode & 0x7f].row, + palmte_keymap[keycode & 0x7f].column, + !(keycode & 0x80)); +} + +static void palmte_onoff_gpios(void *opaque, int line, int level) +{ + switch (line) { + case 0: + printf("%s: current to MMC/SD card %sabled.\n", + __FUNCTION__, level ? "dis" : "en"); + break; + case 1: + printf("%s: internal speaker amplifier %s.\n", + __FUNCTION__, level ? "down" : "on"); + break; + + /* These LCD & Audio output signals have not been identified yet. */ + case 2: + case 3: + case 4: + printf("%s: LCD GPIO%i %s.\n", + __FUNCTION__, line - 1, level ? "high" : "low"); + break; + case 5: + case 6: + printf("%s: Audio GPIO%i %s.\n", + __FUNCTION__, line - 4, level ? "high" : "low"); + break; + } +} + +static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) +{ + qemu_irq *misc_gpio; + + omap_mmc_handlers(cpu->mmc, + qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO), + qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio) + [PALMTE_MMC_SWITCH_GPIO])); + + misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7); + qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]); + qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]); + qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]); + qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]); + qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]); + omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]); + omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]); + + /* Reset some inputs to initial state. */ + qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO)); + qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO)); + qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4)); + qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO)); + qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]); + qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]); + qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]); + qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]); +} + +static struct arm_boot_info palmte_binfo = { + .loader_start = OMAP_EMIFF_BASE, + .ram_size = 0x02000000, + .board_id = 0x331, +}; + +static void palmte_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + MemoryRegion *address_space_mem = get_system_memory(); + struct omap_mpu_state_s *mpu; + int flash_size = 0x00800000; + int sdram_size = palmte_binfo.ram_size; + static uint32_t cs0val = 0xffffffff; + static uint32_t cs1val = 0x0000e1a0; + static uint32_t cs2val = 0x0000e1a0; + static uint32_t cs3val = 0xe1a0e1a0; + int rom_size, rom_loaded = 0; + DisplayState *ds = get_displaystate(); + MemoryRegion *flash = g_new(MemoryRegion, 1); + MemoryRegion *cs = g_new(MemoryRegion, 4); + + mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); + + /* External Flash (EMIFS) */ + memory_region_init_ram(flash, "palmte.flash", flash_size); + vmstate_register_ram_global(flash); + memory_region_set_readonly(flash, true); + memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash); + + memory_region_init_io(&cs[0], &static_ops, &cs0val, "palmte-cs0", + OMAP_CS0_SIZE - flash_size); + memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size, + &cs[0]); + memory_region_init_io(&cs[1], &static_ops, &cs1val, "palmte-cs1", + OMAP_CS1_SIZE); + memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]); + memory_region_init_io(&cs[2], &static_ops, &cs2val, "palmte-cs2", + OMAP_CS2_SIZE); + memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]); + memory_region_init_io(&cs[3], &static_ops, &cs3val, "palmte-cs3", + OMAP_CS3_SIZE); + memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]); + + palmte_microwire_setup(mpu); + + qemu_add_kbd_event_handler(palmte_button_event, mpu); + + palmte_gpio_setup(mpu); + + /* Setup initial (reset) machine state */ + if (nb_option_roms) { + rom_size = get_image_size(option_rom[0].name); + if (rom_size > flash_size) { + fprintf(stderr, "%s: ROM image too big (%x > %x)\n", + __FUNCTION__, rom_size, flash_size); + rom_size = 0; + } + if (rom_size > 0) { + rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE, + flash_size); + rom_loaded = 1; + } + if (rom_size < 0) { + fprintf(stderr, "%s: error loading '%s'\n", + __FUNCTION__, option_rom[0].name); + } + } + + if (!rom_loaded && !kernel_filename) { + fprintf(stderr, "Kernel or ROM image must be specified\n"); + exit(1); + } + + /* Load the kernel. */ + if (kernel_filename) { + palmte_binfo.kernel_filename = kernel_filename; + palmte_binfo.kernel_cmdline = kernel_cmdline; + palmte_binfo.initrd_filename = initrd_filename; + arm_load_kernel(mpu->cpu, &palmte_binfo); + } + + /* FIXME: We shouldn't really be doing this here. The LCD controller + will set the size once configured, so this just sets an initial + size until the guest activates the display. */ + ds->surface = qemu_resize_displaysurface(ds, 320, 320); + dpy_gfx_resize(ds); +} + +static QEMUMachine palmte_machine = { + .name = "cheetah", + .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)", + .init = palmte_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void palmte_machine_init(void) +{ + qemu_register_machine(&palmte_machine); +} + +machine_init(palmte_machine_init); diff --git a/hw/arm/pic_cpu.c b/hw/arm/pic_cpu.c new file mode 100644 index 0000000000..a7ad893cc2 --- /dev/null +++ b/hw/arm/pic_cpu.c @@ -0,0 +1,40 @@ +/* + * Generic ARM Programmable Interrupt Controller support. + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the LGPL + */ + +#include "hw/hw.h" +#include "hw/arm-misc.h" + +/* Input 0 is IRQ and input 1 is FIQ. */ +static void arm_pic_cpu_handler(void *opaque, int irq, int level) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + + switch (irq) { + case ARM_PIC_CPU_IRQ: + if (level) + cpu_interrupt(env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + break; + case ARM_PIC_CPU_FIQ: + if (level) + cpu_interrupt(env, CPU_INTERRUPT_FIQ); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ); + break; + default: + hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq); + } +} + +qemu_irq *arm_pic_init_cpu(ARMCPU *cpu) +{ + return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2); +} diff --git a/hw/arm/realview.c b/hw/arm/realview.c new file mode 100644 index 0000000000..5fb490c832 --- /dev/null +++ b/hw/arm/realview.c @@ -0,0 +1,404 @@ +/* + * ARM RealView Baseboard System emulation. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL. + */ + +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/primecell.h" +#include "hw/devices.h" +#include "hw/pci/pci.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/i2c.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#define SMP_BOOT_ADDR 0xe0000000 +#define SMP_BOOTREG_ADDR 0x10000030 + +/* Board init. */ + +static struct arm_boot_info realview_binfo = { + .smp_loader_start = SMP_BOOT_ADDR, + .smp_bootreg_addr = SMP_BOOTREG_ADDR, +}; + +/* The following two lists must be consistent. */ +enum realview_board_type { + BOARD_EB, + BOARD_EB_MPCORE, + BOARD_PB_A8, + BOARD_PBX_A9, +}; + +static const int realview_board_id[] = { + 0x33b, + 0x33b, + 0x769, + 0x76d +}; + +static void realview_init(QEMUMachineInitArgs *args, + enum realview_board_type board_type) +{ + ARMCPU *cpu = NULL; + CPUARMState *env; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram_lo = g_new(MemoryRegion, 1); + MemoryRegion *ram_hi = g_new(MemoryRegion, 1); + MemoryRegion *ram_alias = g_new(MemoryRegion, 1); + MemoryRegion *ram_hack = g_new(MemoryRegion, 1); + DeviceState *dev, *sysctl, *gpio2, *pl041; + SysBusDevice *busdev; + qemu_irq *irqp; + qemu_irq pic[64]; + qemu_irq mmc_irq[2]; + PCIBus *pci_bus; + NICInfo *nd; + i2c_bus *i2c; + int n; + int done_nic = 0; + qemu_irq cpu_irq[4]; + int is_mpcore = 0; + int is_pb = 0; + uint32_t proc_id = 0; + uint32_t sys_id; + ram_addr_t low_ram_size; + ram_addr_t ram_size = args->ram_size; + + switch (board_type) { + case BOARD_EB: + break; + case BOARD_EB_MPCORE: + is_mpcore = 1; + break; + case BOARD_PB_A8: + is_pb = 1; + break; + case BOARD_PBX_A9: + is_mpcore = 1; + is_pb = 1; + break; + } + for (n = 0; n < smp_cpus; n++) { + cpu = cpu_arm_init(args->cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + irqp = arm_pic_init_cpu(cpu); + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + } + env = &cpu->env; + if (arm_feature(env, ARM_FEATURE_V7)) { + if (is_mpcore) { + proc_id = 0x0c000000; + } else { + proc_id = 0x0e000000; + } + } else if (arm_feature(env, ARM_FEATURE_V6K)) { + proc_id = 0x06000000; + } else if (arm_feature(env, ARM_FEATURE_V6)) { + proc_id = 0x04000000; + } else { + proc_id = 0x02000000; + } + + if (is_pb && ram_size > 0x20000000) { + /* Core tile RAM. */ + low_ram_size = ram_size - 0x20000000; + ram_size = 0x20000000; + memory_region_init_ram(ram_lo, "realview.lowmem", low_ram_size); + vmstate_register_ram_global(ram_lo); + memory_region_add_subregion(sysmem, 0x20000000, ram_lo); + } + + memory_region_init_ram(ram_hi, "realview.highmem", ram_size); + vmstate_register_ram_global(ram_hi); + low_ram_size = ram_size; + if (low_ram_size > 0x10000000) + low_ram_size = 0x10000000; + /* SDRAM at address zero. */ + memory_region_init_alias(ram_alias, "realview.alias", + ram_hi, 0, low_ram_size); + memory_region_add_subregion(sysmem, 0, ram_alias); + if (is_pb) { + /* And again at a high address. */ + memory_region_add_subregion(sysmem, 0x70000000, ram_hi); + } else { + ram_size = low_ram_size; + } + + sys_id = is_pb ? 0x01780500 : 0xc1400400; + sysctl = qdev_create(NULL, "realview_sysctl"); + qdev_prop_set_uint32(sysctl, "sys_id", sys_id); + qdev_prop_set_uint32(sysctl, "proc_id", proc_id); + qdev_init_nofail(sysctl); + sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); + + if (is_mpcore) { + hwaddr periphbase; + dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + if (is_pb) { + periphbase = 0x1f000000; + } else { + periphbase = 0x10100000; + } + sysbus_mmio_map(busdev, 0, periphbase); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } + sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL); + /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */ + realview_binfo.gic_cpu_if_addr = periphbase + 0x100; + } else { + uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000; + /* For now just create the nIRQ GIC, and ignore the others. */ + dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]); + } + for (n = 0; n < 64; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + pl041 = qdev_create(NULL, "pl041"); + qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); + qdev_init_nofail(pl041); + sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); + sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]); + + sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); + sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]); + + sysbus_create_simple("pl011", 0x10009000, pic[12]); + sysbus_create_simple("pl011", 0x1000a000, pic[13]); + sysbus_create_simple("pl011", 0x1000b000, pic[14]); + sysbus_create_simple("pl011", 0x1000c000, pic[15]); + + /* DMA controller is optional, apparently. */ + sysbus_create_simple("pl081", 0x10030000, pic[24]); + + sysbus_create_simple("sp804", 0x10011000, pic[4]); + sysbus_create_simple("sp804", 0x10012000, pic[5]); + + sysbus_create_simple("pl061", 0x10013000, pic[6]); + sysbus_create_simple("pl061", 0x10014000, pic[7]); + gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]); + + sysbus_create_simple("pl111", 0x10020000, pic[23]); + + dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL); + /* Wire up MMC card detect and read-only signals. These have + * to go to both the PL061 GPIO and the sysctl register. + * Note that the PL181 orders these lines (readonly,inserted) + * and the PL061 has them the other way about. Also the card + * detect line is inverted. + */ + mmc_irq[0] = qemu_irq_split( + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT), + qdev_get_gpio_in(gpio2, 1)); + mmc_irq[1] = qemu_irq_split( + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN), + qemu_irq_invert(qdev_get_gpio_in(gpio2, 0))); + qdev_connect_gpio_out(dev, 0, mmc_irq[0]); + qdev_connect_gpio_out(dev, 1, mmc_irq[1]); + + sysbus_create_simple("pl031", 0x10017000, pic[10]); + + if (!is_pb) { + dev = qdev_create(NULL, "realview_pci"); + busdev = SYS_BUS_DEVICE(dev); + qdev_init_nofail(dev); + sysbus_mmio_map(busdev, 0, 0x61000000); /* PCI self-config */ + sysbus_mmio_map(busdev, 1, 0x62000000); /* PCI config */ + sysbus_mmio_map(busdev, 2, 0x63000000); /* PCI I/O */ + sysbus_connect_irq(busdev, 0, pic[48]); + sysbus_connect_irq(busdev, 1, pic[49]); + sysbus_connect_irq(busdev, 2, pic[50]); + sysbus_connect_irq(busdev, 3, pic[51]); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); + if (usb_enabled(false)) { + pci_create_simple(pci_bus, -1, "pci-ohci"); + } + n = drive_get_max_bus(IF_SCSI); + while (n >= 0) { + pci_create_simple(pci_bus, -1, "lsi53c895a"); + n--; + } + } + for(n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + + if (!done_nic && (!nd->model || + strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) { + if (is_pb) { + lan9118_init(nd, 0x4e000000, pic[28]); + } else { + smc91c111_init(nd, 0x4e000000, pic[28]); + } + done_nic = 1; + } else { + pci_nic_init_nofail(nd, "rtl8139", NULL); + } + } + + dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); + i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); + i2c_create_slave(i2c, "ds1338", 0x68); + + /* Memory map for RealView Emulation Baseboard: */ + /* 0x10000000 System registers. */ + /* 0x10001000 System controller. */ + /* 0x10002000 Two-Wire Serial Bus. */ + /* 0x10003000 Reserved. */ + /* 0x10004000 AACI. */ + /* 0x10005000 MCI. */ + /* 0x10006000 KMI0. */ + /* 0x10007000 KMI1. */ + /* 0x10008000 Character LCD. (EB) */ + /* 0x10009000 UART0. */ + /* 0x1000a000 UART1. */ + /* 0x1000b000 UART2. */ + /* 0x1000c000 UART3. */ + /* 0x1000d000 SSPI. */ + /* 0x1000e000 SCI. */ + /* 0x1000f000 Reserved. */ + /* 0x10010000 Watchdog. */ + /* 0x10011000 Timer 0+1. */ + /* 0x10012000 Timer 2+3. */ + /* 0x10013000 GPIO 0. */ + /* 0x10014000 GPIO 1. */ + /* 0x10015000 GPIO 2. */ + /* 0x10002000 Two-Wire Serial Bus - DVI. (PB) */ + /* 0x10017000 RTC. */ + /* 0x10018000 DMC. */ + /* 0x10019000 PCI controller config. */ + /* 0x10020000 CLCD. */ + /* 0x10030000 DMA Controller. */ + /* 0x10040000 GIC1. (EB) */ + /* 0x10050000 GIC2. (EB) */ + /* 0x10060000 GIC3. (EB) */ + /* 0x10070000 GIC4. (EB) */ + /* 0x10080000 SMC. */ + /* 0x1e000000 GIC1. (PB) */ + /* 0x1e001000 GIC2. (PB) */ + /* 0x1e002000 GIC3. (PB) */ + /* 0x1e003000 GIC4. (PB) */ + /* 0x40000000 NOR flash. */ + /* 0x44000000 DoC flash. */ + /* 0x48000000 SRAM. */ + /* 0x4c000000 Configuration flash. */ + /* 0x4e000000 Ethernet. */ + /* 0x4f000000 USB. */ + /* 0x50000000 PISMO. */ + /* 0x54000000 PISMO. */ + /* 0x58000000 PISMO. */ + /* 0x5c000000 PISMO. */ + /* 0x60000000 PCI. */ + /* 0x61000000 PCI Self Config. */ + /* 0x62000000 PCI Config. */ + /* 0x63000000 PCI IO. */ + /* 0x64000000 PCI mem 0. */ + /* 0x68000000 PCI mem 1. */ + /* 0x6c000000 PCI mem 2. */ + + /* ??? Hack to map an additional page of ram for the secondary CPU + startup code. I guess this works on real hardware because the + BootROM happens to be in ROM/flash or in memory that isn't clobbered + until after Linux boots the secondary CPUs. */ + memory_region_init_ram(ram_hack, "realview.hack", 0x1000); + vmstate_register_ram_global(ram_hack); + memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); + + realview_binfo.ram_size = ram_size; + realview_binfo.kernel_filename = args->kernel_filename; + realview_binfo.kernel_cmdline = args->kernel_cmdline; + realview_binfo.initrd_filename = args->initrd_filename; + realview_binfo.nb_cpus = smp_cpus; + realview_binfo.board_id = realview_board_id[board_type]; + realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); + arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo); +} + +static void realview_eb_init(QEMUMachineInitArgs *args) +{ + if (!args->cpu_model) { + args->cpu_model = "arm926"; + } + realview_init(args, BOARD_EB); +} + +static void realview_eb_mpcore_init(QEMUMachineInitArgs *args) +{ + if (!args->cpu_model) { + args->cpu_model = "arm11mpcore"; + } + realview_init(args, BOARD_EB_MPCORE); +} + +static void realview_pb_a8_init(QEMUMachineInitArgs *args) +{ + if (!args->cpu_model) { + args->cpu_model = "cortex-a8"; + } + realview_init(args, BOARD_PB_A8); +} + +static void realview_pbx_a9_init(QEMUMachineInitArgs *args) +{ + if (!args->cpu_model) { + args->cpu_model = "cortex-a9"; + } + realview_init(args, BOARD_PBX_A9); +} + +static QEMUMachine realview_eb_machine = { + .name = "realview-eb", + .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", + .init = realview_eb_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine realview_eb_mpcore_machine = { + .name = "realview-eb-mpcore", + .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)", + .init = realview_eb_mpcore_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine realview_pb_a8_machine = { + .name = "realview-pb-a8", + .desc = "ARM RealView Platform Baseboard for Cortex-A8", + .init = realview_pb_a8_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine realview_pbx_a9_machine = { + .name = "realview-pbx-a9", + .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9", + .init = realview_pbx_a9_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static void realview_machine_init(void) +{ + qemu_register_machine(&realview_eb_machine); + qemu_register_machine(&realview_eb_mpcore_machine); + qemu_register_machine(&realview_pb_a8_machine); + qemu_register_machine(&realview_pbx_a9_machine); +} + +machine_init(realview_machine_init); diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c new file mode 100644 index 0000000000..f5832bea93 --- /dev/null +++ b/hw/arm/spitz.c @@ -0,0 +1,1138 @@ +/* + * PXA270-based Clamshell PDA platforms. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "sysemu/sysemu.h" +#include "hw/pcmcia.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "hw/flash.h" +#include "qemu/timer.h" +#include "hw/devices.h" +#include "hw/sharpsl.h" +#include "ui/console.h" +#include "block/block.h" +#include "audio/audio.h" +#include "hw/boards.h" +#include "sysemu/blockdev.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + +#undef REG_FMT +#define REG_FMT "0x%02lx" + +/* Spitz Flash */ +#define FLASH_BASE 0x0c000000 +#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */ +#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */ +#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */ +#define FLASH_ECCCNTR 0x0c /* ECC byte counter */ +#define FLASH_ECCCLRR 0x10 /* Clear ECC */ +#define FLASH_FLASHIO 0x14 /* Flash I/O */ +#define FLASH_FLASHCTL 0x18 /* Flash Control */ + +#define FLASHCTL_CE0 (1 << 0) +#define FLASHCTL_CLE (1 << 1) +#define FLASHCTL_ALE (1 << 2) +#define FLASHCTL_WP (1 << 3) +#define FLASHCTL_CE1 (1 << 4) +#define FLASHCTL_RYBY (1 << 5) +#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1) + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + DeviceState *nand; + uint8_t ctl; + uint8_t manf_id; + uint8_t chip_id; + ECCState ecc; +} SLNANDState; + +static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size) +{ + SLNANDState *s = (SLNANDState *) opaque; + int ryby; + + switch (addr) { +#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to)) + case FLASH_ECCLPLB: + return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) | + BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7); + +#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to)) + case FLASH_ECCLPUB: + return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) | + BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7); + + case FLASH_ECCCP: + return s->ecc.cp; + + case FLASH_ECCCNTR: + return s->ecc.count & 0xff; + + case FLASH_FLASHCTL: + nand_getpins(s->nand, &ryby); + if (ryby) + return s->ctl | FLASHCTL_RYBY; + else + return s->ctl; + + case FLASH_FLASHIO: + if (size == 4) { + return ecc_digest(&s->ecc, nand_getio(s->nand)) | + (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16); + } + return ecc_digest(&s->ecc, nand_getio(s->nand)); + + default: + zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); + } + return 0; +} + +static void sl_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + SLNANDState *s = (SLNANDState *) opaque; + + switch (addr) { + case FLASH_ECCCLRR: + /* Value is ignored. */ + ecc_reset(&s->ecc); + break; + + case FLASH_FLASHCTL: + s->ctl = value & 0xff & ~FLASHCTL_RYBY; + nand_setpins(s->nand, + s->ctl & FLASHCTL_CLE, + s->ctl & FLASHCTL_ALE, + s->ctl & FLASHCTL_NCE, + s->ctl & FLASHCTL_WP, + 0); + break; + + case FLASH_FLASHIO: + nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff)); + break; + + default: + zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); + } +} + +enum { + FLASH_128M, + FLASH_1024M, +}; + +static const MemoryRegionOps sl_ops = { + .read = sl_read, + .write = sl_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void sl_flash_register(PXA2xxState *cpu, int size) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "sl-nand"); + + qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG); + if (size == FLASH_128M) + qdev_prop_set_uint8(dev, "chip_id", 0x73); + else if (size == FLASH_1024M) + qdev_prop_set_uint8(dev, "chip_id", 0xf1); + + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); +} + +static int sl_nand_init(SysBusDevice *dev) { + SLNANDState *s; + DriveInfo *nand; + + s = FROM_SYSBUS(SLNANDState, dev); + + s->ctl = 0; + nand = drive_get(IF_MTD, 0, 0); + s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id); + + memory_region_init_io(&s->iomem, &sl_ops, s, "sl", 0x40); + sysbus_init_mmio(dev, &s->iomem); + + return 0; +} + +/* Spitz Keyboard */ + +#define SPITZ_KEY_STROBE_NUM 11 +#define SPITZ_KEY_SENSE_NUM 7 + +static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = { + 12, 17, 91, 34, 36, 38, 39 +}; + +static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = { + 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114 +}; + +/* Eighth additional row maps the special keys */ +static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = { + { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 }, + { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 }, + { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 }, + { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 }, + { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 }, + { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 }, + { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 }, + { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 }, +}; + +#define SPITZ_GPIO_AK_INT 13 /* Remote control */ +#define SPITZ_GPIO_SYNC 16 /* Sync button */ +#define SPITZ_GPIO_ON_KEY 95 /* Power button */ +#define SPITZ_GPIO_SWA 97 /* Lid */ +#define SPITZ_GPIO_SWB 96 /* Tablet mode */ + +/* The special buttons are mapped to unused keys */ +static const int spitz_gpiomap[5] = { + SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY, + SPITZ_GPIO_SWA, SPITZ_GPIO_SWB, +}; + +typedef struct { + SysBusDevice busdev; + qemu_irq sense[SPITZ_KEY_SENSE_NUM]; + qemu_irq gpiomap[5]; + int keymap[0x80]; + uint16_t keyrow[SPITZ_KEY_SENSE_NUM]; + uint16_t strobe_state; + uint16_t sense_state; + + uint16_t pre_map[0x100]; + uint16_t modifiers; + uint16_t imodifiers; + uint8_t fifo[16]; + int fifopos, fifolen; + QEMUTimer *kbdtimer; +} SpitzKeyboardState; + +static void spitz_keyboard_sense_update(SpitzKeyboardState *s) +{ + int i; + uint16_t strobe, sense = 0; + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) { + strobe = s->keyrow[i] & s->strobe_state; + if (strobe) { + sense |= 1 << i; + if (!(s->sense_state & (1 << i))) + qemu_irq_raise(s->sense[i]); + } else if (s->sense_state & (1 << i)) + qemu_irq_lower(s->sense[i]); + } + + s->sense_state = sense; +} + +static void spitz_keyboard_strobe(void *opaque, int line, int level) +{ + SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; + + if (level) + s->strobe_state |= 1 << line; + else + s->strobe_state &= ~(1 << line); + spitz_keyboard_sense_update(s); +} + +static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode) +{ + int spitz_keycode = s->keymap[keycode & 0x7f]; + if (spitz_keycode == -1) + return; + + /* Handle the additional keys */ + if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) { + qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80)); + return; + } + + if (keycode & 0x80) + s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf)); + else + s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf); + + spitz_keyboard_sense_update(s); +} + +#define SHIFT (1 << 7) +#define CTRL (1 << 8) +#define FN (1 << 9) + +#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c + +static void spitz_keyboard_handler(void *opaque, int keycode) +{ + SpitzKeyboardState *s = opaque; + uint16_t code; + int mapcode; + switch (keycode) { + case 0x2a: /* Left Shift */ + s->modifiers |= 1; + break; + case 0xaa: + s->modifiers &= ~1; + break; + case 0x36: /* Right Shift */ + s->modifiers |= 2; + break; + case 0xb6: + s->modifiers &= ~2; + break; + case 0x1d: /* Control */ + s->modifiers |= 4; + break; + case 0x9d: + s->modifiers &= ~4; + break; + case 0x38: /* Alt */ + s->modifiers |= 8; + break; + case 0xb8: + s->modifiers &= ~8; + break; + } + + code = s->pre_map[mapcode = ((s->modifiers & 3) ? + (keycode | SHIFT) : + (keycode & ~SHIFT))]; + + if (code != mapcode) { +#if 0 + if ((code & SHIFT) && !(s->modifiers & 1)) + QUEUE_KEY(0x2a | (keycode & 0x80)); + if ((code & CTRL ) && !(s->modifiers & 4)) + QUEUE_KEY(0x1d | (keycode & 0x80)); + if ((code & FN ) && !(s->modifiers & 8)) + QUEUE_KEY(0x38 | (keycode & 0x80)); + if ((code & FN ) && (s->modifiers & 1)) + QUEUE_KEY(0x2a | (~keycode & 0x80)); + if ((code & FN ) && (s->modifiers & 2)) + QUEUE_KEY(0x36 | (~keycode & 0x80)); +#else + if (keycode & 0x80) { + if ((s->imodifiers & 1 ) && !(s->modifiers & 1)) + QUEUE_KEY(0x2a | 0x80); + if ((s->imodifiers & 4 ) && !(s->modifiers & 4)) + QUEUE_KEY(0x1d | 0x80); + if ((s->imodifiers & 8 ) && !(s->modifiers & 8)) + QUEUE_KEY(0x38 | 0x80); + if ((s->imodifiers & 0x10) && (s->modifiers & 1)) + QUEUE_KEY(0x2a); + if ((s->imodifiers & 0x20) && (s->modifiers & 2)) + QUEUE_KEY(0x36); + s->imodifiers = 0; + } else { + if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) { + QUEUE_KEY(0x2a); + s->imodifiers |= 1; + } + if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) { + QUEUE_KEY(0x1d); + s->imodifiers |= 4; + } + if ((code & FN ) && !((s->modifiers | s->imodifiers) & 8)) { + QUEUE_KEY(0x38); + s->imodifiers |= 8; + } + if ((code & FN ) && (s->modifiers & 1) && + !(s->imodifiers & 0x10)) { + QUEUE_KEY(0x2a | 0x80); + s->imodifiers |= 0x10; + } + if ((code & FN ) && (s->modifiers & 2) && + !(s->imodifiers & 0x20)) { + QUEUE_KEY(0x36 | 0x80); + s->imodifiers |= 0x20; + } + } +#endif + } + + QUEUE_KEY((code & 0x7f) | (keycode & 0x80)); +} + +static void spitz_keyboard_tick(void *opaque) +{ + SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; + + if (s->fifolen) { + spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]); + s->fifolen --; + if (s->fifopos >= 16) + s->fifopos = 0; + } + + qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec() / 32); +} + +static void spitz_keyboard_pre_map(SpitzKeyboardState *s) +{ + int i; + for (i = 0; i < 0x100; i ++) + s->pre_map[i] = i; + s->pre_map[0x02 | SHIFT ] = 0x02 | SHIFT; /* exclam */ + s->pre_map[0x28 | SHIFT ] = 0x03 | SHIFT; /* quotedbl */ + s->pre_map[0x04 | SHIFT ] = 0x04 | SHIFT; /* numbersign */ + s->pre_map[0x05 | SHIFT ] = 0x05 | SHIFT; /* dollar */ + s->pre_map[0x06 | SHIFT ] = 0x06 | SHIFT; /* percent */ + s->pre_map[0x08 | SHIFT ] = 0x07 | SHIFT; /* ampersand */ + s->pre_map[0x28 ] = 0x08 | SHIFT; /* apostrophe */ + s->pre_map[0x0a | SHIFT ] = 0x09 | SHIFT; /* parenleft */ + s->pre_map[0x0b | SHIFT ] = 0x0a | SHIFT; /* parenright */ + s->pre_map[0x29 | SHIFT ] = 0x0b | SHIFT; /* asciitilde */ + s->pre_map[0x03 | SHIFT ] = 0x0c | SHIFT; /* at */ + s->pre_map[0xd3 ] = 0x0e | FN; /* Delete */ + s->pre_map[0x3a ] = 0x0f | FN; /* Caps_Lock */ + s->pre_map[0x07 | SHIFT ] = 0x11 | FN; /* asciicircum */ + s->pre_map[0x0d ] = 0x12 | FN; /* equal */ + s->pre_map[0x0d | SHIFT ] = 0x13 | FN; /* plus */ + s->pre_map[0x1a ] = 0x14 | FN; /* bracketleft */ + s->pre_map[0x1b ] = 0x15 | FN; /* bracketright */ + s->pre_map[0x1a | SHIFT ] = 0x16 | FN; /* braceleft */ + s->pre_map[0x1b | SHIFT ] = 0x17 | FN; /* braceright */ + s->pre_map[0x27 ] = 0x22 | FN; /* semicolon */ + s->pre_map[0x27 | SHIFT ] = 0x23 | FN; /* colon */ + s->pre_map[0x09 | SHIFT ] = 0x24 | FN; /* asterisk */ + s->pre_map[0x2b ] = 0x25 | FN; /* backslash */ + s->pre_map[0x2b | SHIFT ] = 0x26 | FN; /* bar */ + s->pre_map[0x0c | SHIFT ] = 0x30 | FN; /* underscore */ + s->pre_map[0x33 | SHIFT ] = 0x33 | FN; /* less */ + s->pre_map[0x35 ] = 0x33 | SHIFT; /* slash */ + s->pre_map[0x34 | SHIFT ] = 0x34 | FN; /* greater */ + s->pre_map[0x35 | SHIFT ] = 0x34 | SHIFT; /* question */ + s->pre_map[0x49 ] = 0x48 | FN; /* Page_Up */ + s->pre_map[0x51 ] = 0x50 | FN; /* Page_Down */ + + s->modifiers = 0; + s->imodifiers = 0; + s->fifopos = 0; + s->fifolen = 0; +} + +#undef SHIFT +#undef CTRL +#undef FN + +static int spitz_keyboard_post_load(void *opaque, int version_id) +{ + SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; + + /* Release all pressed keys */ + memset(s->keyrow, 0, sizeof(s->keyrow)); + spitz_keyboard_sense_update(s); + s->modifiers = 0; + s->imodifiers = 0; + s->fifopos = 0; + s->fifolen = 0; + + return 0; +} + +static void spitz_keyboard_register(PXA2xxState *cpu) +{ + int i; + DeviceState *dev; + SpitzKeyboardState *s; + + dev = sysbus_create_simple("spitz-keyboard", -1, NULL); + s = FROM_SYSBUS(SpitzKeyboardState, SYS_BUS_DEVICE(dev)); + + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) + qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i])); + + for (i = 0; i < 5; i ++) + s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]); + + if (!graphic_rotate) + s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]); + + for (i = 0; i < 5; i++) + qemu_set_irq(s->gpiomap[i], 0); + + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++) + qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i], + qdev_get_gpio_in(dev, i)); + + qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock)); + + qemu_add_kbd_event_handler(spitz_keyboard_handler, s); +} + +static int spitz_keyboard_init(SysBusDevice *dev) +{ + SpitzKeyboardState *s; + int i, j; + + s = FROM_SYSBUS(SpitzKeyboardState, dev); + + for (i = 0; i < 0x80; i ++) + s->keymap[i] = -1; + for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++) + for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++) + if (spitz_keymap[i][j] != -1) + s->keymap[spitz_keymap[i][j]] = (i << 4) | j; + + spitz_keyboard_pre_map(s); + + s->kbdtimer = qemu_new_timer_ns(vm_clock, spitz_keyboard_tick, s); + qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM); + qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM); + + return 0; +} + +/* LCD backlight controller */ + +#define LCDTG_RESCTL 0x00 +#define LCDTG_PHACTRL 0x01 +#define LCDTG_DUTYCTRL 0x02 +#define LCDTG_POWERREG0 0x03 +#define LCDTG_POWERREG1 0x04 +#define LCDTG_GPOR3 0x05 +#define LCDTG_PICTRL 0x06 +#define LCDTG_POLCTRL 0x07 + +typedef struct { + SSISlave ssidev; + uint32_t bl_intensity; + uint32_t bl_power; +} SpitzLCDTG; + +static void spitz_bl_update(SpitzLCDTG *s) +{ + if (s->bl_power && s->bl_intensity) + zaurus_printf("LCD Backlight now at %i/63\n", s->bl_intensity); + else + zaurus_printf("LCD Backlight now off\n"); +} + +/* FIXME: Implement GPIO properly and remove this hack. */ +static SpitzLCDTG *spitz_lcdtg; + +static inline void spitz_bl_bit5(void *opaque, int line, int level) +{ + SpitzLCDTG *s = spitz_lcdtg; + int prev = s->bl_intensity; + + if (level) + s->bl_intensity &= ~0x20; + else + s->bl_intensity |= 0x20; + + if (s->bl_power && prev != s->bl_intensity) + spitz_bl_update(s); +} + +static inline void spitz_bl_power(void *opaque, int line, int level) +{ + SpitzLCDTG *s = spitz_lcdtg; + s->bl_power = !!level; + spitz_bl_update(s); +} + +static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value) +{ + SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); + int addr; + addr = value >> 5; + value &= 0x1f; + + switch (addr) { + case LCDTG_RESCTL: + if (value) + zaurus_printf("LCD in QVGA mode\n"); + else + zaurus_printf("LCD in VGA mode\n"); + break; + + case LCDTG_DUTYCTRL: + s->bl_intensity &= ~0x1f; + s->bl_intensity |= value; + if (s->bl_power) + spitz_bl_update(s); + break; + + case LCDTG_POWERREG0: + /* Set common voltage to M62332FP */ + break; + } + return 0; +} + +static int spitz_lcdtg_init(SSISlave *dev) +{ + SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); + + spitz_lcdtg = s; + s->bl_power = 0; + s->bl_intensity = 0x20; + + return 0; +} + +/* SSP devices */ + +#define CORGI_SSP_PORT 2 + +#define SPITZ_GPIO_LCDCON_CS 53 +#define SPITZ_GPIO_ADS7846_CS 14 +#define SPITZ_GPIO_MAX1111_CS 20 +#define SPITZ_GPIO_TP_INT 11 + +static DeviceState *max1111; + +/* "Demux" the signal based on current chipselect */ +typedef struct { + SSISlave ssidev; + SSIBus *bus[3]; + uint32_t enable[3]; +} CorgiSSPState; + +static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value) +{ + CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); + int i; + + for (i = 0; i < 3; i++) { + if (s->enable[i]) { + return ssi_transfer(s->bus[i], value); + } + } + return 0; +} + +static void corgi_ssp_gpio_cs(void *opaque, int line, int level) +{ + CorgiSSPState *s = (CorgiSSPState *)opaque; + assert(line >= 0 && line < 3); + s->enable[line] = !level; +} + +#define MAX1111_BATT_VOLT 1 +#define MAX1111_BATT_TEMP 2 +#define MAX1111_ACIN_VOLT 3 + +#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */ +#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ +#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ + +static void spitz_adc_temp_on(void *opaque, int line, int level) +{ + if (!max1111) + return; + + if (level) + max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP); + else + max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); +} + +static int corgi_ssp_init(SSISlave *dev) +{ + CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); + + qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3); + s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); + s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); + s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2"); + + return 0; +} + +static void spitz_ssp_attach(PXA2xxState *cpu) +{ + DeviceState *mux; + DeviceState *dev; + void *bus; + + mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp"); + + bus = qdev_get_child_bus(mux, "ssi0"); + ssi_create_slave(bus, "spitz-lcdtg"); + + bus = qdev_get_child_bus(mux, "ssi1"); + dev = ssi_create_slave(bus, "ads7846"); + qdev_connect_gpio_out(dev, 0, + qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT)); + + bus = qdev_get_child_bus(mux, "ssi2"); + max1111 = ssi_create_slave(bus, "max1111"); + max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); + max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); + max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN); + + qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS, + qdev_get_gpio_in(mux, 0)); + qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS, + qdev_get_gpio_in(mux, 1)); + qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS, + qdev_get_gpio_in(mux, 2)); +} + +/* CF Microdrive */ + +static void spitz_microdrive_attach(PXA2xxState *cpu, int slot) +{ + PCMCIACardState *md; + DriveInfo *dinfo; + + dinfo = drive_get(IF_IDE, 0, 0); + if (!dinfo || dinfo->media_cd) + return; + md = dscm1xxxx_init(dinfo); + pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md); +} + +/* Wm8750 and Max7310 on I2C */ + +#define AKITA_MAX_ADDR 0x18 +#define SPITZ_WM_ADDRL 0x1b +#define SPITZ_WM_ADDRH 0x1a + +#define SPITZ_GPIO_WM 5 + +static void spitz_wm8750_addr(void *opaque, int line, int level) +{ + I2CSlave *wm = (I2CSlave *) opaque; + if (level) + i2c_set_slave_address(wm, SPITZ_WM_ADDRH); + else + i2c_set_slave_address(wm, SPITZ_WM_ADDRL); +} + +static void spitz_i2c_setup(PXA2xxState *cpu) +{ + /* Attach the CPU on one end of our I2C bus. */ + i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); + + DeviceState *wm; + + /* Attach a WM8750 to the bus */ + wm = i2c_create_slave(bus, "wm8750", 0); + + spitz_wm8750_addr(wm, 0, 0); + qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM, + qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]); + /* .. and to the sound interface. */ + cpu->i2s->opaque = wm; + cpu->i2s->codec_out = wm8750_dac_dat; + cpu->i2s->codec_in = wm8750_adc_dat; + wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s); +} + +static void spitz_akita_i2c_setup(PXA2xxState *cpu) +{ + /* Attach a Max7310 to Akita I2C bus. */ + i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310", + AKITA_MAX_ADDR); +} + +/* Other peripherals */ + +static void spitz_out_switch(void *opaque, int line, int level) +{ + switch (line) { + case 0: + zaurus_printf("Charging %s.\n", level ? "off" : "on"); + break; + case 1: + zaurus_printf("Discharging %s.\n", level ? "on" : "off"); + break; + case 2: + zaurus_printf("Green LED %s.\n", level ? "on" : "off"); + break; + case 3: + zaurus_printf("Orange LED %s.\n", level ? "on" : "off"); + break; + case 4: + spitz_bl_bit5(opaque, line, level); + break; + case 5: + spitz_bl_power(opaque, line, level); + break; + case 6: + spitz_adc_temp_on(opaque, line, level); + break; + } +} + +#define SPITZ_SCP_LED_GREEN 1 +#define SPITZ_SCP_JK_B 2 +#define SPITZ_SCP_CHRG_ON 3 +#define SPITZ_SCP_MUTE_L 4 +#define SPITZ_SCP_MUTE_R 5 +#define SPITZ_SCP_CF_POWER 6 +#define SPITZ_SCP_LED_ORANGE 7 +#define SPITZ_SCP_JK_A 8 +#define SPITZ_SCP_ADC_TEMP_ON 9 +#define SPITZ_SCP2_IR_ON 1 +#define SPITZ_SCP2_AKIN_PULLUP 2 +#define SPITZ_SCP2_BACKLIGHT_CONT 7 +#define SPITZ_SCP2_BACKLIGHT_ON 8 +#define SPITZ_SCP2_MIC_BIAS 9 + +static void spitz_scoop_gpio_setup(PXA2xxState *cpu, + DeviceState *scp0, DeviceState *scp1) +{ + qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8); + + qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]); + qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]); + qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]); + qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]); + + if (scp1) { + qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]); + qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]); + } + + qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); +} + +#define SPITZ_GPIO_HSYNC 22 +#define SPITZ_GPIO_SD_DETECT 9 +#define SPITZ_GPIO_SD_WP 81 +#define SPITZ_GPIO_ON_RESET 89 +#define SPITZ_GPIO_BAT_COVER 90 +#define SPITZ_GPIO_CF1_IRQ 105 +#define SPITZ_GPIO_CF1_CD 94 +#define SPITZ_GPIO_CF2_IRQ 106 +#define SPITZ_GPIO_CF2_CD 93 + +static int spitz_hsync; + +static void spitz_lcd_hsync_handler(void *opaque, int line, int level) +{ + PXA2xxState *cpu = (PXA2xxState *) opaque; + qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync); + spitz_hsync ^= 1; +} + +static void spitz_gpio_setup(PXA2xxState *cpu, int slots) +{ + qemu_irq lcd_hsync; + /* + * Bad hack: We toggle the LCD hsync GPIO on every GPIO status + * read to satisfy broken guests that poll-wait for hsync. + * Simulating a real hsync event would be less practical and + * wouldn't guarantee that a guest ever exits the loop. + */ + spitz_hsync = 0; + lcd_hsync = qemu_allocate_irqs(spitz_lcd_hsync_handler, cpu, 1)[0]; + pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync); + pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync); + + /* MMC/SD host */ + pxa2xx_mmci_handlers(cpu->mmc, + qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP), + qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT)); + + /* Battery lock always closed */ + qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER)); + + /* Handle reset */ + qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset); + + /* PCMCIA signals: card's IRQ and Card-Detect */ + if (slots >= 1) + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], + qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ), + qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD)); + if (slots >= 2) + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], + qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ), + qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD)); +} + +/* Board init. */ +enum spitz_model_e { spitz, akita, borzoi, terrier }; + +#define SPITZ_RAM 0x04000000 +#define SPITZ_ROM 0x00800000 + +static struct arm_boot_info spitz_binfo = { + .loader_start = PXA2XX_SDRAM_BASE, + .ram_size = 0x04000000, +}; + +static void spitz_common_init(QEMUMachineInitArgs *args, + enum spitz_model_e model, int arm_id) +{ + PXA2xxState *mpu; + DeviceState *scp0, *scp1 = NULL; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *rom = g_new(MemoryRegion, 1); + const char *cpu_model = args->cpu_model; + + if (!cpu_model) + cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; + + /* Setup CPU & memory */ + mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model); + + sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); + + memory_region_init_ram(rom, "spitz.rom", SPITZ_ROM); + vmstate_register_ram_global(rom); + memory_region_set_readonly(rom, true); + memory_region_add_subregion(address_space_mem, 0, rom); + + /* Setup peripherals */ + spitz_keyboard_register(mpu); + + spitz_ssp_attach(mpu); + + scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); + if (model != akita) { + scp1 = sysbus_create_simple("scoop", 0x08800040, NULL); + } + + spitz_scoop_gpio_setup(mpu, scp0, scp1); + + spitz_gpio_setup(mpu, (model == akita) ? 1 : 2); + + spitz_i2c_setup(mpu); + + if (model == akita) + spitz_akita_i2c_setup(mpu); + + if (model == terrier) + /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */ + spitz_microdrive_attach(mpu, 1); + else if (model != akita) + /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ + spitz_microdrive_attach(mpu, 0); + + spitz_binfo.kernel_filename = args->kernel_filename; + spitz_binfo.kernel_cmdline = args->kernel_cmdline; + spitz_binfo.initrd_filename = args->initrd_filename; + spitz_binfo.board_id = arm_id; + arm_load_kernel(mpu->cpu, &spitz_binfo); + sl_bootparam_write(SL_PXA_PARAM_BASE); +} + +static void spitz_init(QEMUMachineInitArgs *args) +{ + spitz_common_init(args, spitz, 0x2c9); +} + +static void borzoi_init(QEMUMachineInitArgs *args) +{ + spitz_common_init(args, borzoi, 0x33f); +} + +static void akita_init(QEMUMachineInitArgs *args) +{ + spitz_common_init(args, akita, 0x2e8); +} + +static void terrier_init(QEMUMachineInitArgs *args) +{ + spitz_common_init(args, terrier, 0x33f); +} + +static QEMUMachine akitapda_machine = { + .name = "akita", + .desc = "Akita PDA (PXA270)", + .init = akita_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine spitzpda_machine = { + .name = "spitz", + .desc = "Spitz PDA (PXA270)", + .init = spitz_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine borzoipda_machine = { + .name = "borzoi", + .desc = "Borzoi PDA (PXA270)", + .init = borzoi_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine terrierpda_machine = { + .name = "terrier", + .desc = "Terrier PDA (PXA270)", + .init = terrier_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void spitz_machine_init(void) +{ + qemu_register_machine(&akitapda_machine); + qemu_register_machine(&spitzpda_machine); + qemu_register_machine(&borzoipda_machine); + qemu_register_machine(&terrierpda_machine); +} + +machine_init(spitz_machine_init); + +static bool is_version_0(void *opaque, int version_id) +{ + return version_id == 0; +} + +static VMStateDescription vmstate_sl_nand_info = { + .name = "sl-nand", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField []) { + VMSTATE_UINT8(ctl, SLNANDState), + VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState), + VMSTATE_END_OF_LIST(), + }, +}; + +static Property sl_nand_properties[] = { + DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG), + DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sl_nand_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sl_nand_init; + dc->vmsd = &vmstate_sl_nand_info; + dc->props = sl_nand_properties; +} + +static const TypeInfo sl_nand_info = { + .name = "sl-nand", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SLNANDState), + .class_init = sl_nand_class_init, +}; + +static VMStateDescription vmstate_spitz_kbd = { + .name = "spitz-keyboard", + .version_id = 1, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = spitz_keyboard_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT16(sense_state, SpitzKeyboardState), + VMSTATE_UINT16(strobe_state, SpitzKeyboardState), + VMSTATE_UNUSED_TEST(is_version_0, 5), + VMSTATE_END_OF_LIST(), + }, +}; + +static Property spitz_keyboard_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void spitz_keyboard_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = spitz_keyboard_init; + dc->vmsd = &vmstate_spitz_kbd; + dc->props = spitz_keyboard_properties; +} + +static const TypeInfo spitz_keyboard_info = { + .name = "spitz-keyboard", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SpitzKeyboardState), + .class_init = spitz_keyboard_class_init, +}; + +static const VMStateDescription vmstate_corgi_ssp_regs = { + .name = "corgi-ssp", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), + VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), + VMSTATE_END_OF_LIST(), + } +}; + +static void corgi_ssp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = corgi_ssp_init; + k->transfer = corgi_ssp_transfer; + dc->vmsd = &vmstate_corgi_ssp_regs; +} + +static const TypeInfo corgi_ssp_info = { + .name = "corgi-ssp", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(CorgiSSPState), + .class_init = corgi_ssp_class_init, +}; + +static const VMStateDescription vmstate_spitz_lcdtg_regs = { + .name = "spitz-lcdtg", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), + VMSTATE_UINT32(bl_intensity, SpitzLCDTG), + VMSTATE_UINT32(bl_power, SpitzLCDTG), + VMSTATE_END_OF_LIST(), + } +}; + +static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = spitz_lcdtg_init; + k->transfer = spitz_lcdtg_transfer; + dc->vmsd = &vmstate_spitz_lcdtg_regs; +} + +static const TypeInfo spitz_lcdtg_info = { + .name = "spitz-lcdtg", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(SpitzLCDTG), + .class_init = spitz_lcdtg_class_init, +}; + +static void spitz_register_types(void) +{ + type_register_static(&corgi_ssp_info); + type_register_static(&spitz_lcdtg_info); + type_register_static(&spitz_keyboard_info); + type_register_static(&sl_nand_info); +} + +type_init(spitz_register_types) diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c new file mode 100644 index 0000000000..f4ce7945f3 --- /dev/null +++ b/hw/arm/stellaris.c @@ -0,0 +1,1401 @@ +/* + * Luminary Micro Stellaris peripherals + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL. + */ + +#include "hw/sysbus.h" +#include "hw/ssi.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "qemu/timer.h" +#include "hw/i2c.h" +#include "net/net.h" +#include "hw/boards.h" +#include "exec/address-spaces.h" + +#define GPIO_A 0 +#define GPIO_B 1 +#define GPIO_C 2 +#define GPIO_D 3 +#define GPIO_E 4 +#define GPIO_F 5 +#define GPIO_G 6 + +#define BP_OLED_I2C 0x01 +#define BP_OLED_SSI 0x02 +#define BP_GAMEPAD 0x04 + +typedef const struct { + const char *name; + uint32_t did0; + uint32_t did1; + uint32_t dc0; + uint32_t dc1; + uint32_t dc2; + uint32_t dc3; + uint32_t dc4; + uint32_t peripherals; +} stellaris_board_info; + +/* General purpose timer module. */ + +typedef struct gptm_state { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t config; + uint32_t mode[2]; + uint32_t control; + uint32_t state; + uint32_t mask; + uint32_t load[2]; + uint32_t match[2]; + uint32_t prescale[2]; + uint32_t match_prescale[2]; + uint32_t rtc; + int64_t tick[2]; + struct gptm_state *opaque[2]; + QEMUTimer *timer[2]; + /* The timers have an alternate output used to trigger the ADC. */ + qemu_irq trigger; + qemu_irq irq; +} gptm_state; + +static void gptm_update_irq(gptm_state *s) +{ + int level; + level = (s->state & s->mask) != 0; + qemu_set_irq(s->irq, level); +} + +static void gptm_stop(gptm_state *s, int n) +{ + qemu_del_timer(s->timer[n]); +} + +static void gptm_reload(gptm_state *s, int n, int reset) +{ + int64_t tick; + if (reset) + tick = qemu_get_clock_ns(vm_clock); + else + tick = s->tick[n]; + + if (s->config == 0) { + /* 32-bit CountDown. */ + uint32_t count; + count = s->load[0] | (s->load[1] << 16); + tick += (int64_t)count * system_clock_scale; + } else if (s->config == 1) { + /* 32-bit RTC. 1Hz tick. */ + tick += get_ticks_per_sec(); + } else if (s->mode[n] == 0xa) { + /* PWM mode. Not implemented. */ + } else { + hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); + } + s->tick[n] = tick; + qemu_mod_timer(s->timer[n], tick); +} + +static void gptm_tick(void *opaque) +{ + gptm_state **p = (gptm_state **)opaque; + gptm_state *s; + int n; + + s = *p; + n = p - s->opaque; + if (s->config == 0) { + s->state |= 1; + if ((s->control & 0x20)) { + /* Output trigger. */ + qemu_irq_pulse(s->trigger); + } + if (s->mode[0] & 1) { + /* One-shot. */ + s->control &= ~1; + } else { + /* Periodic. */ + gptm_reload(s, 0, 0); + } + } else if (s->config == 1) { + /* RTC. */ + uint32_t match; + s->rtc++; + match = s->match[0] | (s->match[1] << 16); + if (s->rtc > match) + s->rtc = 0; + if (s->rtc == 0) { + s->state |= 8; + } + gptm_reload(s, 0, 0); + } else if (s->mode[n] == 0xa) { + /* PWM mode. Not implemented. */ + } else { + hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); + } + gptm_update_irq(s); +} + +static uint64_t gptm_read(void *opaque, hwaddr offset, + unsigned size) +{ + gptm_state *s = (gptm_state *)opaque; + + switch (offset) { + case 0x00: /* CFG */ + return s->config; + case 0x04: /* TAMR */ + return s->mode[0]; + case 0x08: /* TBMR */ + return s->mode[1]; + case 0x0c: /* CTL */ + return s->control; + case 0x18: /* IMR */ + return s->mask; + case 0x1c: /* RIS */ + return s->state; + case 0x20: /* MIS */ + return s->state & s->mask; + case 0x24: /* CR */ + return 0; + case 0x28: /* TAILR */ + return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0); + case 0x2c: /* TBILR */ + return s->load[1]; + case 0x30: /* TAMARCHR */ + return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0); + case 0x34: /* TBMATCHR */ + return s->match[1]; + case 0x38: /* TAPR */ + return s->prescale[0]; + case 0x3c: /* TBPR */ + return s->prescale[1]; + case 0x40: /* TAPMR */ + return s->match_prescale[0]; + case 0x44: /* TBPMR */ + return s->match_prescale[1]; + case 0x48: /* TAR */ + if (s->control == 1) + return s->rtc; + case 0x4c: /* TBR */ + hw_error("TODO: Timer value read\n"); + default: + hw_error("gptm_read: Bad offset 0x%x\n", (int)offset); + return 0; + } +} + +static void gptm_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + gptm_state *s = (gptm_state *)opaque; + uint32_t oldval; + + /* The timers should be disabled before changing the configuration. + We take advantage of this and defer everything until the timer + is enabled. */ + switch (offset) { + case 0x00: /* CFG */ + s->config = value; + break; + case 0x04: /* TAMR */ + s->mode[0] = value; + break; + case 0x08: /* TBMR */ + s->mode[1] = value; + break; + case 0x0c: /* CTL */ + oldval = s->control; + s->control = value; + /* TODO: Implement pause. */ + if ((oldval ^ value) & 1) { + if (value & 1) { + gptm_reload(s, 0, 1); + } else { + gptm_stop(s, 0); + } + } + if (((oldval ^ value) & 0x100) && s->config >= 4) { + if (value & 0x100) { + gptm_reload(s, 1, 1); + } else { + gptm_stop(s, 1); + } + } + break; + case 0x18: /* IMR */ + s->mask = value & 0x77; + gptm_update_irq(s); + break; + case 0x24: /* CR */ + s->state &= ~value; + break; + case 0x28: /* TAILR */ + s->load[0] = value & 0xffff; + if (s->config < 4) { + s->load[1] = value >> 16; + } + break; + case 0x2c: /* TBILR */ + s->load[1] = value & 0xffff; + break; + case 0x30: /* TAMARCHR */ + s->match[0] = value & 0xffff; + if (s->config < 4) { + s->match[1] = value >> 16; + } + break; + case 0x34: /* TBMATCHR */ + s->match[1] = value >> 16; + break; + case 0x38: /* TAPR */ + s->prescale[0] = value; + break; + case 0x3c: /* TBPR */ + s->prescale[1] = value; + break; + case 0x40: /* TAPMR */ + s->match_prescale[0] = value; + break; + case 0x44: /* TBPMR */ + s->match_prescale[0] = value; + break; + default: + hw_error("gptm_write: Bad offset 0x%x\n", (int)offset); + } + gptm_update_irq(s); +} + +static const MemoryRegionOps gptm_ops = { + .read = gptm_read, + .write = gptm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_stellaris_gptm = { + .name = "stellaris_gptm", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(config, gptm_state), + VMSTATE_UINT32_ARRAY(mode, gptm_state, 2), + VMSTATE_UINT32(control, gptm_state), + VMSTATE_UINT32(state, gptm_state), + VMSTATE_UINT32(mask, gptm_state), + VMSTATE_UNUSED(8), + VMSTATE_UINT32_ARRAY(load, gptm_state, 2), + VMSTATE_UINT32_ARRAY(match, gptm_state, 2), + VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2), + VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2), + VMSTATE_UINT32(rtc, gptm_state), + VMSTATE_INT64_ARRAY(tick, gptm_state, 2), + VMSTATE_TIMER_ARRAY(timer, gptm_state, 2), + VMSTATE_END_OF_LIST() + } +}; + +static int stellaris_gptm_init(SysBusDevice *dev) +{ + gptm_state *s = FROM_SYSBUS(gptm_state, dev); + + sysbus_init_irq(dev, &s->irq); + qdev_init_gpio_out(&dev->qdev, &s->trigger, 1); + + memory_region_init_io(&s->iomem, &gptm_ops, s, + "gptm", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + + s->opaque[0] = s->opaque[1] = s; + s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]); + s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s); + return 0; +} + + +/* System controller. */ + +typedef struct { + MemoryRegion iomem; + uint32_t pborctl; + uint32_t ldopctl; + uint32_t int_status; + uint32_t int_mask; + uint32_t resc; + uint32_t rcc; + uint32_t rcc2; + uint32_t rcgc[3]; + uint32_t scgc[3]; + uint32_t dcgc[3]; + uint32_t clkvclr; + uint32_t ldoarst; + uint32_t user0; + uint32_t user1; + qemu_irq irq; + stellaris_board_info *board; +} ssys_state; + +static void ssys_update(ssys_state *s) +{ + qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0); +} + +static uint32_t pllcfg_sandstorm[16] = { + 0x31c0, /* 1 Mhz */ + 0x1ae0, /* 1.8432 Mhz */ + 0x18c0, /* 2 Mhz */ + 0xd573, /* 2.4576 Mhz */ + 0x37a6, /* 3.57954 Mhz */ + 0x1ae2, /* 3.6864 Mhz */ + 0x0c40, /* 4 Mhz */ + 0x98bc, /* 4.906 Mhz */ + 0x935b, /* 4.9152 Mhz */ + 0x09c0, /* 5 Mhz */ + 0x4dee, /* 5.12 Mhz */ + 0x0c41, /* 6 Mhz */ + 0x75db, /* 6.144 Mhz */ + 0x1ae6, /* 7.3728 Mhz */ + 0x0600, /* 8 Mhz */ + 0x585b /* 8.192 Mhz */ +}; + +static uint32_t pllcfg_fury[16] = { + 0x3200, /* 1 Mhz */ + 0x1b20, /* 1.8432 Mhz */ + 0x1900, /* 2 Mhz */ + 0xf42b, /* 2.4576 Mhz */ + 0x37e3, /* 3.57954 Mhz */ + 0x1b21, /* 3.6864 Mhz */ + 0x0c80, /* 4 Mhz */ + 0x98ee, /* 4.906 Mhz */ + 0xd5b4, /* 4.9152 Mhz */ + 0x0a00, /* 5 Mhz */ + 0x4e27, /* 5.12 Mhz */ + 0x1902, /* 6 Mhz */ + 0xec1c, /* 6.144 Mhz */ + 0x1b23, /* 7.3728 Mhz */ + 0x0640, /* 8 Mhz */ + 0xb11c /* 8.192 Mhz */ +}; + +#define DID0_VER_MASK 0x70000000 +#define DID0_VER_0 0x00000000 +#define DID0_VER_1 0x10000000 + +#define DID0_CLASS_MASK 0x00FF0000 +#define DID0_CLASS_SANDSTORM 0x00000000 +#define DID0_CLASS_FURY 0x00010000 + +static int ssys_board_class(const ssys_state *s) +{ + uint32_t did0 = s->board->did0; + switch (did0 & DID0_VER_MASK) { + case DID0_VER_0: + return DID0_CLASS_SANDSTORM; + case DID0_VER_1: + switch (did0 & DID0_CLASS_MASK) { + case DID0_CLASS_SANDSTORM: + case DID0_CLASS_FURY: + return did0 & DID0_CLASS_MASK; + } + /* for unknown classes, fall through */ + default: + hw_error("ssys_board_class: Unknown class 0x%08x\n", did0); + } +} + +static uint64_t ssys_read(void *opaque, hwaddr offset, + unsigned size) +{ + ssys_state *s = (ssys_state *)opaque; + + switch (offset) { + case 0x000: /* DID0 */ + return s->board->did0; + case 0x004: /* DID1 */ + return s->board->did1; + case 0x008: /* DC0 */ + return s->board->dc0; + case 0x010: /* DC1 */ + return s->board->dc1; + case 0x014: /* DC2 */ + return s->board->dc2; + case 0x018: /* DC3 */ + return s->board->dc3; + case 0x01c: /* DC4 */ + return s->board->dc4; + case 0x030: /* PBORCTL */ + return s->pborctl; + case 0x034: /* LDOPCTL */ + return s->ldopctl; + case 0x040: /* SRCR0 */ + return 0; + case 0x044: /* SRCR1 */ + return 0; + case 0x048: /* SRCR2 */ + return 0; + case 0x050: /* RIS */ + return s->int_status; + case 0x054: /* IMC */ + return s->int_mask; + case 0x058: /* MISC */ + return s->int_status & s->int_mask; + case 0x05c: /* RESC */ + return s->resc; + case 0x060: /* RCC */ + return s->rcc; + case 0x064: /* PLLCFG */ + { + int xtal; + xtal = (s->rcc >> 6) & 0xf; + switch (ssys_board_class(s)) { + case DID0_CLASS_FURY: + return pllcfg_fury[xtal]; + case DID0_CLASS_SANDSTORM: + return pllcfg_sandstorm[xtal]; + default: + hw_error("ssys_read: Unhandled class for PLLCFG read.\n"); + return 0; + } + } + case 0x070: /* RCC2 */ + return s->rcc2; + case 0x100: /* RCGC0 */ + return s->rcgc[0]; + case 0x104: /* RCGC1 */ + return s->rcgc[1]; + case 0x108: /* RCGC2 */ + return s->rcgc[2]; + case 0x110: /* SCGC0 */ + return s->scgc[0]; + case 0x114: /* SCGC1 */ + return s->scgc[1]; + case 0x118: /* SCGC2 */ + return s->scgc[2]; + case 0x120: /* DCGC0 */ + return s->dcgc[0]; + case 0x124: /* DCGC1 */ + return s->dcgc[1]; + case 0x128: /* DCGC2 */ + return s->dcgc[2]; + case 0x150: /* CLKVCLR */ + return s->clkvclr; + case 0x160: /* LDOARST */ + return s->ldoarst; + case 0x1e0: /* USER0 */ + return s->user0; + case 0x1e4: /* USER1 */ + return s->user1; + default: + hw_error("ssys_read: Bad offset 0x%x\n", (int)offset); + return 0; + } +} + +static bool ssys_use_rcc2(ssys_state *s) +{ + return (s->rcc2 >> 31) & 0x1; +} + +/* + * Caculate the sys. clock period in ms. + */ +static void ssys_calculate_system_clock(ssys_state *s) +{ + if (ssys_use_rcc2(s)) { + system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1); + } else { + system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); + } +} + +static void ssys_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + ssys_state *s = (ssys_state *)opaque; + + switch (offset) { + case 0x030: /* PBORCTL */ + s->pborctl = value & 0xffff; + break; + case 0x034: /* LDOPCTL */ + s->ldopctl = value & 0x1f; + break; + case 0x040: /* SRCR0 */ + case 0x044: /* SRCR1 */ + case 0x048: /* SRCR2 */ + fprintf(stderr, "Peripheral reset not implemented\n"); + break; + case 0x054: /* IMC */ + s->int_mask = value & 0x7f; + break; + case 0x058: /* MISC */ + s->int_status &= ~value; + break; + case 0x05c: /* RESC */ + s->resc = value & 0x3f; + break; + case 0x060: /* RCC */ + if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { + /* PLL enable. */ + s->int_status |= (1 << 6); + } + s->rcc = value; + ssys_calculate_system_clock(s); + break; + case 0x070: /* RCC2 */ + if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) { + break; + } + + if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { + /* PLL enable. */ + s->int_status |= (1 << 6); + } + s->rcc2 = value; + ssys_calculate_system_clock(s); + break; + case 0x100: /* RCGC0 */ + s->rcgc[0] = value; + break; + case 0x104: /* RCGC1 */ + s->rcgc[1] = value; + break; + case 0x108: /* RCGC2 */ + s->rcgc[2] = value; + break; + case 0x110: /* SCGC0 */ + s->scgc[0] = value; + break; + case 0x114: /* SCGC1 */ + s->scgc[1] = value; + break; + case 0x118: /* SCGC2 */ + s->scgc[2] = value; + break; + case 0x120: /* DCGC0 */ + s->dcgc[0] = value; + break; + case 0x124: /* DCGC1 */ + s->dcgc[1] = value; + break; + case 0x128: /* DCGC2 */ + s->dcgc[2] = value; + break; + case 0x150: /* CLKVCLR */ + s->clkvclr = value; + break; + case 0x160: /* LDOARST */ + s->ldoarst = value; + break; + default: + hw_error("ssys_write: Bad offset 0x%x\n", (int)offset); + } + ssys_update(s); +} + +static const MemoryRegionOps ssys_ops = { + .read = ssys_read, + .write = ssys_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ssys_reset(void *opaque) +{ + ssys_state *s = (ssys_state *)opaque; + + s->pborctl = 0x7ffd; + s->rcc = 0x078e3ac0; + + if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) { + s->rcc2 = 0; + } else { + s->rcc2 = 0x07802810; + } + s->rcgc[0] = 1; + s->scgc[0] = 1; + s->dcgc[0] = 1; + ssys_calculate_system_clock(s); +} + +static int stellaris_sys_post_load(void *opaque, int version_id) +{ + ssys_state *s = opaque; + + ssys_calculate_system_clock(s); + + return 0; +} + +static const VMStateDescription vmstate_stellaris_sys = { + .name = "stellaris_sys", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = stellaris_sys_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(pborctl, ssys_state), + VMSTATE_UINT32(ldopctl, ssys_state), + VMSTATE_UINT32(int_mask, ssys_state), + VMSTATE_UINT32(int_status, ssys_state), + VMSTATE_UINT32(resc, ssys_state), + VMSTATE_UINT32(rcc, ssys_state), + VMSTATE_UINT32_V(rcc2, ssys_state, 2), + VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3), + VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3), + VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3), + VMSTATE_UINT32(clkvclr, ssys_state), + VMSTATE_UINT32(ldoarst, ssys_state), + VMSTATE_END_OF_LIST() + } +}; + +static int stellaris_sys_init(uint32_t base, qemu_irq irq, + stellaris_board_info * board, + uint8_t *macaddr) +{ + ssys_state *s; + + s = (ssys_state *)g_malloc0(sizeof(ssys_state)); + s->irq = irq; + s->board = board; + /* Most devices come preprogrammed with a MAC address in the user data. */ + s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16); + s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16); + + memory_region_init_io(&s->iomem, &ssys_ops, s, "ssys", 0x00001000); + memory_region_add_subregion(get_system_memory(), base, &s->iomem); + ssys_reset(s); + vmstate_register(NULL, -1, &vmstate_stellaris_sys, s); + return 0; +} + + +/* I2C controller. */ + +typedef struct { + SysBusDevice busdev; + i2c_bus *bus; + qemu_irq irq; + MemoryRegion iomem; + uint32_t msa; + uint32_t mcs; + uint32_t mdr; + uint32_t mtpr; + uint32_t mimr; + uint32_t mris; + uint32_t mcr; +} stellaris_i2c_state; + +#define STELLARIS_I2C_MCS_BUSY 0x01 +#define STELLARIS_I2C_MCS_ERROR 0x02 +#define STELLARIS_I2C_MCS_ADRACK 0x04 +#define STELLARIS_I2C_MCS_DATACK 0x08 +#define STELLARIS_I2C_MCS_ARBLST 0x10 +#define STELLARIS_I2C_MCS_IDLE 0x20 +#define STELLARIS_I2C_MCS_BUSBSY 0x40 + +static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset, + unsigned size) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + switch (offset) { + case 0x00: /* MSA */ + return s->msa; + case 0x04: /* MCS */ + /* We don't emulate timing, so the controller is never busy. */ + return s->mcs | STELLARIS_I2C_MCS_IDLE; + case 0x08: /* MDR */ + return s->mdr; + case 0x0c: /* MTPR */ + return s->mtpr; + case 0x10: /* MIMR */ + return s->mimr; + case 0x14: /* MRIS */ + return s->mris; + case 0x18: /* MMIS */ + return s->mris & s->mimr; + case 0x20: /* MCR */ + return s->mcr; + default: + hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset); + return 0; + } +} + +static void stellaris_i2c_update(stellaris_i2c_state *s) +{ + int level; + + level = (s->mris & s->mimr) != 0; + qemu_set_irq(s->irq, level); +} + +static void stellaris_i2c_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + switch (offset) { + case 0x00: /* MSA */ + s->msa = value & 0xff; + break; + case 0x04: /* MCS */ + if ((s->mcr & 0x10) == 0) { + /* Disabled. Do nothing. */ + break; + } + /* Grab the bus if this is starting a transfer. */ + if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { + if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) { + s->mcs |= STELLARIS_I2C_MCS_ARBLST; + } else { + s->mcs &= ~STELLARIS_I2C_MCS_ARBLST; + s->mcs |= STELLARIS_I2C_MCS_BUSBSY; + } + } + /* If we don't have the bus then indicate an error. */ + if (!i2c_bus_busy(s->bus) + || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { + s->mcs |= STELLARIS_I2C_MCS_ERROR; + break; + } + s->mcs &= ~STELLARIS_I2C_MCS_ERROR; + if (value & 1) { + /* Transfer a byte. */ + /* TODO: Handle errors. */ + if (s->msa & 1) { + /* Recv */ + s->mdr = i2c_recv(s->bus) & 0xff; + } else { + /* Send */ + i2c_send(s->bus, s->mdr); + } + /* Raise an interrupt. */ + s->mris |= 1; + } + if (value & 4) { + /* Finish transfer. */ + i2c_end_transfer(s->bus); + s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY; + } + break; + case 0x08: /* MDR */ + s->mdr = value & 0xff; + break; + case 0x0c: /* MTPR */ + s->mtpr = value & 0xff; + break; + case 0x10: /* MIMR */ + s->mimr = 1; + break; + case 0x1c: /* MICR */ + s->mris &= ~value; + break; + case 0x20: /* MCR */ + if (value & 1) + hw_error( + "stellaris_i2c_write: Loopback not implemented\n"); + if (value & 0x20) + hw_error( + "stellaris_i2c_write: Slave mode not implemented\n"); + s->mcr = value & 0x31; + break; + default: + hw_error("stellaris_i2c_write: Bad offset 0x%x\n", + (int)offset); + } + stellaris_i2c_update(s); +} + +static void stellaris_i2c_reset(stellaris_i2c_state *s) +{ + if (s->mcs & STELLARIS_I2C_MCS_BUSBSY) + i2c_end_transfer(s->bus); + + s->msa = 0; + s->mcs = 0; + s->mdr = 0; + s->mtpr = 1; + s->mimr = 0; + s->mris = 0; + s->mcr = 0; + stellaris_i2c_update(s); +} + +static const MemoryRegionOps stellaris_i2c_ops = { + .read = stellaris_i2c_read, + .write = stellaris_i2c_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_stellaris_i2c = { + .name = "stellaris_i2c", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(msa, stellaris_i2c_state), + VMSTATE_UINT32(mcs, stellaris_i2c_state), + VMSTATE_UINT32(mdr, stellaris_i2c_state), + VMSTATE_UINT32(mtpr, stellaris_i2c_state), + VMSTATE_UINT32(mimr, stellaris_i2c_state), + VMSTATE_UINT32(mris, stellaris_i2c_state), + VMSTATE_UINT32(mcr, stellaris_i2c_state), + VMSTATE_END_OF_LIST() + } +}; + +static int stellaris_i2c_init(SysBusDevice * dev) +{ + stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev); + i2c_bus *bus; + + sysbus_init_irq(dev, &s->irq); + bus = i2c_init_bus(&dev->qdev, "i2c"); + s->bus = bus; + + memory_region_init_io(&s->iomem, &stellaris_i2c_ops, s, + "i2c", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + /* ??? For now we only implement the master interface. */ + stellaris_i2c_reset(s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s); + return 0; +} + +/* Analogue to Digital Converter. This is only partially implemented, + enough for applications that use a combined ADC and timer tick. */ + +#define STELLARIS_ADC_EM_CONTROLLER 0 +#define STELLARIS_ADC_EM_COMP 1 +#define STELLARIS_ADC_EM_EXTERNAL 4 +#define STELLARIS_ADC_EM_TIMER 5 +#define STELLARIS_ADC_EM_PWM0 6 +#define STELLARIS_ADC_EM_PWM1 7 +#define STELLARIS_ADC_EM_PWM2 8 + +#define STELLARIS_ADC_FIFO_EMPTY 0x0100 +#define STELLARIS_ADC_FIFO_FULL 0x1000 + +typedef struct +{ + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t actss; + uint32_t ris; + uint32_t im; + uint32_t emux; + uint32_t ostat; + uint32_t ustat; + uint32_t sspri; + uint32_t sac; + struct { + uint32_t state; + uint32_t data[16]; + } fifo[4]; + uint32_t ssmux[4]; + uint32_t ssctl[4]; + uint32_t noise; + qemu_irq irq[4]; +} stellaris_adc_state; + +static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) +{ + int tail; + + tail = s->fifo[n].state & 0xf; + if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) { + s->ustat |= 1 << n; + } else { + s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf); + s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL; + if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf)) + s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY; + } + return s->fifo[n].data[tail]; +} + +static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, + uint32_t value) +{ + int head; + + /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry + FIFO fir each sequencer. */ + head = (s->fifo[n].state >> 4) & 0xf; + if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) { + s->ostat |= 1 << n; + return; + } + s->fifo[n].data[head] = value; + head = (head + 1) & 0xf; + s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY; + s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4); + if ((s->fifo[n].state & 0xf) == head) + s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL; +} + +static void stellaris_adc_update(stellaris_adc_state *s) +{ + int level; + int n; + + for (n = 0; n < 4; n++) { + level = (s->ris & s->im & (1 << n)) != 0; + qemu_set_irq(s->irq[n], level); + } +} + +static void stellaris_adc_trigger(void *opaque, int irq, int level) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + int n; + + for (n = 0; n < 4; n++) { + if ((s->actss & (1 << n)) == 0) { + continue; + } + + if (((s->emux >> (n * 4)) & 0xff) != 5) { + continue; + } + + /* Some applications use the ADC as a random number source, so introduce + some variation into the signal. */ + s->noise = s->noise * 314159 + 1; + /* ??? actual inputs not implemented. Return an arbitrary value. */ + stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7)); + s->ris |= (1 << n); + stellaris_adc_update(s); + } +} + +static void stellaris_adc_reset(stellaris_adc_state *s) +{ + int n; + + for (n = 0; n < 4; n++) { + s->ssmux[n] = 0; + s->ssctl[n] = 0; + s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY; + } +} + +static uint64_t stellaris_adc_read(void *opaque, hwaddr offset, + unsigned size) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + + /* TODO: Implement this. */ + if (offset >= 0x40 && offset < 0xc0) { + int n; + n = (offset - 0x40) >> 5; + switch (offset & 0x1f) { + case 0x00: /* SSMUX */ + return s->ssmux[n]; + case 0x04: /* SSCTL */ + return s->ssctl[n]; + case 0x08: /* SSFIFO */ + return stellaris_adc_fifo_read(s, n); + case 0x0c: /* SSFSTAT */ + return s->fifo[n].state; + default: + break; + } + } + switch (offset) { + case 0x00: /* ACTSS */ + return s->actss; + case 0x04: /* RIS */ + return s->ris; + case 0x08: /* IM */ + return s->im; + case 0x0c: /* ISC */ + return s->ris & s->im; + case 0x10: /* OSTAT */ + return s->ostat; + case 0x14: /* EMUX */ + return s->emux; + case 0x18: /* USTAT */ + return s->ustat; + case 0x20: /* SSPRI */ + return s->sspri; + case 0x30: /* SAC */ + return s->sac; + default: + hw_error("strllaris_adc_read: Bad offset 0x%x\n", + (int)offset); + return 0; + } +} + +static void stellaris_adc_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + + /* TODO: Implement this. */ + if (offset >= 0x40 && offset < 0xc0) { + int n; + n = (offset - 0x40) >> 5; + switch (offset & 0x1f) { + case 0x00: /* SSMUX */ + s->ssmux[n] = value & 0x33333333; + return; + case 0x04: /* SSCTL */ + if (value != 6) { + hw_error("ADC: Unimplemented sequence %" PRIx64 "\n", + value); + } + s->ssctl[n] = value; + return; + default: + break; + } + } + switch (offset) { + case 0x00: /* ACTSS */ + s->actss = value & 0xf; + break; + case 0x08: /* IM */ + s->im = value; + break; + case 0x0c: /* ISC */ + s->ris &= ~value; + break; + case 0x10: /* OSTAT */ + s->ostat &= ~value; + break; + case 0x14: /* EMUX */ + s->emux = value; + break; + case 0x18: /* USTAT */ + s->ustat &= ~value; + break; + case 0x20: /* SSPRI */ + s->sspri = value; + break; + case 0x28: /* PSSI */ + hw_error("Not implemented: ADC sample initiate\n"); + break; + case 0x30: /* SAC */ + s->sac = value; + break; + default: + hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset); + } + stellaris_adc_update(s); +} + +static const MemoryRegionOps stellaris_adc_ops = { + .read = stellaris_adc_read, + .write = stellaris_adc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_stellaris_adc = { + .name = "stellaris_adc", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(actss, stellaris_adc_state), + VMSTATE_UINT32(ris, stellaris_adc_state), + VMSTATE_UINT32(im, stellaris_adc_state), + VMSTATE_UINT32(emux, stellaris_adc_state), + VMSTATE_UINT32(ostat, stellaris_adc_state), + VMSTATE_UINT32(ustat, stellaris_adc_state), + VMSTATE_UINT32(sspri, stellaris_adc_state), + VMSTATE_UINT32(sac, stellaris_adc_state), + VMSTATE_UINT32(fifo[0].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[0], stellaris_adc_state), + VMSTATE_UINT32(ssctl[0], stellaris_adc_state), + VMSTATE_UINT32(fifo[1].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[1], stellaris_adc_state), + VMSTATE_UINT32(ssctl[1], stellaris_adc_state), + VMSTATE_UINT32(fifo[2].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[2], stellaris_adc_state), + VMSTATE_UINT32(ssctl[2], stellaris_adc_state), + VMSTATE_UINT32(fifo[3].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[3], stellaris_adc_state), + VMSTATE_UINT32(ssctl[3], stellaris_adc_state), + VMSTATE_UINT32(noise, stellaris_adc_state), + VMSTATE_END_OF_LIST() + } +}; + +static int stellaris_adc_init(SysBusDevice *dev) +{ + stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev); + int n; + + for (n = 0; n < 4; n++) { + sysbus_init_irq(dev, &s->irq[n]); + } + + memory_region_init_io(&s->iomem, &stellaris_adc_ops, s, + "adc", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + stellaris_adc_reset(s); + qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s); + return 0; +} + +/* Board init. */ +static stellaris_board_info stellaris_boards[] = { + { "LM3S811EVB", + 0, + 0x0032000e, + 0x001f001f, /* dc0 */ + 0x001132bf, + 0x01071013, + 0x3f0f01ff, + 0x0000001f, + BP_OLED_I2C + }, + { "LM3S6965EVB", + 0x10010002, + 0x1073402e, + 0x00ff007f, /* dc0 */ + 0x001133ff, + 0x030f5317, + 0x0f0f87ff, + 0x5000007f, + BP_OLED_SSI | BP_GAMEPAD + } +}; + +static void stellaris_init(const char *kernel_filename, const char *cpu_model, + stellaris_board_info *board) +{ + static const int uart_irq[] = {5, 6, 33, 34}; + static const int timer_irq[] = {19, 21, 23, 35}; + static const uint32_t gpio_addr[7] = + { 0x40004000, 0x40005000, 0x40006000, 0x40007000, + 0x40024000, 0x40025000, 0x40026000}; + static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; + + MemoryRegion *address_space_mem = get_system_memory(); + qemu_irq *pic; + DeviceState *gpio_dev[7]; + qemu_irq gpio_in[7][8]; + qemu_irq gpio_out[7][8]; + qemu_irq adc; + int sram_size; + int flash_size; + i2c_bus *i2c; + DeviceState *dev; + int i; + int j; + + flash_size = ((board->dc0 & 0xffff) + 1) << 1; + sram_size = (board->dc0 >> 18) + 1; + pic = armv7m_init(address_space_mem, + flash_size, sram_size, kernel_filename, cpu_model); + + if (board->dc1 & (1 << 16)) { + dev = sysbus_create_varargs("stellaris-adc", 0x40038000, + pic[14], pic[15], pic[16], pic[17], NULL); + adc = qdev_get_gpio_in(dev, 0); + } else { + adc = NULL; + } + for (i = 0; i < 4; i++) { + if (board->dc2 & (0x10000 << i)) { + dev = sysbus_create_simple("stellaris-gptm", + 0x40030000 + i * 0x1000, + pic[timer_irq[i]]); + /* TODO: This is incorrect, but we get away with it because + the ADC output is only ever pulsed. */ + qdev_connect_gpio_out(dev, 0, adc); + } + } + + stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a); + + for (i = 0; i < 7; i++) { + if (board->dc4 & (1 << i)) { + gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i], + pic[gpio_irq[i]]); + for (j = 0; j < 8; j++) { + gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j); + gpio_out[i][j] = NULL; + } + } + } + + if (board->dc2 & (1 << 12)) { + dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]); + i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); + if (board->peripherals & BP_OLED_I2C) { + i2c_create_slave(i2c, "ssd0303", 0x3d); + } + } + + for (i = 0; i < 4; i++) { + if (board->dc2 & (1 << i)) { + sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000, + pic[uart_irq[i]]); + } + } + if (board->dc2 & (1 << 4)) { + dev = sysbus_create_simple("pl022", 0x40008000, pic[7]); + if (board->peripherals & BP_OLED_SSI) { + void *bus; + DeviceState *sddev; + DeviceState *ssddev; + + /* Some boards have both an OLED controller and SD card connected to + * the same SSI port, with the SD card chip select connected to a + * GPIO pin. Technically the OLED chip select is connected to the + * SSI Fss pin. We do not bother emulating that as both devices + * should never be selected simultaneously, and our OLED controller + * ignores stray 0xff commands that occur when deselecting the SD + * card. + */ + bus = qdev_get_child_bus(dev, "ssi"); + + sddev = ssi_create_slave(bus, "ssi-sd"); + ssddev = ssi_create_slave(bus, "ssd0323"); + gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0), + qdev_get_gpio_in(ssddev, 0)); + gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1); + + /* Make sure the select pin is high. */ + qemu_irq_raise(gpio_out[GPIO_D][0]); + } + } + if (board->dc4 & (1 << 28)) { + DeviceState *enet; + + qemu_check_nic_model(&nd_table[0], "stellaris"); + + enet = qdev_create(NULL, "stellaris_enet"); + qdev_set_nic_properties(enet, &nd_table[0]); + qdev_init_nofail(enet); + sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000); + sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, pic[42]); + } + if (board->peripherals & BP_GAMEPAD) { + qemu_irq gpad_irq[5]; + static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; + + gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */ + gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */ + gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */ + gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */ + gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */ + + stellaris_gamepad_init(5, gpad_irq, gpad_keycode); + } + for (i = 0; i < 7; i++) { + if (board->dc4 & (1 << i)) { + for (j = 0; j < 8; j++) { + if (gpio_out[i][j]) { + qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]); + } + } + } + } +} + +/* FIXME: Figure out how to generate these from stellaris_boards. */ +static void lm3s811evb_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]); +} + +static void lm3s6965evb_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); +} + +static QEMUMachine lm3s811evb_machine = { + .name = "lm3s811evb", + .desc = "Stellaris LM3S811EVB", + .init = lm3s811evb_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine lm3s6965evb_machine = { + .name = "lm3s6965evb", + .desc = "Stellaris LM3S6965EVB", + .init = lm3s6965evb_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void stellaris_machine_init(void) +{ + qemu_register_machine(&lm3s811evb_machine); + qemu_register_machine(&lm3s6965evb_machine); +} + +machine_init(stellaris_machine_init); + +static void stellaris_i2c_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = stellaris_i2c_init; +} + +static const TypeInfo stellaris_i2c_info = { + .name = "stellaris-i2c", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(stellaris_i2c_state), + .class_init = stellaris_i2c_class_init, +}; + +static void stellaris_gptm_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = stellaris_gptm_init; +} + +static const TypeInfo stellaris_gptm_info = { + .name = "stellaris-gptm", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(gptm_state), + .class_init = stellaris_gptm_class_init, +}; + +static void stellaris_adc_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = stellaris_adc_init; +} + +static const TypeInfo stellaris_adc_info = { + .name = "stellaris-adc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(stellaris_adc_state), + .class_init = stellaris_adc_class_init, +}; + +static void stellaris_register_types(void) +{ + type_register_static(&stellaris_i2c_info); + type_register_static(&stellaris_gptm_info); + type_register_static(&stellaris_adc_info); +} + +type_init(stellaris_register_types) diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c new file mode 100644 index 0000000000..747888c64e --- /dev/null +++ b/hw/arm/tosa.c @@ -0,0 +1,302 @@ +/* vim:set shiftwidth=4 ts=4 et: */ +/* + * PXA255 Sharp Zaurus SL-6000 PDA platform + * + * Copyright (c) 2008 Dmitry Baryshkov + * + * Code based on spitz platform by Andrzej Zaborowski + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/sharpsl.h" +#include "hw/pcmcia.h" +#include "block/block.h" +#include "hw/boards.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "sysemu/blockdev.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + +#define TOSA_RAM 0x04000000 +#define TOSA_ROM 0x00800000 + +#define TOSA_GPIO_USB_IN (5) +#define TOSA_GPIO_nSD_DETECT (9) +#define TOSA_GPIO_ON_RESET (19) +#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */ +#define TOSA_GPIO_CF_CD (13) +#define TOSA_GPIO_TC6393XB_INT (15) +#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */ + +#define TOSA_SCOOP_GPIO_BASE 1 +#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2) +#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3) +#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4) + +#define TOSA_SCOOP_JC_GPIO_BASE 1 +#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0) +#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1) +#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2) +#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5) +#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7) + +#define DAC_BASE 0x4e +#define DAC_CH1 0 +#define DAC_CH2 1 + +static void tosa_microdrive_attach(PXA2xxState *cpu) +{ + PCMCIACardState *md; + DriveInfo *dinfo; + + dinfo = drive_get(IF_IDE, 0, 0); + if (!dinfo || dinfo->media_cd) + return; + md = dscm1xxxx_init(dinfo); + pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); +} + +static void tosa_out_switch(void *opaque, int line, int level) +{ + switch (line) { + case 0: + fprintf(stderr, "blue LED %s.\n", level ? "on" : "off"); + break; + case 1: + fprintf(stderr, "green LED %s.\n", level ? "on" : "off"); + break; + case 2: + fprintf(stderr, "amber LED %s.\n", level ? "on" : "off"); + break; + case 3: + fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off"); + break; + default: + fprintf(stderr, "Uhandled out event: %d = %d\n", line, level); + break; + } +} + + +static void tosa_gpio_setup(PXA2xxState *cpu, + DeviceState *scp0, + DeviceState *scp1, + TC6393xbState *tmio) +{ + qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4); + /* MMC/SD host */ + pxa2xx_mmci_handlers(cpu->mmc, + qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP), + qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT))); + + /* Handle reset */ + qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset); + + /* PCMCIA signals: card's IRQ and Card-Detect */ + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], + qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ), + qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD)); + + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], + qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ), + NULL); + + qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]); + qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]); + qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]); + qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]); + + qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio)); + + /* UDC Vbus */ + qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN)); +} + +static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value) +{ + fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f); + return 0; +} + +static int tosa_ssp_init(SSISlave *dev) +{ + /* Nothing to do. */ + return 0; +} + +typedef struct { + I2CSlave i2c; + int len; + char buf[3]; +} TosaDACState; + +static int tosa_dac_send(I2CSlave *i2c, uint8_t data) +{ + TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c); + s->buf[s->len] = data; + if (s->len ++ > 2) { +#ifdef VERBOSE + fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len); +#endif + return 1; + } + + if (s->len == 2) { + fprintf(stderr, "dac: channel %d value 0x%02x\n", + s->buf[0], s->buf[1]); + } + + return 0; +} + +static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) +{ + TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c); + s->len = 0; + switch (event) { + case I2C_START_SEND: + break; + case I2C_START_RECV: + printf("%s: recv not supported!!!\n", __FUNCTION__); + break; + case I2C_FINISH: +#ifdef VERBOSE + if (s->len < 2) + printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len); + if (s->len > 2) + printf("%s: message too long\n", __FUNCTION__); +#endif + break; + default: + break; + } +} + +static int tosa_dac_recv(I2CSlave *s) +{ + printf("%s: recv not supported!!!\n", __FUNCTION__); + return -1; +} + +static int tosa_dac_init(I2CSlave *i2c) +{ + /* Nothing to do. */ + return 0; +} + +static void tosa_tg_init(PXA2xxState *cpu) +{ + i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); + i2c_create_slave(bus, "tosa_dac", DAC_BASE); + ssi_create_slave(cpu->ssp[1], "tosa-ssp"); +} + + +static struct arm_boot_info tosa_binfo = { + .loader_start = PXA2XX_SDRAM_BASE, + .ram_size = 0x04000000, +}; + +static void tosa_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *rom = g_new(MemoryRegion, 1); + PXA2xxState *mpu; + TC6393xbState *tmio; + DeviceState *scp0, *scp1; + + if (!cpu_model) + cpu_model = "pxa255"; + + mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); + + memory_region_init_ram(rom, "tosa.rom", TOSA_ROM); + vmstate_register_ram_global(rom); + memory_region_set_readonly(rom, true); + memory_region_add_subregion(address_space_mem, 0, rom); + + tmio = tc6393xb_init(address_space_mem, 0x10000000, + qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT)); + + scp0 = sysbus_create_simple("scoop", 0x08800000, NULL); + scp1 = sysbus_create_simple("scoop", 0x14800040, NULL); + + tosa_gpio_setup(mpu, scp0, scp1, tmio); + + tosa_microdrive_attach(mpu); + + tosa_tg_init(mpu); + + tosa_binfo.kernel_filename = kernel_filename; + tosa_binfo.kernel_cmdline = kernel_cmdline; + tosa_binfo.initrd_filename = initrd_filename; + tosa_binfo.board_id = 0x208; + arm_load_kernel(mpu->cpu, &tosa_binfo); + sl_bootparam_write(SL_PXA_PARAM_BASE); +} + +static QEMUMachine tosapda_machine = { + .name = "tosa", + .desc = "Tosa PDA (PXA255)", + .init = tosa_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void tosapda_machine_init(void) +{ + qemu_register_machine(&tosapda_machine); +} + +machine_init(tosapda_machine_init); + +static void tosa_dac_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = tosa_dac_init; + k->event = tosa_dac_event; + k->recv = tosa_dac_recv; + k->send = tosa_dac_send; +} + +static const TypeInfo tosa_dac_info = { + .name = "tosa_dac", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(TosaDACState), + .class_init = tosa_dac_class_init, +}; + +static void tosa_ssp_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = tosa_ssp_init; + k->transfer = tosa_ssp_tansfer; +} + +static const TypeInfo tosa_ssp_info = { + .name = "tosa-ssp", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(SSISlave), + .class_init = tosa_ssp_class_init, +}; + +static void tosa_register_types(void) +{ + type_register_static(&tosa_dac_info); + type_register_static(&tosa_ssp_info); +} + +type_init(tosa_register_types) diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c new file mode 100644 index 0000000000..baaa265888 --- /dev/null +++ b/hw/arm/versatilepb.c @@ -0,0 +1,403 @@ +/* + * ARM Versatile Platform/Application Baseboard System emulation. + * + * Copyright (c) 2005-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL. + */ + +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/pci/pci.h" +#include "hw/i2c.h" +#include "hw/boards.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" +#include "hw/flash.h" + +#define VERSATILE_FLASH_ADDR 0x34000000 +#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) +#define VERSATILE_FLASH_SECT_SIZE (256 * 1024) + +/* Primary interrupt controller. */ + +typedef struct vpb_sic_state +{ + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t level; + uint32_t mask; + uint32_t pic_enable; + qemu_irq parent[32]; + int irq; +} vpb_sic_state; + +static const VMStateDescription vmstate_vpb_sic = { + .name = "versatilepb_sic", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(level, vpb_sic_state), + VMSTATE_UINT32(mask, vpb_sic_state), + VMSTATE_UINT32(pic_enable, vpb_sic_state), + VMSTATE_END_OF_LIST() + } +}; + +static void vpb_sic_update(vpb_sic_state *s) +{ + uint32_t flags; + + flags = s->level & s->mask; + qemu_set_irq(s->parent[s->irq], flags != 0); +} + +static void vpb_sic_update_pic(vpb_sic_state *s) +{ + int i; + uint32_t mask; + + for (i = 21; i <= 30; i++) { + mask = 1u << i; + if (!(s->pic_enable & mask)) + continue; + qemu_set_irq(s->parent[i], (s->level & mask) != 0); + } +} + +static void vpb_sic_set_irq(void *opaque, int irq, int level) +{ + vpb_sic_state *s = (vpb_sic_state *)opaque; + if (level) + s->level |= 1u << irq; + else + s->level &= ~(1u << irq); + if (s->pic_enable & (1u << irq)) + qemu_set_irq(s->parent[irq], level); + vpb_sic_update(s); +} + +static uint64_t vpb_sic_read(void *opaque, hwaddr offset, + unsigned size) +{ + vpb_sic_state *s = (vpb_sic_state *)opaque; + + switch (offset >> 2) { + case 0: /* STATUS */ + return s->level & s->mask; + case 1: /* RAWSTAT */ + return s->level; + case 2: /* ENABLE */ + return s->mask; + case 4: /* SOFTINT */ + return s->level & 1; + case 8: /* PICENABLE */ + return s->pic_enable; + default: + printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset); + return 0; + } +} + +static void vpb_sic_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + vpb_sic_state *s = (vpb_sic_state *)opaque; + + switch (offset >> 2) { + case 2: /* ENSET */ + s->mask |= value; + break; + case 3: /* ENCLR */ + s->mask &= ~value; + break; + case 4: /* SOFTINTSET */ + if (value) + s->mask |= 1; + break; + case 5: /* SOFTINTCLR */ + if (value) + s->mask &= ~1u; + break; + case 8: /* PICENSET */ + s->pic_enable |= (value & 0x7fe00000); + vpb_sic_update_pic(s); + break; + case 9: /* PICENCLR */ + s->pic_enable &= ~value; + vpb_sic_update_pic(s); + break; + default: + printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset); + return; + } + vpb_sic_update(s); +} + +static const MemoryRegionOps vpb_sic_ops = { + .read = vpb_sic_read, + .write = vpb_sic_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int vpb_sic_init(SysBusDevice *dev) +{ + vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev); + int i; + + qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32); + for (i = 0; i < 32; i++) { + sysbus_init_irq(dev, &s->parent[i]); + } + s->irq = 31; + memory_region_init_io(&s->iomem, &vpb_sic_ops, s, "vpb-sic", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +/* Board init. */ + +/* The AB and PB boards both use the same core, just with different + peripherals and expansion busses. For now we emulate a subset of the + PB peripherals and just change the board ID. */ + +static struct arm_boot_info versatile_binfo; + +static void versatile_init(QEMUMachineInitArgs *args, int board_id) +{ + ARMCPU *cpu; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + qemu_irq *cpu_pic; + qemu_irq pic[32]; + qemu_irq sic[32]; + DeviceState *dev, *sysctl; + SysBusDevice *busdev; + DeviceState *pl041; + PCIBus *pci_bus; + NICInfo *nd; + i2c_bus *i2c; + int n; + int done_smc = 0; + DriveInfo *dinfo; + + if (!args->cpu_model) { + args->cpu_model = "arm926"; + } + cpu = cpu_arm_init(args->cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + memory_region_init_ram(ram, "versatile.ram", args->ram_size); + vmstate_register_ram_global(ram); + /* ??? RAM should repeat to fill physical memory space. */ + /* SDRAM at address zero. */ + memory_region_add_subregion(sysmem, 0, ram); + + sysctl = qdev_create(NULL, "realview_sysctl"); + qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004); + qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000); + qdev_init_nofail(sysctl); + sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); + + cpu_pic = arm_pic_init_cpu(cpu); + dev = sysbus_create_varargs("pl190", 0x10140000, + cpu_pic[ARM_PIC_CPU_IRQ], + cpu_pic[ARM_PIC_CPU_FIQ], NULL); + for (n = 0; n < 32; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL); + for (n = 0; n < 32; n++) { + sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]); + sic[n] = qdev_get_gpio_in(dev, n); + } + + sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]); + sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]); + + dev = qdev_create(NULL, "versatile_pci"); + busdev = SYS_BUS_DEVICE(dev); + qdev_init_nofail(dev); + sysbus_mmio_map(busdev, 0, 0x41000000); /* PCI self-config */ + sysbus_mmio_map(busdev, 1, 0x42000000); /* PCI config */ + sysbus_connect_irq(busdev, 0, sic[27]); + sysbus_connect_irq(busdev, 1, sic[28]); + sysbus_connect_irq(busdev, 2, sic[29]); + sysbus_connect_irq(busdev, 3, sic[30]); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); + + /* The Versatile PCI bridge does not provide access to PCI IO space, + so many of the qemu PCI devices are not useable. */ + for(n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + + if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) { + smc91c111_init(nd, 0x10010000, sic[25]); + done_smc = 1; + } else { + pci_nic_init_nofail(nd, "rtl8139", NULL); + } + } + if (usb_enabled(false)) { + pci_create_simple(pci_bus, -1, "pci-ohci"); + } + n = drive_get_max_bus(IF_SCSI); + while (n >= 0) { + pci_create_simple(pci_bus, -1, "lsi53c895a"); + n--; + } + + sysbus_create_simple("pl011", 0x101f1000, pic[12]); + sysbus_create_simple("pl011", 0x101f2000, pic[13]); + sysbus_create_simple("pl011", 0x101f3000, pic[14]); + sysbus_create_simple("pl011", 0x10009000, sic[6]); + + sysbus_create_simple("pl080", 0x10130000, pic[17]); + sysbus_create_simple("sp804", 0x101e2000, pic[4]); + sysbus_create_simple("sp804", 0x101e3000, pic[5]); + + sysbus_create_simple("pl061", 0x101e4000, pic[6]); + sysbus_create_simple("pl061", 0x101e5000, pic[7]); + sysbus_create_simple("pl061", 0x101e6000, pic[8]); + sysbus_create_simple("pl061", 0x101e7000, pic[9]); + + /* The versatile/PB actually has a modified Color LCD controller + that includes hardware cursor support from the PL111. */ + dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]); + /* Wire up the mux control signals from the SYS_CLCD register */ + qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0)); + + sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL); + sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL); + + /* Add PL031 Real Time Clock. */ + sysbus_create_simple("pl031", 0x101e8000, pic[10]); + + dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); + i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); + i2c_create_slave(i2c, "ds1338", 0x68); + + /* Add PL041 AACI Interface to the LM4549 codec */ + pl041 = qdev_create(NULL, "pl041"); + qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); + qdev_init_nofail(pl041); + sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); + sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]); + + /* Memory map for Versatile/PB: */ + /* 0x10000000 System registers. */ + /* 0x10001000 PCI controller config registers. */ + /* 0x10002000 Serial bus interface. */ + /* 0x10003000 Secondary interrupt controller. */ + /* 0x10004000 AACI (audio). */ + /* 0x10005000 MMCI0. */ + /* 0x10006000 KMI0 (keyboard). */ + /* 0x10007000 KMI1 (mouse). */ + /* 0x10008000 Character LCD Interface. */ + /* 0x10009000 UART3. */ + /* 0x1000a000 Smart card 1. */ + /* 0x1000b000 MMCI1. */ + /* 0x10010000 Ethernet. */ + /* 0x10020000 USB. */ + /* 0x10100000 SSMC. */ + /* 0x10110000 MPMC. */ + /* 0x10120000 CLCD Controller. */ + /* 0x10130000 DMA Controller. */ + /* 0x10140000 Vectored interrupt controller. */ + /* 0x101d0000 AHB Monitor Interface. */ + /* 0x101e0000 System Controller. */ + /* 0x101e1000 Watchdog Interface. */ + /* 0x101e2000 Timer 0/1. */ + /* 0x101e3000 Timer 2/3. */ + /* 0x101e4000 GPIO port 0. */ + /* 0x101e5000 GPIO port 1. */ + /* 0x101e6000 GPIO port 2. */ + /* 0x101e7000 GPIO port 3. */ + /* 0x101e8000 RTC. */ + /* 0x101f0000 Smart card 0. */ + /* 0x101f1000 UART0. */ + /* 0x101f2000 UART1. */ + /* 0x101f3000 UART2. */ + /* 0x101f4000 SSPI. */ + /* 0x34000000 NOR Flash */ + + dinfo = drive_get(IF_PFLASH, 0, 0); + if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash", + VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, + VERSATILE_FLASH_SECT_SIZE, + VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE, + 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + } + + versatile_binfo.ram_size = args->ram_size; + versatile_binfo.kernel_filename = args->kernel_filename; + versatile_binfo.kernel_cmdline = args->kernel_cmdline; + versatile_binfo.initrd_filename = args->initrd_filename; + versatile_binfo.board_id = board_id; + arm_load_kernel(cpu, &versatile_binfo); +} + +static void vpb_init(QEMUMachineInitArgs *args) +{ + versatile_init(args, 0x183); +} + +static void vab_init(QEMUMachineInitArgs *args) +{ + versatile_init(args, 0x25e); +} + +static QEMUMachine versatilepb_machine = { + .name = "versatilepb", + .desc = "ARM Versatile/PB (ARM926EJ-S)", + .init = vpb_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine versatileab_machine = { + .name = "versatileab", + .desc = "ARM Versatile/AB (ARM926EJ-S)", + .init = vab_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static void versatile_machine_init(void) +{ + qemu_register_machine(&versatilepb_machine); + qemu_register_machine(&versatileab_machine); +} + +machine_init(versatile_machine_init); + +static void vpb_sic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = vpb_sic_init; + dc->no_user = 1; + dc->vmsd = &vmstate_vpb_sic; +} + +static const TypeInfo vpb_sic_info = { + .name = "versatilepb_sic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(vpb_sic_state), + .class_init = vpb_sic_class_init, +}; + +static void versatilepb_register_types(void) +{ + type_register_static(&vpb_sic_info); +} + +type_init(versatilepb_register_types) diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c new file mode 100644 index 0000000000..02922c38b3 --- /dev/null +++ b/hw/arm/vexpress.c @@ -0,0 +1,500 @@ +/* + * ARM Versatile Express emulation. + * + * Copyright (c) 2010 - 2011 B Labs Ltd. + * Copyright (c) 2011 Linaro Limited + * Written by Bahadir Balban, Amit Mahajan, Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/primecell.h" +#include "hw/devices.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "exec/address-spaces.h" +#include "sysemu/blockdev.h" +#include "hw/flash.h" + +#define VEXPRESS_BOARD_ID 0x8e0 +#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) +#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024) + +static struct arm_boot_info vexpress_binfo; + +/* Address maps for peripherals: + * the Versatile Express motherboard has two possible maps, + * the "legacy" one (used for A9) and the "Cortex-A Series" + * map (used for newer cores). + * Individual daughterboards can also have different maps for + * their peripherals. + */ + +enum { + VE_SYSREGS, + VE_SP810, + VE_SERIALPCI, + VE_PL041, + VE_MMCI, + VE_KMI0, + VE_KMI1, + VE_UART0, + VE_UART1, + VE_UART2, + VE_UART3, + VE_WDT, + VE_TIMER01, + VE_TIMER23, + VE_SERIALDVI, + VE_RTC, + VE_COMPACTFLASH, + VE_CLCD, + VE_NORFLASH0, + VE_NORFLASH1, + VE_SRAM, + VE_VIDEORAM, + VE_ETHERNET, + VE_USB, + VE_DAPROM, +}; + +static hwaddr motherboard_legacy_map[] = { + /* CS7: 0x10000000 .. 0x10020000 */ + [VE_SYSREGS] = 0x10000000, + [VE_SP810] = 0x10001000, + [VE_SERIALPCI] = 0x10002000, + [VE_PL041] = 0x10004000, + [VE_MMCI] = 0x10005000, + [VE_KMI0] = 0x10006000, + [VE_KMI1] = 0x10007000, + [VE_UART0] = 0x10009000, + [VE_UART1] = 0x1000a000, + [VE_UART2] = 0x1000b000, + [VE_UART3] = 0x1000c000, + [VE_WDT] = 0x1000f000, + [VE_TIMER01] = 0x10011000, + [VE_TIMER23] = 0x10012000, + [VE_SERIALDVI] = 0x10016000, + [VE_RTC] = 0x10017000, + [VE_COMPACTFLASH] = 0x1001a000, + [VE_CLCD] = 0x1001f000, + /* CS0: 0x40000000 .. 0x44000000 */ + [VE_NORFLASH0] = 0x40000000, + /* CS1: 0x44000000 .. 0x48000000 */ + [VE_NORFLASH1] = 0x44000000, + /* CS2: 0x48000000 .. 0x4a000000 */ + [VE_SRAM] = 0x48000000, + /* CS3: 0x4c000000 .. 0x50000000 */ + [VE_VIDEORAM] = 0x4c000000, + [VE_ETHERNET] = 0x4e000000, + [VE_USB] = 0x4f000000, +}; + +static hwaddr motherboard_aseries_map[] = { + /* CS0: 0x08000000 .. 0x0c000000 */ + [VE_NORFLASH0] = 0x08000000, + /* CS4: 0x0c000000 .. 0x10000000 */ + [VE_NORFLASH1] = 0x0c000000, + /* CS5: 0x10000000 .. 0x14000000 */ + /* CS1: 0x14000000 .. 0x18000000 */ + [VE_SRAM] = 0x14000000, + /* CS2: 0x18000000 .. 0x1c000000 */ + [VE_VIDEORAM] = 0x18000000, + [VE_ETHERNET] = 0x1a000000, + [VE_USB] = 0x1b000000, + /* CS3: 0x1c000000 .. 0x20000000 */ + [VE_DAPROM] = 0x1c000000, + [VE_SYSREGS] = 0x1c010000, + [VE_SP810] = 0x1c020000, + [VE_SERIALPCI] = 0x1c030000, + [VE_PL041] = 0x1c040000, + [VE_MMCI] = 0x1c050000, + [VE_KMI0] = 0x1c060000, + [VE_KMI1] = 0x1c070000, + [VE_UART0] = 0x1c090000, + [VE_UART1] = 0x1c0a0000, + [VE_UART2] = 0x1c0b0000, + [VE_UART3] = 0x1c0c0000, + [VE_WDT] = 0x1c0f0000, + [VE_TIMER01] = 0x1c110000, + [VE_TIMER23] = 0x1c120000, + [VE_SERIALDVI] = 0x1c160000, + [VE_RTC] = 0x1c170000, + [VE_COMPACTFLASH] = 0x1c1a0000, + [VE_CLCD] = 0x1c1f0000, +}; + +/* Structure defining the peculiarities of a specific daughterboard */ + +typedef struct VEDBoardInfo VEDBoardInfo; + +typedef void DBoardInitFn(const VEDBoardInfo *daughterboard, + ram_addr_t ram_size, + const char *cpu_model, + qemu_irq *pic, uint32_t *proc_id); + +struct VEDBoardInfo { + const hwaddr *motherboard_map; + hwaddr loader_start; + const hwaddr gic_cpu_if_addr; + DBoardInitFn *init; +}; + +static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, + ram_addr_t ram_size, + const char *cpu_model, + qemu_irq *pic, uint32_t *proc_id) +{ + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *lowram = g_new(MemoryRegion, 1); + DeviceState *dev; + SysBusDevice *busdev; + qemu_irq *irqp; + int n; + qemu_irq cpu_irq[4]; + ram_addr_t low_ram_size; + + if (!cpu_model) { + cpu_model = "cortex-a9"; + } + + *proc_id = 0x0c000191; + + for (n = 0; n < smp_cpus; n++) { + ARMCPU *cpu = cpu_arm_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + irqp = arm_pic_init_cpu(cpu); + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + } + + if (ram_size > 0x40000000) { + /* 1GB is the maximum the address space permits */ + fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n"); + exit(1); + } + + memory_region_init_ram(ram, "vexpress.highmem", ram_size); + vmstate_register_ram_global(ram); + low_ram_size = ram_size; + if (low_ram_size > 0x4000000) { + low_ram_size = 0x4000000; + } + /* RAM is from 0x60000000 upwards. The bottom 64MB of the + * address space should in theory be remappable to various + * things including ROM or RAM; we always map the RAM there. + */ + memory_region_init_alias(lowram, "vexpress.lowmem", ram, 0, low_ram_size); + memory_region_add_subregion(sysmem, 0x0, lowram); + memory_region_add_subregion(sysmem, 0x60000000, ram); + + /* 0x1e000000 A9MPCore (SCU) private memory region */ + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0x1e000000); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } + /* Interrupts [42:0] are from the motherboard; + * [47:43] are reserved; [63:48] are daughterboard + * peripherals. Note that some documentation numbers + * external interrupts starting from 32 (because the + * A9MP has internal interrupts 0..31). + */ + for (n = 0; n < 64; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ + + /* 0x10020000 PL111 CLCD (daughterboard) */ + sysbus_create_simple("pl111", 0x10020000, pic[44]); + + /* 0x10060000 AXI RAM */ + /* 0x100e0000 PL341 Dynamic Memory Controller */ + /* 0x100e1000 PL354 Static Memory Controller */ + /* 0x100e2000 System Configuration Controller */ + + sysbus_create_simple("sp804", 0x100e4000, pic[48]); + /* 0x100e5000 SP805 Watchdog module */ + /* 0x100e6000 BP147 TrustZone Protection Controller */ + /* 0x100e9000 PL301 'Fast' AXI matrix */ + /* 0x100ea000 PL301 'Slow' AXI matrix */ + /* 0x100ec000 TrustZone Address Space Controller */ + /* 0x10200000 CoreSight debug APB */ + /* 0x1e00a000 PL310 L2 Cache Controller */ + sysbus_create_varargs("l2x0", 0x1e00a000, NULL); +} + +static const VEDBoardInfo a9_daughterboard = { + .motherboard_map = motherboard_legacy_map, + .loader_start = 0x60000000, + .gic_cpu_if_addr = 0x1e000100, + .init = a9_daughterboard_init, +}; + +static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, + ram_addr_t ram_size, + const char *cpu_model, + qemu_irq *pic, uint32_t *proc_id) +{ + int n; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); + qemu_irq cpu_irq[4]; + DeviceState *dev; + SysBusDevice *busdev; + + if (!cpu_model) { + cpu_model = "cortex-a15"; + } + + *proc_id = 0x14000237; + + for (n = 0; n < smp_cpus; n++) { + ARMCPU *cpu; + qemu_irq *irqp; + + cpu = cpu_arm_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + irqp = arm_pic_init_cpu(cpu); + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + } + + { + /* We have to use a separate 64 bit variable here to avoid the gcc + * "comparison is always false due to limited range of data type" + * warning if we are on a host where ram_addr_t is 32 bits. + */ + uint64_t rsz = ram_size; + if (rsz > (30ULL * 1024 * 1024 * 1024)) { + fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n"); + exit(1); + } + } + + memory_region_init_ram(ram, "vexpress.highmem", ram_size); + vmstate_register_ram_global(ram); + /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */ + memory_region_add_subregion(sysmem, 0x80000000, ram); + + /* 0x2c000000 A15MPCore private memory region (GIC) */ + dev = qdev_create(NULL, "a15mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0x2c000000); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } + /* Interrupts [42:0] are from the motherboard; + * [47:43] are reserved; [63:48] are daughterboard + * peripherals. Note that some documentation numbers + * external interrupts starting from 32 (because there + * are internal interrupts 0..31). + */ + for (n = 0; n < 64; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + /* A15 daughterboard peripherals: */ + + /* 0x20000000: CoreSight interfaces: not modelled */ + /* 0x2a000000: PL301 AXI interconnect: not modelled */ + /* 0x2a420000: SCC: not modelled */ + /* 0x2a430000: system counter: not modelled */ + /* 0x2b000000: HDLCD controller: not modelled */ + /* 0x2b060000: SP805 watchdog: not modelled */ + /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */ + /* 0x2e000000: system SRAM */ + memory_region_init_ram(sram, "vexpress.a15sram", 0x10000); + vmstate_register_ram_global(sram); + memory_region_add_subregion(sysmem, 0x2e000000, sram); + + /* 0x7ffb0000: DMA330 DMA controller: not modelled */ + /* 0x7ffd0000: PL354 static memory controller: not modelled */ +} + +static const VEDBoardInfo a15_daughterboard = { + .motherboard_map = motherboard_aseries_map, + .loader_start = 0x80000000, + .gic_cpu_if_addr = 0x2c002000, + .init = a15_daughterboard_init, +}; + +static void vexpress_common_init(const VEDBoardInfo *daughterboard, + QEMUMachineInitArgs *args) +{ + DeviceState *dev, *sysctl, *pl041; + qemu_irq pic[64]; + uint32_t proc_id; + uint32_t sys_id; + DriveInfo *dinfo; + ram_addr_t vram_size, sram_size; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *vram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); + const hwaddr *map = daughterboard->motherboard_map; + + daughterboard->init(daughterboard, args->ram_size, args->cpu_model, + pic, &proc_id); + + /* Motherboard peripherals: the wiring is the same but the + * addresses vary between the legacy and A-Series memory maps. + */ + + sys_id = 0x1190f500; + + sysctl = qdev_create(NULL, "realview_sysctl"); + qdev_prop_set_uint32(sysctl, "sys_id", sys_id); + qdev_prop_set_uint32(sysctl, "proc_id", proc_id); + qdev_init_nofail(sysctl); + sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); + + /* VE_SP810: not modelled */ + /* VE_SERIALPCI: not modelled */ + + pl041 = qdev_create(NULL, "pl041"); + qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); + qdev_init_nofail(pl041); + sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); + sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); + + dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL); + /* Wire up MMC card detect and read-only signals */ + qdev_connect_gpio_out(dev, 0, + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT)); + qdev_connect_gpio_out(dev, 1, + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN)); + + sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]); + sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]); + + sysbus_create_simple("pl011", map[VE_UART0], pic[5]); + sysbus_create_simple("pl011", map[VE_UART1], pic[6]); + sysbus_create_simple("pl011", map[VE_UART2], pic[7]); + sysbus_create_simple("pl011", map[VE_UART3], pic[8]); + + sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); + sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); + + /* VE_SERIALDVI: not modelled */ + + sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */ + + /* VE_COMPACTFLASH: not modelled */ + + sysbus_create_simple("pl111", map[VE_CLCD], pic[14]); + + dinfo = drive_get_next(IF_PFLASH); + if (!pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0", + VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, + VEXPRESS_FLASH_SECT_SIZE, + VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4, + 0x00, 0x89, 0x00, 0x18, 0)) { + fprintf(stderr, "vexpress: error registering flash 0.\n"); + exit(1); + } + + dinfo = drive_get_next(IF_PFLASH); + if (!pflash_cfi01_register(map[VE_NORFLASH1], NULL, "vexpress.flash1", + VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, + VEXPRESS_FLASH_SECT_SIZE, + VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4, + 0x00, 0x89, 0x00, 0x18, 0)) { + fprintf(stderr, "vexpress: error registering flash 1.\n"); + exit(1); + } + + sram_size = 0x2000000; + memory_region_init_ram(sram, "vexpress.sram", sram_size); + vmstate_register_ram_global(sram); + memory_region_add_subregion(sysmem, map[VE_SRAM], sram); + + vram_size = 0x800000; + memory_region_init_ram(vram, "vexpress.vram", vram_size); + vmstate_register_ram_global(vram); + memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram); + + /* 0x4e000000 LAN9118 Ethernet */ + if (nd_table[0].used) { + lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]); + } + + /* VE_USB: not modelled */ + + /* VE_DAPROM: not modelled */ + + vexpress_binfo.ram_size = args->ram_size; + vexpress_binfo.kernel_filename = args->kernel_filename; + vexpress_binfo.kernel_cmdline = args->kernel_cmdline; + vexpress_binfo.initrd_filename = args->initrd_filename; + vexpress_binfo.nb_cpus = smp_cpus; + vexpress_binfo.board_id = VEXPRESS_BOARD_ID; + vexpress_binfo.loader_start = daughterboard->loader_start; + vexpress_binfo.smp_loader_start = map[VE_SRAM]; + vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30; + vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr; + arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo); +} + +static void vexpress_a9_init(QEMUMachineInitArgs *args) +{ + vexpress_common_init(&a9_daughterboard, args); +} + +static void vexpress_a15_init(QEMUMachineInitArgs *args) +{ + vexpress_common_init(&a15_daughterboard, args); +} + +static QEMUMachine vexpress_a9_machine = { + .name = "vexpress-a9", + .desc = "ARM Versatile Express for Cortex-A9", + .init = vexpress_a9_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine vexpress_a15_machine = { + .name = "vexpress-a15", + .desc = "ARM Versatile Express for Cortex-A15", + .init = vexpress_a15_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static void vexpress_machine_init(void) +{ + qemu_register_machine(&vexpress_a9_machine); + qemu_register_machine(&vexpress_a15_machine); +} + +machine_init(vexpress_machine_init); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c new file mode 100644 index 0000000000..f78c47e43e --- /dev/null +++ b/hw/arm/xilinx_zynq.c @@ -0,0 +1,224 @@ +/* + * Xilinx Zynq Baseboard System emulation. + * + * Copyright (c) 2010 Xilinx. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com) + * Copyright (c) 2012 Petalogix Pty Ltd. + * Written by Haibing Ma + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "net/net.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/flash.h" +#include "sysemu/blockdev.h" +#include "hw/loader.h" +#include "hw/ssi.h" + +#define NUM_SPI_FLASHES 4 +#define NUM_QSPI_FLASHES 2 +#define NUM_QSPI_BUSSES 2 + +#define FLASH_SIZE (64 * 1024 * 1024) +#define FLASH_SECTOR_SIZE (128 * 1024) + +#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */ + +static struct arm_boot_info zynq_binfo = {}; + +static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) +{ + DeviceState *dev; + SysBusDevice *s; + + qemu_check_nic_model(nd, "cadence_gem"); + dev = qdev_create(NULL, "cadence_gem"); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(s, 0, base); + sysbus_connect_irq(s, 0, irq); +} + +static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, + bool is_qspi) +{ + DeviceState *dev; + SysBusDevice *busdev; + SSIBus *spi; + DeviceState *flash_dev; + int i, j; + int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1; + int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES; + + dev = qdev_create(NULL, "xilinx,spips"); + qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1); + qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); + qdev_prop_set_uint8(dev, "num-busses", num_busses); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, base_addr); + if (is_qspi) { + sysbus_mmio_map(busdev, 1, 0xFC000000); + } + sysbus_connect_irq(busdev, 0, irq); + + for (i = 0; i < num_busses; ++i) { + char bus_name[16]; + qemu_irq cs_line; + + snprintf(bus_name, 16, "spi%d", i); + spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); + + for (j = 0; j < num_ss; ++j) { + flash_dev = ssi_create_slave_no_init(spi, "n25q128"); + qdev_init_nofail(flash_dev); + + cs_line = qdev_get_gpio_in(flash_dev, 0); + sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); + } + } + +} + +static void zynq_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + ARMCPU *cpu; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ext_ram = g_new(MemoryRegion, 1); + MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); + DeviceState *dev; + SysBusDevice *busdev; + qemu_irq *irqp; + qemu_irq pic[64]; + NICInfo *nd; + int n; + qemu_irq cpu_irq; + + if (!cpu_model) { + cpu_model = "cortex-a9"; + } + + cpu = cpu_arm_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + irqp = arm_pic_init_cpu(cpu); + cpu_irq = irqp[ARM_PIC_CPU_IRQ]; + + /* max 2GB ram */ + if (ram_size > 0x80000000) { + ram_size = 0x80000000; + } + + /* DDR remapped to address zero. */ + memory_region_init_ram(ext_ram, "zynq.ext_ram", ram_size); + vmstate_register_ram_global(ext_ram); + memory_region_add_subregion(address_space_mem, 0, ext_ram); + + /* 256K of on-chip memory */ + memory_region_init_ram(ocm_ram, "zynq.ocm_ram", 256 << 10); + vmstate_register_ram_global(ocm_ram); + memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram); + + DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); + + /* AMD */ + pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE, + dinfo ? dinfo->bdrv : NULL, FLASH_SECTOR_SIZE, + FLASH_SIZE/FLASH_SECTOR_SIZE, 1, + 1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa, + 0); + + dev = qdev_create(NULL, "xilinx,zynq_slcr"); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); + + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", 1); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0xF8F00000); + sysbus_connect_irq(busdev, 0, cpu_irq); + + for (n = 0; n < 64; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false); + zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false); + zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true); + + sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); + sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]); + + sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); + sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); + + sysbus_create_varargs("cadence_ttc", 0xF8001000, + pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL); + sysbus_create_varargs("cadence_ttc", 0xF8002000, + pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL); + + for (n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + if (n == 0) { + gem_init(nd, 0xE000B000, pic[54-IRQ_OFFSET]); + } else if (n == 1) { + gem_init(nd, 0xE000C000, pic[77-IRQ_OFFSET]); + } + } + + dev = qdev_create(NULL, "generic-sdhci"); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); + + dev = qdev_create(NULL, "generic-sdhci"); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); + + zynq_binfo.ram_size = ram_size; + zynq_binfo.kernel_filename = kernel_filename; + zynq_binfo.kernel_cmdline = kernel_cmdline; + zynq_binfo.initrd_filename = initrd_filename; + zynq_binfo.nb_cpus = 1; + zynq_binfo.board_id = 0xd32; + zynq_binfo.loader_start = 0; + arm_load_kernel(arm_env_get_cpu(first_cpu), &zynq_binfo); +} + +static QEMUMachine zynq_machine = { + .name = "xilinx-zynq-a9", + .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9", + .init = zynq_init, + .block_default_type = IF_SCSI, + .max_cpus = 1, + .no_sdcard = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void zynq_machine_init(void) +{ + qemu_register_machine(&zynq_machine); +} + +machine_init(zynq_machine_init); diff --git a/hw/arm/z2.c b/hw/arm/z2.c new file mode 100644 index 0000000000..cbb6d8085e --- /dev/null +++ b/hw/arm/z2.c @@ -0,0 +1,384 @@ +/* + * PXA270-based Zipit Z2 device + * + * Copyright (c) 2011 by Vasily Khoruzhick + * + * Code is based on mainstone platform. + * + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "hw/flash.h" +#include "sysemu/blockdev.h" +#include "ui/console.h" +#include "audio/audio.h" +#include "exec/address-spaces.h" + +#ifdef DEBUG_Z2 +#define DPRINTF(fmt, ...) \ + printf(fmt, ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) +#endif + +static struct keymap map[0x100] = { + [0 ... 0xff] = { -1, -1 }, + [0x3b] = {0, 0}, /* Option = F1 */ + [0xc8] = {0, 1}, /* Up */ + [0xd0] = {0, 2}, /* Down */ + [0xcb] = {0, 3}, /* Left */ + [0xcd] = {0, 4}, /* Right */ + [0xcf] = {0, 5}, /* End */ + [0x0d] = {0, 6}, /* KPPLUS */ + [0xc7] = {1, 0}, /* Home */ + [0x10] = {1, 1}, /* Q */ + [0x17] = {1, 2}, /* I */ + [0x22] = {1, 3}, /* G */ + [0x2d] = {1, 4}, /* X */ + [0x1c] = {1, 5}, /* Enter */ + [0x0c] = {1, 6}, /* KPMINUS */ + [0xc9] = {2, 0}, /* PageUp */ + [0x11] = {2, 1}, /* W */ + [0x18] = {2, 2}, /* O */ + [0x23] = {2, 3}, /* H */ + [0x2e] = {2, 4}, /* C */ + [0x38] = {2, 5}, /* LeftAlt */ + [0xd1] = {3, 0}, /* PageDown */ + [0x12] = {3, 1}, /* E */ + [0x19] = {3, 2}, /* P */ + [0x24] = {3, 3}, /* J */ + [0x2f] = {3, 4}, /* V */ + [0x2a] = {3, 5}, /* LeftShift */ + [0x01] = {4, 0}, /* Esc */ + [0x13] = {4, 1}, /* R */ + [0x1e] = {4, 2}, /* A */ + [0x25] = {4, 3}, /* K */ + [0x30] = {4, 4}, /* B */ + [0x1d] = {4, 5}, /* LeftCtrl */ + [0x0f] = {5, 0}, /* Tab */ + [0x14] = {5, 1}, /* T */ + [0x1f] = {5, 2}, /* S */ + [0x26] = {5, 3}, /* L */ + [0x31] = {5, 4}, /* N */ + [0x39] = {5, 5}, /* Space */ + [0x3c] = {6, 0}, /* Stop = F2 */ + [0x15] = {6, 1}, /* Y */ + [0x20] = {6, 2}, /* D */ + [0x0e] = {6, 3}, /* Backspace */ + [0x32] = {6, 4}, /* M */ + [0x33] = {6, 5}, /* Comma */ + [0x3d] = {7, 0}, /* Play = F3 */ + [0x16] = {7, 1}, /* U */ + [0x21] = {7, 2}, /* F */ + [0x2c] = {7, 3}, /* Z */ + [0x27] = {7, 4}, /* Semicolon */ + [0x34] = {7, 5}, /* Dot */ +}; + +#define Z2_RAM_SIZE 0x02000000 +#define Z2_FLASH_BASE 0x00000000 +#define Z2_FLASH_SIZE 0x00800000 + +static struct arm_boot_info z2_binfo = { + .loader_start = PXA2XX_SDRAM_BASE, + .ram_size = Z2_RAM_SIZE, +}; + +#define Z2_GPIO_SD_DETECT 96 +#define Z2_GPIO_AC_IN 0 +#define Z2_GPIO_KEY_ON 1 +#define Z2_GPIO_LCD_CS 88 + +typedef struct { + SSISlave ssidev; + int32_t selected; + int32_t enabled; + uint8_t buf[3]; + uint32_t cur_reg; + int pos; +} ZipitLCD; + +static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value) +{ + ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); + uint16_t val; + if (z->selected) { + z->buf[z->pos] = value & 0xff; + z->pos++; + } + if (z->pos == 3) { + switch (z->buf[0]) { + case 0x74: + DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]); + z->cur_reg = z->buf[2]; + break; + case 0x76: + val = z->buf[1] << 8 | z->buf[2]; + DPRINTF("%s: value: 0x%.4x\n", __func__, val); + if (z->cur_reg == 0x22 && val == 0x0000) { + z->enabled = 1; + printf("%s: LCD enabled\n", __func__); + } else if (z->cur_reg == 0x10 && val == 0x0000) { + z->enabled = 0; + printf("%s: LCD disabled\n", __func__); + } + break; + default: + DPRINTF("%s: unknown command!\n", __func__); + break; + } + z->pos = 0; + } + return 0; +} + +static void z2_lcd_cs(void *opaque, int line, int level) +{ + ZipitLCD *z2_lcd = opaque; + z2_lcd->selected = !level; +} + +static int zipit_lcd_init(SSISlave *dev) +{ + ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); + z->selected = 0; + z->enabled = 0; + z->pos = 0; + + return 0; +} + +static VMStateDescription vmstate_zipit_lcd_state = { + .name = "zipit-lcd", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), + VMSTATE_INT32(selected, ZipitLCD), + VMSTATE_INT32(enabled, ZipitLCD), + VMSTATE_BUFFER(buf, ZipitLCD), + VMSTATE_UINT32(cur_reg, ZipitLCD), + VMSTATE_INT32(pos, ZipitLCD), + VMSTATE_END_OF_LIST(), + } +}; + +static void zipit_lcd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = zipit_lcd_init; + k->transfer = zipit_lcd_transfer; + dc->vmsd = &vmstate_zipit_lcd_state; +} + +static const TypeInfo zipit_lcd_info = { + .name = "zipit-lcd", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(ZipitLCD), + .class_init = zipit_lcd_class_init, +}; + +typedef struct { + I2CSlave i2c; + int len; + uint8_t buf[3]; +} AER915State; + +static int aer915_send(I2CSlave *i2c, uint8_t data) +{ + AER915State *s = FROM_I2C_SLAVE(AER915State, i2c); + s->buf[s->len] = data; + if (s->len++ > 2) { + DPRINTF("%s: message too long (%i bytes)\n", + __func__, s->len); + return 1; + } + + if (s->len == 2) { + DPRINTF("%s: reg %d value 0x%02x\n", __func__, + s->buf[0], s->buf[1]); + } + + return 0; +} + +static void aer915_event(I2CSlave *i2c, enum i2c_event event) +{ + AER915State *s = FROM_I2C_SLAVE(AER915State, i2c); + switch (event) { + case I2C_START_SEND: + s->len = 0; + break; + case I2C_START_RECV: + if (s->len != 1) { + DPRINTF("%s: short message!?\n", __func__); + } + break; + case I2C_FINISH: + break; + default: + break; + } +} + +static int aer915_recv(I2CSlave *slave) +{ + int retval = 0x00; + AER915State *s = FROM_I2C_SLAVE(AER915State, slave); + + switch (s->buf[0]) { + /* Return hardcoded battery voltage, + * 0xf0 means ~4.1V + */ + case 0x02: + retval = 0xf0; + break; + /* Return 0x00 for other regs, + * we don't know what they are for, + * anyway they return 0x00 on real hardware. + */ + default: + break; + } + + return retval; +} + +static int aer915_init(I2CSlave *i2c) +{ + /* Nothing to do. */ + return 0; +} + +static VMStateDescription vmstate_aer915_state = { + .name = "aer915", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(len, AER915State), + VMSTATE_BUFFER(buf, AER915State), + VMSTATE_END_OF_LIST(), + } +}; + +static void aer915_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = aer915_init; + k->event = aer915_event; + k->recv = aer915_recv; + k->send = aer915_send; + dc->vmsd = &vmstate_aer915_state; +} + +static const TypeInfo aer915_info = { + .name = "aer915", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(AER915State), + .class_init = aer915_class_init, +}; + +static void z2_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + MemoryRegion *address_space_mem = get_system_memory(); + uint32_t sector_len = 0x10000; + PXA2xxState *mpu; + DriveInfo *dinfo; + int be; + void *z2_lcd; + i2c_bus *bus; + DeviceState *wm; + + if (!cpu_model) { + cpu_model = "pxa270-c5"; + } + + /* Setup CPU & memory */ + mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model); + +#ifdef TARGET_WORDS_BIGENDIAN + be = 1; +#else + be = 0; +#endif + dinfo = drive_get(IF_PFLASH, 0, 0); + if (!dinfo) { + fprintf(stderr, "Flash image must be given with the " + "'pflash' parameter\n"); + exit(1); + } + + if (!pflash_cfi01_register(Z2_FLASH_BASE, + NULL, "z2.flash0", Z2_FLASH_SIZE, + dinfo->bdrv, sector_len, + Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0, + be)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + exit(1); + } + + /* setup keypad */ + pxa27x_register_keypad(mpu->kp, map, 0x100); + + /* MMC/SD host */ + pxa2xx_mmci_handlers(mpu->mmc, + NULL, + qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT)); + + type_register_static(&zipit_lcd_info); + type_register_static(&aer915_info); + z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd"); + bus = pxa2xx_i2c_bus(mpu->i2c[0]); + i2c_create_slave(bus, "aer915", 0x55); + wm = i2c_create_slave(bus, "wm8750", 0x1b); + mpu->i2s->opaque = wm; + mpu->i2s->codec_out = wm8750_dac_dat; + mpu->i2s->codec_in = wm8750_adc_dat; + wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s); + + qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS, + qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]); + + if (kernel_filename) { + z2_binfo.kernel_filename = kernel_filename; + z2_binfo.kernel_cmdline = kernel_cmdline; + z2_binfo.initrd_filename = initrd_filename; + z2_binfo.board_id = 0x6dd; + arm_load_kernel(mpu->cpu, &z2_binfo); + } +} + +static QEMUMachine z2_machine = { + .name = "z2", + .desc = "Zipit Z2 (PXA27x)", + .init = z2_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void z2_machine_init(void) +{ + qemu_register_machine(&z2_machine); +} + +machine_init(z2_machine_init); diff --git a/hw/arm_boot.c b/hw/arm_boot.c deleted file mode 100644 index 43253fd34a..0000000000 --- a/hw/arm_boot.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * ARM kernel loader. - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "config.h" -#include "hw/hw.h" -#include "hw/arm-misc.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "sysemu/device_tree.h" -#include "qemu/config-file.h" - -#define KERNEL_ARGS_ADDR 0x100 -#define KERNEL_LOAD_ADDR 0x00010000 - -/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ -static uint32_t bootloader[] = { - 0xe3a00000, /* mov r0, #0 */ - 0xe59f1004, /* ldr r1, [pc, #4] */ - 0xe59f2004, /* ldr r2, [pc, #4] */ - 0xe59ff004, /* ldr pc, [pc, #4] */ - 0, /* Board ID */ - 0, /* Address of kernel args. Set by integratorcp_init. */ - 0 /* Kernel entry point. Set by integratorcp_init. */ -}; - -/* Handling for secondary CPU boot in a multicore system. - * Unlike the uniprocessor/primary CPU boot, this is platform - * dependent. The default code here is based on the secondary - * CPU boot protocol used on realview/vexpress boards, with - * some parameterisation to increase its flexibility. - * QEMU platform models for which this code is not appropriate - * should override write_secondary_boot and secondary_cpu_reset_hook - * instead. - * - * This code enables the interrupt controllers for the secondary - * CPUs and then puts all the secondary CPUs into a loop waiting - * for an interprocessor interrupt and polling a configurable - * location for the kernel secondary CPU entry point. - */ -#define DSB_INSN 0xf57ff04f -#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */ - -static uint32_t smpboot[] = { - 0xe59f2028, /* ldr r2, gic_cpu_if */ - 0xe59f0028, /* ldr r0, startaddr */ - 0xe3a01001, /* mov r1, #1 */ - 0xe5821000, /* str r1, [r2] - set GICC_CTLR.Enable */ - 0xe3a010ff, /* mov r1, #0xff */ - 0xe5821004, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */ - DSB_INSN, /* dsb */ - 0xe320f003, /* wfi */ - 0xe5901000, /* ldr r1, [r0] */ - 0xe1110001, /* tst r1, r1 */ - 0x0afffffb, /* beq */ - 0xe12fff11, /* bx r1 */ - 0, /* gic_cpu_if: base address of GIC CPU interface */ - 0 /* bootreg: Boot register address is held here */ -}; - -static void default_write_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - int n; - smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; - smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; - for (n = 0; n < ARRAY_SIZE(smpboot); n++) { - /* Replace DSB with the pre-v7 DSB if necessary. */ - if (!arm_feature(&cpu->env, ARM_FEATURE_V7) && - smpboot[n] == DSB_INSN) { - smpboot[n] = CP15_DSB_INSN; - } - smpboot[n] = tswap32(smpboot[n]); - } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); -} - -static void default_reset_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - CPUARMState *env = &cpu->env; - - stl_phys_notdirty(info->smp_bootreg_addr, 0); - env->regs[15] = info->smp_loader_start; -} - -#define WRITE_WORD(p, value) do { \ - stl_phys_notdirty(p, value); \ - p += 4; \ -} while (0) - -static void set_kernel_args(const struct arm_boot_info *info) -{ - int initrd_size = info->initrd_size; - hwaddr base = info->loader_start; - hwaddr p; - - p = base + KERNEL_ARGS_ADDR; - /* ATAG_CORE */ - WRITE_WORD(p, 5); - WRITE_WORD(p, 0x54410001); - WRITE_WORD(p, 1); - WRITE_WORD(p, 0x1000); - WRITE_WORD(p, 0); - /* ATAG_MEM */ - /* TODO: handle multiple chips on one ATAG list */ - WRITE_WORD(p, 4); - WRITE_WORD(p, 0x54410002); - WRITE_WORD(p, info->ram_size); - WRITE_WORD(p, info->loader_start); - if (initrd_size) { - /* ATAG_INITRD2 */ - WRITE_WORD(p, 4); - WRITE_WORD(p, 0x54420005); - WRITE_WORD(p, info->initrd_start); - WRITE_WORD(p, initrd_size); - } - if (info->kernel_cmdline && *info->kernel_cmdline) { - /* ATAG_CMDLINE */ - int cmdline_size; - - cmdline_size = strlen(info->kernel_cmdline); - cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline, - cmdline_size + 1); - cmdline_size = (cmdline_size >> 2) + 1; - WRITE_WORD(p, cmdline_size + 2); - WRITE_WORD(p, 0x54410009); - p += cmdline_size * 4; - } - if (info->atag_board) { - /* ATAG_BOARD */ - int atag_board_len; - uint8_t atag_board_buf[0x1000]; - - atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3; - WRITE_WORD(p, (atag_board_len + 8) >> 2); - WRITE_WORD(p, 0x414f4d50); - cpu_physical_memory_write(p, atag_board_buf, atag_board_len); - p += atag_board_len; - } - /* ATAG_END */ - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); -} - -static void set_kernel_args_old(const struct arm_boot_info *info) -{ - hwaddr p; - const char *s; - int initrd_size = info->initrd_size; - hwaddr base = info->loader_start; - - /* see linux/include/asm-arm/setup.h */ - p = base + KERNEL_ARGS_ADDR; - /* page_size */ - WRITE_WORD(p, 4096); - /* nr_pages */ - WRITE_WORD(p, info->ram_size / 4096); - /* ramdisk_size */ - WRITE_WORD(p, 0); -#define FLAG_READONLY 1 -#define FLAG_RDLOAD 4 -#define FLAG_RDPROMPT 8 - /* flags */ - WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT); - /* rootdev */ - WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */ - /* video_num_cols */ - WRITE_WORD(p, 0); - /* video_num_rows */ - WRITE_WORD(p, 0); - /* video_x */ - WRITE_WORD(p, 0); - /* video_y */ - WRITE_WORD(p, 0); - /* memc_control_reg */ - WRITE_WORD(p, 0); - /* unsigned char sounddefault */ - /* unsigned char adfsdrives */ - /* unsigned char bytes_per_char_h */ - /* unsigned char bytes_per_char_v */ - WRITE_WORD(p, 0); - /* pages_in_bank[4] */ - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); - /* pages_in_vram */ - WRITE_WORD(p, 0); - /* initrd_start */ - if (initrd_size) { - WRITE_WORD(p, info->initrd_start); - } else { - WRITE_WORD(p, 0); - } - /* initrd_size */ - WRITE_WORD(p, initrd_size); - /* rd_start */ - WRITE_WORD(p, 0); - /* system_rev */ - WRITE_WORD(p, 0); - /* system_serial_low */ - WRITE_WORD(p, 0); - /* system_serial_high */ - WRITE_WORD(p, 0); - /* mem_fclk_21285 */ - WRITE_WORD(p, 0); - /* zero unused fields */ - while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) { - WRITE_WORD(p, 0); - } - s = info->kernel_cmdline; - if (s) { - cpu_physical_memory_write(p, (void *)s, strlen(s) + 1); - } else { - WRITE_WORD(p, 0); - } -} - -static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) -{ -#ifdef CONFIG_FDT - uint32_t *mem_reg_property; - uint32_t mem_reg_propsize; - void *fdt = NULL; - char *filename; - int size, rc; - uint32_t acells, scells, hival; - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename); - if (!filename) { - fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename); - return -1; - } - - fdt = load_device_tree(filename, &size); - if (!fdt) { - fprintf(stderr, "Couldn't open dtb file %s\n", filename); - g_free(filename); - return -1; - } - g_free(filename); - - acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells"); - scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells"); - if (acells == 0 || scells == 0) { - fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n"); - return -1; - } - - mem_reg_propsize = acells + scells; - mem_reg_property = g_new0(uint32_t, mem_reg_propsize); - mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start); - hival = cpu_to_be32(binfo->loader_start >> 32); - if (acells > 1) { - mem_reg_property[acells - 2] = hival; - } else if (hival != 0) { - fprintf(stderr, "qemu: dtb file not compatible with " - "RAM start address > 4GB\n"); - exit(1); - } - mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size); - hival = cpu_to_be32(binfo->ram_size >> 32); - if (scells > 1) { - mem_reg_property[acells + scells - 2] = hival; - } else if (hival != 0) { - fprintf(stderr, "qemu: dtb file not compatible with " - "RAM size > 4GB\n"); - exit(1); - } - - rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, - mem_reg_propsize * sizeof(uint32_t)); - if (rc < 0) { - fprintf(stderr, "couldn't set /memory/reg\n"); - } - - if (binfo->kernel_cmdline && *binfo->kernel_cmdline) { - rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - binfo->kernel_cmdline); - if (rc < 0) { - fprintf(stderr, "couldn't set /chosen/bootargs\n"); - } - } - - if (binfo->initrd_size) { - rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - binfo->initrd_start); - if (rc < 0) { - fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); - } - - rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - binfo->initrd_start + binfo->initrd_size); - if (rc < 0) { - fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); - } - } - - cpu_physical_memory_write(addr, fdt, size); - - return 0; - -#else - fprintf(stderr, "Device tree requested, " - "but qemu was compiled without fdt support\n"); - return -1; -#endif -} - -static void do_cpu_reset(void *opaque) -{ - ARMCPU *cpu = opaque; - CPUARMState *env = &cpu->env; - const struct arm_boot_info *info = env->boot_info; - - cpu_reset(CPU(cpu)); - if (info) { - if (!info->is_linux) { - /* Jump to the entry point. */ - env->regs[15] = info->entry & 0xfffffffe; - env->thumb = info->entry & 1; - } else { - if (env == first_cpu) { - env->regs[15] = info->loader_start; - if (!info->dtb_filename) { - if (old_param) { - set_kernel_args_old(info); - } else { - set_kernel_args(info); - } - } - } else { - info->secondary_cpu_reset_hook(cpu, info); - } - } - } -} - -void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) -{ - CPUARMState *env = &cpu->env; - int kernel_size; - int initrd_size; - int n; - int is_linux = 0; - uint64_t elf_entry; - hwaddr entry; - int big_endian; - QemuOpts *machine_opts; - - /* Load the kernel. */ - if (!info->kernel_filename) { - fprintf(stderr, "Kernel image must be specified\n"); - exit(1); - } - - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - info->dtb_filename = qemu_opt_get(machine_opts, "dtb"); - } else { - info->dtb_filename = NULL; - } - - if (!info->secondary_cpu_reset_hook) { - info->secondary_cpu_reset_hook = default_reset_secondary; - } - if (!info->write_secondary_boot) { - info->write_secondary_boot = default_write_secondary; - } - - if (info->nb_cpus == 0) - info->nb_cpus = 1; - -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - - /* We want to put the initrd far enough into RAM that when the - * kernel is uncompressed it will not clobber the initrd. However - * on boards without much RAM we must ensure that we still leave - * enough room for a decent sized initrd, and on boards with large - * amounts of RAM we must avoid the initrd being so far up in RAM - * that it is outside lowmem and inaccessible to the kernel. - * So for boards with less than 256MB of RAM we put the initrd - * halfway into RAM, and for boards with 256MB of RAM or more we put - * the initrd at 128MB. - */ - info->initrd_start = info->loader_start + - MIN(info->ram_size / 2, 128 * 1024 * 1024); - - /* Assume that raw images are linux kernels, and ELF images are not. */ - kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry, - NULL, NULL, big_endian, ELF_MACHINE, 1); - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(info->kernel_filename, &entry, NULL, - &is_linux); - } - if (kernel_size < 0) { - entry = info->loader_start + KERNEL_LOAD_ADDR; - kernel_size = load_image_targphys(info->kernel_filename, entry, - info->ram_size - KERNEL_LOAD_ADDR); - is_linux = 1; - } - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - info->kernel_filename); - exit(1); - } - info->entry = entry; - if (is_linux) { - if (info->initrd_filename) { - initrd_size = load_image_targphys(info->initrd_filename, - info->initrd_start, - info->ram_size - - info->initrd_start); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - info->initrd_filename); - exit(1); - } - } else { - initrd_size = 0; - } - info->initrd_size = initrd_size; - - bootloader[4] = info->board_id; - - /* for device tree boot, we pass the DTB directly in r2. Otherwise - * we point to the kernel args. - */ - if (info->dtb_filename) { - /* Place the DTB after the initrd in memory. Note that some - * kernels will trash anything in the 4K page the initrd - * ends in, so make sure the DTB isn't caught up in that. - */ - hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, - 4096); - if (load_dtb(dtb_start, info)) { - exit(1); - } - bootloader[5] = dtb_start; - } else { - bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; - if (info->ram_size >= (1ULL << 32)) { - fprintf(stderr, "qemu: RAM size must be less than 4GB to boot" - " Linux kernel using ATAGS (try passing a device tree" - " using -dtb)\n"); - exit(1); - } - } - bootloader[6] = entry; - for (n = 0; n < sizeof(bootloader) / 4; n++) { - bootloader[n] = tswap32(bootloader[n]); - } - rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader), - info->loader_start); - if (info->nb_cpus > 1) { - info->write_secondary_boot(cpu, info); - } - } - info->is_linux = is_linux; - - for (; env; env = env->next_cpu) { - cpu = arm_env_get_cpu(env); - env->boot_info = info; - qemu_register_reset(do_cpu_reset, cpu); - } -} diff --git a/hw/arm_pic.c b/hw/arm_pic.c deleted file mode 100644 index a7ad893cc2..0000000000 --- a/hw/arm_pic.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Generic ARM Programmable Interrupt Controller support. - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the LGPL - */ - -#include "hw/hw.h" -#include "hw/arm-misc.h" - -/* Input 0 is IRQ and input 1 is FIQ. */ -static void arm_pic_cpu_handler(void *opaque, int irq, int level) -{ - ARMCPU *cpu = opaque; - CPUARMState *env = &cpu->env; - - switch (irq) { - case ARM_PIC_CPU_IRQ: - if (level) - cpu_interrupt(env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - break; - case ARM_PIC_CPU_FIQ: - if (level) - cpu_interrupt(env, CPU_INTERRUPT_FIQ); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ); - break; - default: - hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq); - } -} - -qemu_irq *arm_pic_init_cpu(ARMCPU *cpu) -{ - return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2); -} diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c deleted file mode 100644 index eccd423abf..0000000000 --- a/hw/axis_dev88.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * QEMU model for the AXIS devboard 88. - * - * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/sysbus.h" -#include "net/net.h" -#include "hw/flash.h" -#include "hw/boards.h" -#include "hw/etraxfs.h" -#include "hw/loader.h" -#include "elf.h" -#include "hw/cris-boot.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#define D(x) -#define DNAND(x) - -struct nand_state_t -{ - DeviceState *nand; - MemoryRegion iomem; - unsigned int rdy:1; - unsigned int ale:1; - unsigned int cle:1; - unsigned int ce:1; -}; - -static struct nand_state_t nand_state; -static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size) -{ - struct nand_state_t *s = opaque; - uint32_t r; - int rdy; - - r = nand_getio(s->nand); - nand_getpins(s->nand, &rdy); - s->rdy = rdy; - - DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r)); - return r; -} - -static void -nand_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - struct nand_state_t *s = opaque; - int rdy; - - DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value)); - nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0); - nand_setio(s->nand, value); - nand_getpins(s->nand, &rdy); - s->rdy = rdy; -} - -static const MemoryRegionOps nand_ops = { - .read = nand_read, - .write = nand_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -struct tempsensor_t -{ - unsigned int shiftreg; - unsigned int count; - enum { - ST_OUT, ST_IN, ST_Z - } state; - - uint16_t regs[3]; -}; - -static void tempsensor_clkedge(struct tempsensor_t *s, - unsigned int clk, unsigned int data_in) -{ - D(printf("%s clk=%d state=%d sr=%x\n", __func__, - clk, s->state, s->shiftreg)); - if (s->count == 0) { - s->count = 16; - s->state = ST_OUT; - } - switch (s->state) { - case ST_OUT: - /* Output reg is clocked at negedge. */ - if (!clk) { - s->count--; - s->shiftreg <<= 1; - if (s->count == 0) { - s->shiftreg = 0; - s->state = ST_IN; - s->count = 16; - } - } - break; - case ST_Z: - if (clk) { - s->count--; - if (s->count == 0) { - s->shiftreg = 0; - s->state = ST_OUT; - s->count = 16; - } - } - break; - case ST_IN: - /* Indata is sampled at posedge. */ - if (clk) { - s->count--; - s->shiftreg <<= 1; - s->shiftreg |= data_in & 1; - if (s->count == 0) { - D(printf("%s cfgreg=%x\n", __func__, s->shiftreg)); - s->regs[0] = s->shiftreg; - s->state = ST_OUT; - s->count = 16; - - if ((s->regs[0] & 0xff) == 0) { - /* 25 degrees celcius. */ - s->shiftreg = 0x0b9f; - } else if ((s->regs[0] & 0xff) == 0xff) { - /* Sensor ID, 0x8100 LM70. */ - s->shiftreg = 0x8100; - } else - printf("Invalid tempsens state %x\n", s->regs[0]); - } - } - break; - } -} - - -#define RW_PA_DOUT 0x00 -#define R_PA_DIN 0x01 -#define RW_PA_OE 0x02 -#define RW_PD_DOUT 0x10 -#define R_PD_DIN 0x11 -#define RW_PD_OE 0x12 - -static struct gpio_state_t -{ - MemoryRegion iomem; - struct nand_state_t *nand; - struct tempsensor_t tempsensor; - uint32_t regs[0x5c / 4]; -} gpio_state; - -static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size) -{ - struct gpio_state_t *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) - { - case R_PA_DIN: - r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE]; - - /* Encode pins from the nand. */ - r |= s->nand->rdy << 7; - break; - case R_PD_DIN: - r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE]; - - /* Encode temp sensor pins. */ - r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4; - break; - - default: - r = s->regs[addr]; - break; - } - return r; - D(printf("%s %x=%x\n", __func__, addr, r)); -} - -static void gpio_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - struct gpio_state_t *s = opaque; - D(printf("%s %x=%x\n", __func__, addr, (unsigned)value)); - - addr >>= 2; - switch (addr) - { - case RW_PA_DOUT: - /* Decode nand pins. */ - s->nand->ale = !!(value & (1 << 6)); - s->nand->cle = !!(value & (1 << 5)); - s->nand->ce = !!(value & (1 << 4)); - - s->regs[addr] = value; - break; - - case RW_PD_DOUT: - /* Temp sensor clk. */ - if ((s->regs[addr] ^ value) & 2) - tempsensor_clkedge(&s->tempsensor, !!(value & 2), - !!(value & 16)); - s->regs[addr] = value; - break; - - default: - s->regs[addr] = value; - break; - } -} - -static const MemoryRegionOps gpio_ops = { - .read = gpio_read, - .write = gpio_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -#define INTMEM_SIZE (128 * 1024) - -static struct cris_load_info li; - -static -void axisdev88_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - CRISCPU *cpu; - CPUCRISState *env; - DeviceState *dev; - SysBusDevice *s; - DriveInfo *nand; - qemu_irq irq[30], nmi[2], *cpu_irq; - void *etraxfs_dmac; - struct etraxfs_dma_client *dma_eth; - int i; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *phys_ram = g_new(MemoryRegion, 1); - MemoryRegion *phys_intmem = g_new(MemoryRegion, 1); - - /* init CPUs */ - if (cpu_model == NULL) { - cpu_model = "crisv32"; - } - cpu = cpu_cris_init(cpu_model); - env = &cpu->env; - - /* allocate RAM */ - memory_region_init_ram(phys_ram, "axisdev88.ram", ram_size); - vmstate_register_ram_global(phys_ram); - memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram); - - /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the - internal memory. */ - memory_region_init_ram(phys_intmem, "axisdev88.chipram", INTMEM_SIZE); - vmstate_register_ram_global(phys_intmem); - memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem); - - /* Attach a NAND flash to CS1. */ - nand = drive_get(IF_MTD, 0, 0); - nand_state.nand = nand_init(nand ? nand->bdrv : NULL, - NAND_MFR_STMICRO, 0x39); - memory_region_init_io(&nand_state.iomem, &nand_ops, &nand_state, - "nand", 0x05000000); - memory_region_add_subregion(address_space_mem, 0x10000000, - &nand_state.iomem); - - gpio_state.nand = &nand_state; - memory_region_init_io(&gpio_state.iomem, &gpio_ops, &gpio_state, - "gpio", 0x5c); - memory_region_add_subregion(address_space_mem, 0x3001a000, - &gpio_state.iomem); - - - cpu_irq = cris_pic_init_cpu(env); - dev = qdev_create(NULL, "etraxfs,pic"); - /* FIXME: Is there a proper way to signal vectors to the CPU core? */ - qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, 0x3001c000); - sysbus_connect_irq(s, 0, cpu_irq[0]); - sysbus_connect_irq(s, 1, cpu_irq[1]); - for (i = 0; i < 30; i++) { - irq[i] = qdev_get_gpio_in(dev, i); - } - nmi[0] = qdev_get_gpio_in(dev, 30); - nmi[1] = qdev_get_gpio_in(dev, 31); - - etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10); - for (i = 0; i < 10; i++) { - /* On ETRAX, odd numbered channels are inputs. */ - etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1); - } - - /* Add the two ethernet blocks. */ - dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels. */ - etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]); - if (nb_nics > 1) { - etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]); - } - - /* The DMA Connector block is missing, hardwire things for now. */ - etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]); - etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]); - if (nb_nics > 1) { - etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]); - etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]); - } - - /* 2 timers. */ - sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL); - sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL); - - for (i = 0; i < 4; i++) { - sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000, - irq[0x14 + i]); - } - - if (!kernel_filename) { - fprintf(stderr, "Kernel image must be specified\n"); - exit(1); - } - - li.image_filename = kernel_filename; - li.cmdline = kernel_cmdline; - cris_load_image(cpu, &li); -} - -static QEMUMachine axisdev88_machine = { - .name = "axis-dev88", - .desc = "AXIS devboard 88", - .init = axisdev88_init, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void axisdev88_machine_init(void) -{ - qemu_register_machine(&axisdev88_machine); -} - -machine_init(axisdev88_machine_init); diff --git a/hw/collie.c b/hw/collie.c deleted file mode 100644 index 17fddc8d5b..0000000000 --- a/hw/collie.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SA-1110-based Sharp Zaurus SL-5500 platform. - * - * Copyright (C) 2011 Dmitry Eremin-Solenikov - * - * This code is licensed under GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "hw/boards.h" -#include "hw/devices.h" -#include "hw/strongarm.h" -#include "hw/arm-misc.h" -#include "hw/flash.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -static struct arm_boot_info collie_binfo = { - .loader_start = SA_SDCS0, - .ram_size = 0x20000000, -}; - -static void collie_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - StrongARMState *s; - DriveInfo *dinfo; - MemoryRegion *sysmem = get_system_memory(); - - if (!cpu_model) { - cpu_model = "sa1110"; - } - - s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model); - - dinfo = drive_get(IF_PFLASH, 0, 0); - pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000, - dinfo ? dinfo->bdrv : NULL, (64 * 1024), - 512, 4, 0x00, 0x00, 0x00, 0x00, 0); - - dinfo = drive_get(IF_PFLASH, 0, 1); - pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000, - dinfo ? dinfo->bdrv : NULL, (64 * 1024), - 512, 4, 0x00, 0x00, 0x00, 0x00, 0); - - sysbus_create_simple("scoop", 0x40800000, NULL); - - collie_binfo.kernel_filename = kernel_filename; - collie_binfo.kernel_cmdline = kernel_cmdline; - collie_binfo.initrd_filename = initrd_filename; - collie_binfo.board_id = 0x208; - arm_load_kernel(s->cpu, &collie_binfo); -} - -static QEMUMachine collie_machine = { - .name = "collie", - .desc = "Collie PDA (SA-1110)", - .init = collie_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void collie_machine_init(void) -{ - qemu_register_machine(&collie_machine); -} - -machine_init(collie_machine_init) diff --git a/hw/cris-boot.c b/hw/cris-boot.c deleted file mode 100644 index c330e22a86..0000000000 --- a/hw/cris-boot.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * CRIS image loading. - * - * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/loader.h" -#include "elf.h" -#include "hw/cris-boot.h" - -static void main_cpu_reset(void *opaque) -{ - CRISCPU *cpu = opaque; - CPUCRISState *env = &cpu->env; - struct cris_load_info *li; - - li = env->load_info; - - cpu_reset(CPU(cpu)); - - if (!li) { - /* nothing more to do. */ - return; - } - - env->pc = li->entry; - - if (li->image_filename) { - env->regs[8] = 0x56902387; /* RAM boot magic. */ - env->regs[9] = 0x40004000 + li->image_size; - } - - if (li->cmdline) { - /* Let the kernel know we are modifying the cmdline. */ - env->regs[10] = 0x87109563; - env->regs[11] = 0x40000000; - } -} - -static uint64_t translate_kernel_address(void *opaque, uint64_t addr) -{ - return addr - 0x80000000LL; -} - -void cris_load_image(CRISCPU *cpu, struct cris_load_info *li) -{ - CPUCRISState *env = &cpu->env; - uint64_t entry, high; - int kcmdline_len; - int image_size; - - env->load_info = li; - /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis - devboard SDK. */ - image_size = load_elf(li->image_filename, translate_kernel_address, NULL, - &entry, NULL, &high, 0, ELF_MACHINE, 0); - li->entry = entry; - if (image_size < 0) { - /* Takes a kimage from the axis devboard SDK. */ - image_size = load_image_targphys(li->image_filename, 0x40004000, - ram_size); - li->entry = 0x40004000; - } - - if (image_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - li->image_filename); - exit(1); - } - - if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) { - if (kcmdline_len > 256) { - fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n"); - exit(1); - } - pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline); - } - qemu_register_reset(main_cpu_reset, cpu); -} diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs index aa9298a0ed..a94c62450d 100644 --- a/hw/cris/Makefile.objs +++ b/hw/cris/Makefile.objs @@ -1,8 +1,3 @@ -# Boards -obj-y = cris_pic_cpu.o -obj-y += cris-boot.o -obj-y += axis_dev88.o - # IO blocks obj-y += etraxfs_dma.o obj-y += etraxfs_pic.o @@ -11,3 +6,8 @@ obj-y += etraxfs_timer.o obj-y += etraxfs_ser.o obj-y := $(addprefix ../,$(obj-y)) + +# Boards +obj-y += pic_cpu.o +obj-y += boot.o +obj-y += axis_dev88.o diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c new file mode 100644 index 0000000000..eccd423abf --- /dev/null +++ b/hw/cris/axis_dev88.c @@ -0,0 +1,366 @@ +/* + * QEMU model for the AXIS devboard 88. + * + * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "net/net.h" +#include "hw/flash.h" +#include "hw/boards.h" +#include "hw/etraxfs.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/cris-boot.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#define D(x) +#define DNAND(x) + +struct nand_state_t +{ + DeviceState *nand; + MemoryRegion iomem; + unsigned int rdy:1; + unsigned int ale:1; + unsigned int cle:1; + unsigned int ce:1; +}; + +static struct nand_state_t nand_state; +static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size) +{ + struct nand_state_t *s = opaque; + uint32_t r; + int rdy; + + r = nand_getio(s->nand); + nand_getpins(s->nand, &rdy); + s->rdy = rdy; + + DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r)); + return r; +} + +static void +nand_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + struct nand_state_t *s = opaque; + int rdy; + + DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value)); + nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0); + nand_setio(s->nand, value); + nand_getpins(s->nand, &rdy); + s->rdy = rdy; +} + +static const MemoryRegionOps nand_ops = { + .read = nand_read, + .write = nand_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +struct tempsensor_t +{ + unsigned int shiftreg; + unsigned int count; + enum { + ST_OUT, ST_IN, ST_Z + } state; + + uint16_t regs[3]; +}; + +static void tempsensor_clkedge(struct tempsensor_t *s, + unsigned int clk, unsigned int data_in) +{ + D(printf("%s clk=%d state=%d sr=%x\n", __func__, + clk, s->state, s->shiftreg)); + if (s->count == 0) { + s->count = 16; + s->state = ST_OUT; + } + switch (s->state) { + case ST_OUT: + /* Output reg is clocked at negedge. */ + if (!clk) { + s->count--; + s->shiftreg <<= 1; + if (s->count == 0) { + s->shiftreg = 0; + s->state = ST_IN; + s->count = 16; + } + } + break; + case ST_Z: + if (clk) { + s->count--; + if (s->count == 0) { + s->shiftreg = 0; + s->state = ST_OUT; + s->count = 16; + } + } + break; + case ST_IN: + /* Indata is sampled at posedge. */ + if (clk) { + s->count--; + s->shiftreg <<= 1; + s->shiftreg |= data_in & 1; + if (s->count == 0) { + D(printf("%s cfgreg=%x\n", __func__, s->shiftreg)); + s->regs[0] = s->shiftreg; + s->state = ST_OUT; + s->count = 16; + + if ((s->regs[0] & 0xff) == 0) { + /* 25 degrees celcius. */ + s->shiftreg = 0x0b9f; + } else if ((s->regs[0] & 0xff) == 0xff) { + /* Sensor ID, 0x8100 LM70. */ + s->shiftreg = 0x8100; + } else + printf("Invalid tempsens state %x\n", s->regs[0]); + } + } + break; + } +} + + +#define RW_PA_DOUT 0x00 +#define R_PA_DIN 0x01 +#define RW_PA_OE 0x02 +#define RW_PD_DOUT 0x10 +#define R_PD_DIN 0x11 +#define RW_PD_OE 0x12 + +static struct gpio_state_t +{ + MemoryRegion iomem; + struct nand_state_t *nand; + struct tempsensor_t tempsensor; + uint32_t regs[0x5c / 4]; +} gpio_state; + +static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size) +{ + struct gpio_state_t *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) + { + case R_PA_DIN: + r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE]; + + /* Encode pins from the nand. */ + r |= s->nand->rdy << 7; + break; + case R_PD_DIN: + r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE]; + + /* Encode temp sensor pins. */ + r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4; + break; + + default: + r = s->regs[addr]; + break; + } + return r; + D(printf("%s %x=%x\n", __func__, addr, r)); +} + +static void gpio_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + struct gpio_state_t *s = opaque; + D(printf("%s %x=%x\n", __func__, addr, (unsigned)value)); + + addr >>= 2; + switch (addr) + { + case RW_PA_DOUT: + /* Decode nand pins. */ + s->nand->ale = !!(value & (1 << 6)); + s->nand->cle = !!(value & (1 << 5)); + s->nand->ce = !!(value & (1 << 4)); + + s->regs[addr] = value; + break; + + case RW_PD_DOUT: + /* Temp sensor clk. */ + if ((s->regs[addr] ^ value) & 2) + tempsensor_clkedge(&s->tempsensor, !!(value & 2), + !!(value & 16)); + s->regs[addr] = value; + break; + + default: + s->regs[addr] = value; + break; + } +} + +static const MemoryRegionOps gpio_ops = { + .read = gpio_read, + .write = gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +#define INTMEM_SIZE (128 * 1024) + +static struct cris_load_info li; + +static +void axisdev88_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + CRISCPU *cpu; + CPUCRISState *env; + DeviceState *dev; + SysBusDevice *s; + DriveInfo *nand; + qemu_irq irq[30], nmi[2], *cpu_irq; + void *etraxfs_dmac; + struct etraxfs_dma_client *dma_eth; + int i; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *phys_ram = g_new(MemoryRegion, 1); + MemoryRegion *phys_intmem = g_new(MemoryRegion, 1); + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "crisv32"; + } + cpu = cpu_cris_init(cpu_model); + env = &cpu->env; + + /* allocate RAM */ + memory_region_init_ram(phys_ram, "axisdev88.ram", ram_size); + vmstate_register_ram_global(phys_ram); + memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram); + + /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the + internal memory. */ + memory_region_init_ram(phys_intmem, "axisdev88.chipram", INTMEM_SIZE); + vmstate_register_ram_global(phys_intmem); + memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem); + + /* Attach a NAND flash to CS1. */ + nand = drive_get(IF_MTD, 0, 0); + nand_state.nand = nand_init(nand ? nand->bdrv : NULL, + NAND_MFR_STMICRO, 0x39); + memory_region_init_io(&nand_state.iomem, &nand_ops, &nand_state, + "nand", 0x05000000); + memory_region_add_subregion(address_space_mem, 0x10000000, + &nand_state.iomem); + + gpio_state.nand = &nand_state; + memory_region_init_io(&gpio_state.iomem, &gpio_ops, &gpio_state, + "gpio", 0x5c); + memory_region_add_subregion(address_space_mem, 0x3001a000, + &gpio_state.iomem); + + + cpu_irq = cris_pic_init_cpu(env); + dev = qdev_create(NULL, "etraxfs,pic"); + /* FIXME: Is there a proper way to signal vectors to the CPU core? */ + qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(s, 0, 0x3001c000); + sysbus_connect_irq(s, 0, cpu_irq[0]); + sysbus_connect_irq(s, 1, cpu_irq[1]); + for (i = 0; i < 30; i++) { + irq[i] = qdev_get_gpio_in(dev, i); + } + nmi[0] = qdev_get_gpio_in(dev, 30); + nmi[1] = qdev_get_gpio_in(dev, 31); + + etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10); + for (i = 0; i < 10; i++) { + /* On ETRAX, odd numbered channels are inputs. */ + etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1); + } + + /* Add the two ethernet blocks. */ + dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels. */ + etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]); + if (nb_nics > 1) { + etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]); + } + + /* The DMA Connector block is missing, hardwire things for now. */ + etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]); + etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]); + if (nb_nics > 1) { + etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]); + etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]); + } + + /* 2 timers. */ + sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL); + sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL); + + for (i = 0; i < 4; i++) { + sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000, + irq[0x14 + i]); + } + + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + + li.image_filename = kernel_filename; + li.cmdline = kernel_cmdline; + cris_load_image(cpu, &li); +} + +static QEMUMachine axisdev88_machine = { + .name = "axis-dev88", + .desc = "AXIS devboard 88", + .init = axisdev88_init, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void axisdev88_machine_init(void) +{ + qemu_register_machine(&axisdev88_machine); +} + +machine_init(axisdev88_machine_init); diff --git a/hw/cris/boot.c b/hw/cris/boot.c new file mode 100644 index 0000000000..c330e22a86 --- /dev/null +++ b/hw/cris/boot.c @@ -0,0 +1,98 @@ +/* + * CRIS image loading. + * + * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/cris-boot.h" + +static void main_cpu_reset(void *opaque) +{ + CRISCPU *cpu = opaque; + CPUCRISState *env = &cpu->env; + struct cris_load_info *li; + + li = env->load_info; + + cpu_reset(CPU(cpu)); + + if (!li) { + /* nothing more to do. */ + return; + } + + env->pc = li->entry; + + if (li->image_filename) { + env->regs[8] = 0x56902387; /* RAM boot magic. */ + env->regs[9] = 0x40004000 + li->image_size; + } + + if (li->cmdline) { + /* Let the kernel know we are modifying the cmdline. */ + env->regs[10] = 0x87109563; + env->regs[11] = 0x40000000; + } +} + +static uint64_t translate_kernel_address(void *opaque, uint64_t addr) +{ + return addr - 0x80000000LL; +} + +void cris_load_image(CRISCPU *cpu, struct cris_load_info *li) +{ + CPUCRISState *env = &cpu->env; + uint64_t entry, high; + int kcmdline_len; + int image_size; + + env->load_info = li; + /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis + devboard SDK. */ + image_size = load_elf(li->image_filename, translate_kernel_address, NULL, + &entry, NULL, &high, 0, ELF_MACHINE, 0); + li->entry = entry; + if (image_size < 0) { + /* Takes a kimage from the axis devboard SDK. */ + image_size = load_image_targphys(li->image_filename, 0x40004000, + ram_size); + li->entry = 0x40004000; + } + + if (image_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + li->image_filename); + exit(1); + } + + if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) { + if (kcmdline_len > 256) { + fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n"); + exit(1); + } + pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline); + } + qemu_register_reset(main_cpu_reset, cpu); +} diff --git a/hw/cris/pic_cpu.c b/hw/cris/pic_cpu.c new file mode 100644 index 0000000000..7f50471e53 --- /dev/null +++ b/hw/cris/pic_cpu.c @@ -0,0 +1,45 @@ +/* + * QEMU CRIS CPU interrupt wrapper logic. + * + * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/etraxfs.h" + +#define D(x) + +static void cris_pic_cpu_handler(void *opaque, int irq, int level) +{ + CPUCRISState *env = (CPUCRISState *)opaque; + int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; + + if (level) + cpu_interrupt(env, type); + else + cpu_reset_interrupt(env, type); +} + +qemu_irq *cris_pic_init_cpu(CPUCRISState *env) +{ + return qemu_allocate_irqs(cris_pic_cpu_handler, env, 2); +} diff --git a/hw/cris_pic_cpu.c b/hw/cris_pic_cpu.c deleted file mode 100644 index 7f50471e53..0000000000 --- a/hw/cris_pic_cpu.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * QEMU CRIS CPU interrupt wrapper logic. - * - * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "hw/etraxfs.h" - -#define D(x) - -static void cris_pic_cpu_handler(void *opaque, int irq, int level) -{ - CPUCRISState *env = (CPUCRISState *)opaque; - int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; - - if (level) - cpu_interrupt(env, type); - else - cpu_reset_interrupt(env, type); -} - -qemu_irq *cris_pic_init_cpu(CPUCRISState *env) -{ - return qemu_allocate_irqs(cris_pic_cpu_handler, env, 2); -} diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c deleted file mode 100644 index 544d56b59d..0000000000 --- a/hw/dummy_m68k.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Dummy board with just RAM and CPU for use as an ISS. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ - -#include "hw/hw.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "exec/address-spaces.h" - -#define KERNEL_LOAD_ADDR 0x10000 - -/* Board init. */ - -static void dummy_m68k_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - CPUM68KState *env; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - int kernel_size; - uint64_t elf_entry; - hwaddr entry; - - if (!cpu_model) - cpu_model = "cfv4e"; - env = cpu_init(cpu_model); - if (!env) { - fprintf(stderr, "Unable to find m68k CPU definition\n"); - exit(1); - } - - /* Initialize CPU registers. */ - env->vbr = 0; - - /* RAM at address zero */ - memory_region_init_ram(ram, "dummy_m68k.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space_mem, 0, ram); - - /* Load kernel. */ - if (kernel_filename) { - kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, - NULL, NULL, 1, ELF_MACHINE, 0); - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); - } - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - ram_size - KERNEL_LOAD_ADDR); - entry = KERNEL_LOAD_ADDR; - } - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - } else { - entry = 0; - } - env->pc = entry; -} - -static QEMUMachine dummy_m68k_machine = { - .name = "dummy", - .desc = "Dummy board", - .init = dummy_m68k_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void dummy_m68k_machine_init(void) -{ - qemu_register_machine(&dummy_m68k_machine); -} - -machine_init(dummy_m68k_machine_init); diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c deleted file mode 100644 index 473da349bd..0000000000 --- a/hw/exynos4_boards.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Samsung exynos4 SoC based boards emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. - * Maksim Kozlov - * Evgeny Voevodin - * Igor Mitsyanko - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - */ - -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "net/net.h" -#include "hw/arm-misc.h" -#include "exec/address-spaces.h" -#include "hw/exynos4210.h" -#include "hw/boards.h" - -#undef DEBUG - -//#define DEBUG - -#ifdef DEBUG - #undef PRINT_DEBUG - #define PRINT_DEBUG(fmt, args...) \ - do { \ - fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ - } while (0) -#else - #define PRINT_DEBUG(fmt, args...) do {} while (0) -#endif - -#define SMDK_LAN9118_BASE_ADDR 0x05000000 - -typedef enum Exynos4BoardType { - EXYNOS4_BOARD_NURI, - EXYNOS4_BOARD_SMDKC210, - EXYNOS4_NUM_OF_BOARDS -} Exynos4BoardType; - -static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = 0xD33, - [EXYNOS4_BOARD_SMDKC210] = 0xB16, -}; - -static int exynos4_board_smp_bootreg_addr[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = EXYNOS4210_SECOND_CPU_BOOTREG, - [EXYNOS4_BOARD_SMDKC210] = EXYNOS4210_SECOND_CPU_BOOTREG, -}; - -static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = 0x40000000, - [EXYNOS4_BOARD_SMDKC210] = 0x40000000, -}; - -static struct arm_boot_info exynos4_board_binfo = { - .loader_start = EXYNOS4210_BASE_BOOT_ADDR, - .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR, - .nb_cpus = EXYNOS4210_NCPUS, - .write_secondary_boot = exynos4210_write_secondary, -}; - -static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS]; - -static void lan9215_init(uint32_t base, qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *s; - - /* This should be a 9215 but the 9118 is close enough */ - if (nd_table[0].used) { - qemu_check_nic_model(&nd_table[0], "lan9118"); - dev = qdev_create(NULL, "lan9118"); - qdev_set_nic_properties(dev, &nd_table[0]); - qdev_prop_set_uint32(dev, "mode_16bit", 1); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, base); - sysbus_connect_irq(s, 0, irq); - } -} - -static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, - Exynos4BoardType board_type) -{ - if (smp_cpus != EXYNOS4210_NCPUS) { - fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus" - " value.\n", - exynos4_machines[board_type].name, - exynos4_machines[board_type].max_cpus); - } - - exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type]; - exynos4_board_binfo.board_id = exynos4_board_id[board_type]; - exynos4_board_binfo.smp_bootreg_addr = - exynos4_board_smp_bootreg_addr[board_type]; - exynos4_board_binfo.kernel_filename = args->kernel_filename; - exynos4_board_binfo.initrd_filename = args->initrd_filename; - exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline; - exynos4_board_binfo.gic_cpu_if_addr = - EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; - - PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n" - " kernel_filename: %s\n" - " kernel_cmdline: %s\n" - " initrd_filename: %s\n", - exynos4_board_ram_size[board_type] / 1048576, - exynos4_board_ram_size[board_type], - args->kernel_filename, - args->kernel_cmdline, - args->initrd_filename); - - return exynos4210_init(get_system_memory(), - exynos4_board_ram_size[board_type]); -} - -static void nuri_init(QEMUMachineInitArgs *args) -{ - exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI); - - arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); -} - -static void smdkc210_init(QEMUMachineInitArgs *args) -{ - Exynos4210State *s = exynos4_boards_init_common(args, - EXYNOS4_BOARD_SMDKC210); - - lan9215_init(SMDK_LAN9118_BASE_ADDR, - qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); - arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); -} - -static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = { - .name = "nuri", - .desc = "Samsung NURI board (Exynos4210)", - .init = nuri_init, - .max_cpus = EXYNOS4210_NCPUS, - DEFAULT_MACHINE_OPTIONS, - }, - [EXYNOS4_BOARD_SMDKC210] = { - .name = "smdkc210", - .desc = "Samsung SMDKC210 board (Exynos4210)", - .init = smdkc210_init, - .max_cpus = EXYNOS4210_NCPUS, - DEFAULT_MACHINE_OPTIONS, - }, -}; - -static void exynos4_machine_init(void) -{ - qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_NURI]); - qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_SMDKC210]); -} - -machine_init(exynos4_machine_init); diff --git a/hw/gumstix.c b/hw/gumstix.c deleted file mode 100644 index 8859b7392f..0000000000 --- a/hw/gumstix.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Gumstix Platforms - * - * Copyright (c) 2007 by Thorsten Zitterell - * - * Code based on spitz platform by Andrzej Zaborowski - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -/* - * Example usage: - * - * connex: - * ======= - * create image: - * # dd of=flash bs=1k count=16k if=/dev/zero - * # dd of=flash bs=1k conv=notrunc if=u-boot.bin - * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 - * start it: - * # qemu-system-arm -M connex -pflash flash -monitor null -nographic - * - * verdex: - * ======= - * create image: - * # dd of=flash bs=1k count=32k if=/dev/zero - * # dd of=flash bs=1k conv=notrunc if=u-boot.bin - * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 - * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage - * start it: - * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289 - */ - -#include "hw/hw.h" -#include "hw/pxa.h" -#include "net/net.h" -#include "hw/flash.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -static const int sector_len = 128 * 1024; - -static void connex_init(QEMUMachineInitArgs *args) -{ - PXA2xxState *cpu; - DriveInfo *dinfo; - int be; - MemoryRegion *address_space_mem = get_system_memory(); - - uint32_t connex_rom = 0x01000000; - uint32_t connex_ram = 0x04000000; - - cpu = pxa255_init(address_space_mem, connex_ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo) { - fprintf(stderr, "A flash image must be given with the " - "'pflash' parameter\n"); - exit(1); - } - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom, - dinfo->bdrv, sector_len, connex_rom / sector_len, - 2, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - - /* Interrupt line of NIC is connected to GPIO line 36 */ - smc91c111_init(&nd_table[0], 0x04000300, - qdev_get_gpio_in(cpu->gpio, 36)); -} - -static void verdex_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - PXA2xxState *cpu; - DriveInfo *dinfo; - int be; - MemoryRegion *address_space_mem = get_system_memory(); - - uint32_t verdex_rom = 0x02000000; - uint32_t verdex_ram = 0x10000000; - - cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0"); - - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo) { - fprintf(stderr, "A flash image must be given with the " - "'pflash' parameter\n"); - exit(1); - } - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom, - dinfo->bdrv, sector_len, verdex_rom / sector_len, - 2, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - - /* Interrupt line of NIC is connected to GPIO line 99 */ - smc91c111_init(&nd_table[0], 0x04000300, - qdev_get_gpio_in(cpu->gpio, 99)); -} - -static QEMUMachine connex_machine = { - .name = "connex", - .desc = "Gumstix Connex (PXA255)", - .init = connex_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine verdex_machine = { - .name = "verdex", - .desc = "Gumstix Verdex (PXA270)", - .init = verdex_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void gumstix_machine_init(void) -{ - qemu_register_machine(&connex_machine); - qemu_register_machine(&verdex_machine); -} - -machine_init(gumstix_machine_init); diff --git a/hw/highbank.c b/hw/highbank.c deleted file mode 100644 index a622224dcc..0000000000 --- a/hw/highbank.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Calxeda Highbank SoC emulation - * - * Copyright (c) 2010-2012 Calxeda - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - */ - -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "hw/loader.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/sysbus.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#define SMP_BOOT_ADDR 0x100 -#define SMP_BOOT_REG 0x40 -#define GIC_BASE_ADDR 0xfff10000 - -#define NIRQ_GIC 160 - -/* Board init. */ - -static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) -{ - int n; - uint32_t smpboot[] = { - 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */ - 0xe210000f, /* ands r0, r0, #0x0f */ - 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */ - 0xe0830200, /* add r0, r3, r0, lsl #4 */ - 0xe59f2024, /* ldr r2, privbase */ - 0xe3a01001, /* mov r1, #1 */ - 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */ - 0xe3a010ff, /* mov r1, #0xff */ - 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */ - 0xf57ff04f, /* dsb */ - 0xe320f003, /* wfi */ - 0xe5901000, /* ldr r1, [r0] */ - 0xe1110001, /* tst r1, r1 */ - 0x0afffffb, /* beq */ - 0xe12fff11, /* bx r1 */ - GIC_BASE_ADDR /* privbase: gic address. */ - }; - for (n = 0; n < ARRAY_SIZE(smpboot); n++) { - smpboot[n] = tswap32(smpboot[n]); - } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); -} - -static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) -{ - CPUARMState *env = &cpu->env; - - switch (info->nb_cpus) { - case 4: - stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0); - case 3: - stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0); - case 2: - stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0); - env->regs[15] = SMP_BOOT_ADDR; - break; - default: - break; - } -} - -#define NUM_REGS 0x200 -static void hb_regs_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - uint32_t *regs = opaque; - - if (offset == 0xf00) { - if (value == 1 || value == 2) { - qemu_system_reset_request(); - } else if (value == 3) { - qemu_system_shutdown_request(); - } - } - - regs[offset/4] = value; -} - -static uint64_t hb_regs_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint32_t *regs = opaque; - uint32_t value = regs[offset/4]; - - if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) { - value |= 0x30000000; - } - - return value; -} - -static const MemoryRegionOps hb_mem_ops = { - .read = hb_regs_read, - .write = hb_regs_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -typedef struct { - SysBusDevice busdev; - MemoryRegion *iomem; - uint32_t regs[NUM_REGS]; -} HighbankRegsState; - -static VMStateDescription vmstate_highbank_regs = { - .name = "highbank-regs", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS), - VMSTATE_END_OF_LIST(), - }, -}; - -static void highbank_regs_reset(DeviceState *dev) -{ - SysBusDevice *sys_dev = SYS_BUS_DEVICE(dev); - HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev); - - s->regs[0x40] = 0x05F20121; - s->regs[0x41] = 0x2; - s->regs[0x42] = 0x05F30121; - s->regs[0x43] = 0x05F40121; -} - -static int highbank_regs_init(SysBusDevice *dev) -{ - HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev); - - s->iomem = g_new(MemoryRegion, 1); - memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs", - 0x1000); - sysbus_init_mmio(dev, s->iomem); - - return 0; -} - -static void highbank_regs_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - sbc->init = highbank_regs_init; - dc->desc = "Calxeda Highbank registers"; - dc->vmsd = &vmstate_highbank_regs; - dc->reset = highbank_regs_reset; -} - -static const TypeInfo highbank_regs_info = { - .name = "highbank-regs", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(HighbankRegsState), - .class_init = highbank_regs_class_init, -}; - -static void highbank_regs_register_types(void) -{ - type_register_static(&highbank_regs_info); -} - -type_init(highbank_regs_register_types) - -static struct arm_boot_info highbank_binfo; - -/* ram_size must be set to match the upper bound of memory in the - * device tree (linux/arch/arm/boot/dts/highbank.dts), which is - * normally 0xff900000 or -m 4089. When running this board on a - * 32-bit host, set the reg value of memory to 0xf7ff00000 in the - * device tree and pass -m 2047 to QEMU. - */ -static void highbank_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - DeviceState *dev; - SysBusDevice *busdev; - qemu_irq *irqp; - qemu_irq pic[128]; - int n; - qemu_irq cpu_irq[4]; - MemoryRegion *sysram; - MemoryRegion *dram; - MemoryRegion *sysmem; - char *sysboot_filename; - - if (!cpu_model) { - cpu_model = "cortex-a9"; - } - - for (n = 0; n < smp_cpus; n++) { - ARMCPU *cpu; - cpu = cpu_arm_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - /* This will become a QOM property eventually */ - cpu->reset_cbar = GIC_BASE_ADDR; - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; - } - - sysmem = get_system_memory(); - dram = g_new(MemoryRegion, 1); - memory_region_init_ram(dram, "highbank.dram", ram_size); - /* SDRAM at address zero. */ - memory_region_add_subregion(sysmem, 0, dram); - - sysram = g_new(MemoryRegion, 1); - memory_region_init_ram(sysram, "highbank.sysram", 0x8000); - memory_region_add_subregion(sysmem, 0xfff88000, sysram); - if (bios_name != NULL) { - sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (sysboot_filename != NULL) { - uint32_t filesize = get_image_size(sysboot_filename); - if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) { - hw_error("Unable to load %s\n", bios_name); - } - } else { - hw_error("Unable to find %s\n", bios_name); - } - } - - dev = qdev_create(NULL, "a9mpcore_priv"); - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR); - for (n = 0; n < smp_cpus; n++) { - sysbus_connect_irq(busdev, n, cpu_irq[n]); - } - - for (n = 0; n < 128; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - dev = qdev_create(NULL, "l2x0"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xfff12000); - - dev = qdev_create(NULL, "sp804"); - qdev_prop_set_uint32(dev, "freq0", 150000000); - qdev_prop_set_uint32(dev, "freq1", 150000000); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xfff34000); - sysbus_connect_irq(busdev, 0, pic[18]); - sysbus_create_simple("pl011", 0xfff36000, pic[20]); - - dev = qdev_create(NULL, "highbank-regs"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xfff3c000); - - sysbus_create_simple("pl061", 0xfff30000, pic[14]); - sysbus_create_simple("pl061", 0xfff31000, pic[15]); - sysbus_create_simple("pl061", 0xfff32000, pic[16]); - sysbus_create_simple("pl061", 0xfff33000, pic[17]); - sysbus_create_simple("pl031", 0xfff35000, pic[19]); - sysbus_create_simple("pl022", 0xfff39000, pic[23]); - - sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]); - - if (nd_table[0].used) { - qemu_check_nic_model(&nd_table[0], "xgmac"); - dev = qdev_create(NULL, "xgmac"); - qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]); - - qemu_check_nic_model(&nd_table[1], "xgmac"); - dev = qdev_create(NULL, "xgmac"); - qdev_set_nic_properties(dev, &nd_table[1]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]); - } - - highbank_binfo.ram_size = ram_size; - highbank_binfo.kernel_filename = kernel_filename; - highbank_binfo.kernel_cmdline = kernel_cmdline; - highbank_binfo.initrd_filename = initrd_filename; - /* highbank requires a dtb in order to boot, and the dtb will override - * the board ID. The following value is ignored, so set it to -1 to be - * clear that the value is meaningless. - */ - highbank_binfo.board_id = -1; - highbank_binfo.nb_cpus = smp_cpus; - highbank_binfo.loader_start = 0; - highbank_binfo.write_secondary_boot = hb_write_secondary; - highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary; - arm_load_kernel(arm_env_get_cpu(first_cpu), &highbank_binfo); -} - -static QEMUMachine highbank_machine = { - .name = "highbank", - .desc = "Calxeda Highbank (ECX-1000)", - .init = highbank_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static void highbank_machine_init(void) -{ - qemu_register_machine(&highbank_machine); -} - -machine_init(highbank_machine_init); diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 025803aa66..5d071f418e 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,12 +1,11 @@ -obj-y += mc146818rtc.o pc.o +obj-y += mc146818rtc.o obj-y += apic_common.o apic.o kvmvapic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o -obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o -obj-y += debugcon.o debugexit.o multiboot.o -obj-y += pc_piix.o +obj-y += pci/pci-hotplug.o wdt_ib700.o +obj-y += debugcon.o debugexit.o obj-y += pc_sysfw.o -obj-y += lpc_ich9.o q35.o pc_q35.o +obj-y += lpc_ich9.o q35.o obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o @@ -15,3 +14,7 @@ obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o obj-y += pc-testdev.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += multiboot.o smbios.o +obj-y += pc.o pc_piix.o pc_q35.o +obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c new file mode 100644 index 0000000000..3cb228f0ca --- /dev/null +++ b/hw/i386/multiboot.c @@ -0,0 +1,349 @@ +/* + * QEMU PC System Emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/fw_cfg.h" +#include "hw/multiboot.h" +#include "hw/loader.h" +#include "elf.h" +#include "sysemu/sysemu.h" + +/* Show multiboot debug output */ +//#define DEBUG_MULTIBOOT + +#ifdef DEBUG_MULTIBOOT +#define mb_debug(a...) fprintf(stderr, ## a) +#else +#define mb_debug(a...) +#endif + +#define MULTIBOOT_STRUCT_ADDR 0x9000 + +#if MULTIBOOT_STRUCT_ADDR > 0xf0000 +#error multiboot struct needs to fit in 16 bit real mode +#endif + +enum { + /* Multiboot info */ + MBI_FLAGS = 0, + MBI_MEM_LOWER = 4, + MBI_MEM_UPPER = 8, + MBI_BOOT_DEVICE = 12, + MBI_CMDLINE = 16, + MBI_MODS_COUNT = 20, + MBI_MODS_ADDR = 24, + MBI_MMAP_ADDR = 48, + + MBI_SIZE = 88, + + /* Multiboot modules */ + MB_MOD_START = 0, + MB_MOD_END = 4, + MB_MOD_CMDLINE = 8, + + MB_MOD_SIZE = 16, + + /* Region offsets */ + ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0, + ADDR_MBI = ADDR_E820_MAP + 0x500, + + /* Multiboot flags */ + MULTIBOOT_FLAGS_MEMORY = 1 << 0, + MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1, + MULTIBOOT_FLAGS_CMDLINE = 1 << 2, + MULTIBOOT_FLAGS_MODULES = 1 << 3, + MULTIBOOT_FLAGS_MMAP = 1 << 6, +}; + +typedef struct { + /* buffer holding kernel, cmdlines and mb_infos */ + void *mb_buf; + /* address in target */ + hwaddr mb_buf_phys; + /* size of mb_buf in bytes */ + unsigned mb_buf_size; + /* offset of mb-info's in bytes */ + hwaddr offset_mbinfo; + /* offset in buffer for cmdlines in bytes */ + hwaddr offset_cmdlines; + /* offset of modules in bytes */ + hwaddr offset_mods; + /* available slots for mb modules infos */ + int mb_mods_avail; + /* currently used slots of mb modules */ + int mb_mods_count; +} MultibootState; + +static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline) +{ + hwaddr p = s->offset_cmdlines; + char *b = (char *)s->mb_buf + p; + + get_opt_value(b, strlen(cmdline) + 1, cmdline); + s->offset_cmdlines += strlen(b) + 1; + return s->mb_buf_phys + p; +} + +static void mb_add_mod(MultibootState *s, + hwaddr start, hwaddr end, + hwaddr cmdline_phys) +{ + char *p; + assert(s->mb_mods_count < s->mb_mods_avail); + + p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count; + + stl_p(p + MB_MOD_START, start); + stl_p(p + MB_MOD_END, end); + stl_p(p + MB_MOD_CMDLINE, cmdline_phys); + + mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n", + s->mb_mods_count, start, end); + + s->mb_mods_count++; +} + +int load_multiboot(void *fw_cfg, + FILE *f, + const char *kernel_filename, + const char *initrd_filename, + const char *kernel_cmdline, + int kernel_file_size, + uint8_t *header) +{ + int i, is_multiboot = 0; + uint32_t flags = 0; + uint32_t mh_entry_addr; + uint32_t mh_load_addr; + uint32_t mb_kernel_size; + MultibootState mbs; + uint8_t bootinfo[MBI_SIZE]; + uint8_t *mb_bootinfo_data; + + /* Ok, let's see if it is a multiboot image. + The header is 12x32bit long, so the latest entry may be 8192 - 48. */ + for (i = 0; i < (8192 - 48); i += 4) { + if (ldl_p(header+i) == 0x1BADB002) { + uint32_t checksum = ldl_p(header+i+8); + flags = ldl_p(header+i+4); + checksum += flags; + checksum += (uint32_t)0x1BADB002; + if (!checksum) { + is_multiboot = 1; + break; + } + } + } + + if (!is_multiboot) + return 0; /* no multiboot */ + + mb_debug("qemu: I believe we found a multiboot image!\n"); + memset(bootinfo, 0, sizeof(bootinfo)); + memset(&mbs, 0, sizeof(mbs)); + + if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */ + fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n"); + } + if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */ + uint64_t elf_entry; + uint64_t elf_low, elf_high; + int kernel_size; + fclose(f); + + if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) { + fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n"); + exit(1); + } + + kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, + &elf_low, &elf_high, 0, ELF_MACHINE, 0); + if (kernel_size < 0) { + fprintf(stderr, "Error while loading elf kernel\n"); + exit(1); + } + mh_load_addr = elf_low; + mb_kernel_size = elf_high - elf_low; + mh_entry_addr = elf_entry; + + mbs.mb_buf = g_malloc(mb_kernel_size); + if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) { + fprintf(stderr, "Error while fetching elf kernel from rom\n"); + exit(1); + } + + mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n", + mb_kernel_size, (size_t)mh_entry_addr); + } else { + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */ + uint32_t mh_header_addr = ldl_p(header+i+12); + uint32_t mh_load_end_addr = ldl_p(header+i+20); + uint32_t mh_bss_end_addr = ldl_p(header+i+24); + mh_load_addr = ldl_p(header+i+16); + uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); + uint32_t mb_load_size = 0; + mh_entry_addr = ldl_p(header+i+28); + + if (mh_load_end_addr) { + mb_kernel_size = mh_bss_end_addr - mh_load_addr; + mb_load_size = mh_load_end_addr - mh_load_addr; + } else { + mb_kernel_size = kernel_file_size - mb_kernel_text_offset; + mb_load_size = mb_kernel_size; + } + + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. + uint32_t mh_mode_type = ldl_p(header+i+32); + uint32_t mh_width = ldl_p(header+i+36); + uint32_t mh_height = ldl_p(header+i+40); + uint32_t mh_depth = ldl_p(header+i+44); */ + + mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr); + mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr); + mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr); + mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr); + mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n", + mb_load_size, mh_load_addr); + + mbs.mb_buf = g_malloc(mb_kernel_size); + fseek(f, mb_kernel_text_offset, SEEK_SET); + if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) { + fprintf(stderr, "fread() failed\n"); + exit(1); + } + memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size); + fclose(f); + } + + mbs.mb_buf_phys = mh_load_addr; + + mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size); + mbs.offset_mbinfo = mbs.mb_buf_size; + + /* Calculate space for cmdlines and mb_mods */ + mbs.mb_buf_size += strlen(kernel_filename) + 1; + mbs.mb_buf_size += strlen(kernel_cmdline) + 1; + if (initrd_filename) { + const char *r = initrd_filename; + mbs.mb_buf_size += strlen(r) + 1; + mbs.mb_mods_avail = 1; + while (*(r = get_opt_value(NULL, 0, r))) { + mbs.mb_mods_avail++; + r++; + } + mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail; + } + + mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size); + + /* enlarge mb_buf to hold cmdlines and mb-info structs */ + mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); + mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE; + + if (initrd_filename) { + char *next_initrd, not_last; + + mbs.offset_mods = mbs.mb_buf_size; + + do { + char *next_space; + int mb_mod_length; + uint32_t offs = mbs.mb_buf_size; + + next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename); + not_last = *next_initrd; + *next_initrd = '\0'; + /* if a space comes after the module filename, treat everything + after that as parameters */ + hwaddr c = mb_add_cmdline(&mbs, initrd_filename); + if ((next_space = strchr(initrd_filename, ' '))) + *next_space = '\0'; + mb_debug("multiboot loading module: %s\n", initrd_filename); + mb_mod_length = get_image_size(initrd_filename); + if (mb_mod_length < 0) { + fprintf(stderr, "Failed to open file '%s'\n", initrd_filename); + exit(1); + } + + mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size); + mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); + + load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs); + mb_add_mod(&mbs, mbs.mb_buf_phys + offs, + mbs.mb_buf_phys + offs + mb_mod_length, c); + + mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx"\n", + (char *)mbs.mb_buf + offs, + (char *)mbs.mb_buf + offs + mb_mod_length, c); + initrd_filename = next_initrd+1; + } while (not_last); + } + + /* Commandline support */ + char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2]; + snprintf(kcmdline, sizeof(kcmdline), "%s %s", + kernel_filename, kernel_cmdline); + stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline)); + + stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo); + stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */ + + /* the kernel is where we want it to be now */ + stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY + | MULTIBOOT_FLAGS_BOOT_DEVICE + | MULTIBOOT_FLAGS_CMDLINE + | MULTIBOOT_FLAGS_MODULES + | MULTIBOOT_FLAGS_MMAP); + stl_p(bootinfo + MBI_MEM_LOWER, 640); + stl_p(bootinfo + MBI_MEM_UPPER, (ram_size / 1024) - 1024); + stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */ + stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP); + + mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr); + mb_debug(" mb_buf_phys = "TARGET_FMT_plx"\n", mbs.mb_buf_phys); + mb_debug(" mod_start = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods); + mb_debug(" mb_mods_count = %d\n", mbs.mb_mods_count); + + /* save bootinfo off the stack */ + mb_bootinfo_data = g_malloc(sizeof(bootinfo)); + memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo)); + + /* Pass variables to option rom */ + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, + mbs.mb_buf, mbs.mb_buf_size); + + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo)); + fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data, + sizeof(bootinfo)); + + option_rom[nb_option_roms].name = "multiboot.bin"; + option_rom[nb_option_roms].bootindex = 0; + nb_option_roms++; + + return 1; /* yes, we are multiboot */ +} diff --git a/hw/i386/pc.c b/hw/i386/pc.c new file mode 100644 index 0000000000..309bb83cab --- /dev/null +++ b/hw/i386/pc.c @@ -0,0 +1,1161 @@ +/* + * QEMU PC System Emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/apic.h" +#include "hw/fdc.h" +#include "hw/ide.h" +#include "hw/pci/pci.h" +#include "monitor/monitor.h" +#include "hw/fw_cfg.h" +#include "hw/hpet_emul.h" +#include "hw/smbios.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/multiboot.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" +#include "hw/pci/msi.h" +#include "hw/sysbus.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "kvm_i386.h" +#include "hw/xen.h" +#include "sysemu/blockdev.h" +#include "hw/block-common.h" +#include "ui/qemu-spice.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "sysemu/arch_init.h" +#include "qemu/bitmap.h" + +/* debug PC/ISA interrupts */ +//#define DEBUG_IRQ + +#ifdef DEBUG_IRQ +#define DPRINTF(fmt, ...) \ + do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) +#endif + +/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ +#define ACPI_DATA_SIZE 0x10000 +#define BIOS_CFG_IOPORT 0x510 +#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) +#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) +#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) +#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) +#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4) + +#define E820_NR_ENTRIES 16 + +struct e820_entry { + uint64_t address; + uint64_t length; + uint32_t type; +} QEMU_PACKED __attribute((__aligned__(4))); + +struct e820_table { + uint32_t count; + struct e820_entry entry[E820_NR_ENTRIES]; +} QEMU_PACKED __attribute((__aligned__(4))); + +static struct e820_table e820_table; +struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; + +void gsi_handler(void *opaque, int n, int level) +{ + GSIState *s = opaque; + + DPRINTF("pc: %s GSI %d\n", level ? "raising" : "lowering", n); + if (n < ISA_NUM_IRQS) { + qemu_set_irq(s->i8259_irq[n], level); + } + qemu_set_irq(s->ioapic_irq[n], level); +} + +static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ +} + +static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0xffffffffffffffffULL; +} + +/* MSDOS compatibility mode FPU exception support */ +static qemu_irq ferr_irq; + +void pc_register_ferr_irq(qemu_irq irq) +{ + ferr_irq = irq; +} + +/* XXX: add IGNNE support */ +void cpu_set_ferr(CPUX86State *s) +{ + qemu_irq_raise(ferr_irq); +} + +static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + qemu_irq_lower(ferr_irq); +} + +static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0xffffffffffffffffULL; +} + +/* TSC handling */ +uint64_t cpu_get_tsc(CPUX86State *env) +{ + return cpu_get_ticks(); +} + +/* SMM support */ + +static cpu_set_smm_t smm_set; +static void *smm_arg; + +void cpu_smm_register(cpu_set_smm_t callback, void *arg) +{ + assert(smm_set == NULL); + assert(smm_arg == NULL); + smm_set = callback; + smm_arg = arg; +} + +void cpu_smm_update(CPUX86State *env) +{ + if (smm_set && smm_arg && env == first_cpu) + smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg); +} + + +/* IRQ handling */ +int cpu_get_pic_interrupt(CPUX86State *env) +{ + int intno; + + intno = apic_get_interrupt(env->apic_state); + if (intno >= 0) { + return intno; + } + /* read the irq from the PIC */ + if (!apic_accept_pic_intr(env->apic_state)) { + return -1; + } + + intno = pic_read_irq(isa_pic); + return intno; +} + +static void pic_irq_request(void *opaque, int irq, int level) +{ + CPUX86State *env = first_cpu; + + DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq); + if (env->apic_state) { + while (env) { + if (apic_accept_pic_intr(env->apic_state)) { + apic_deliver_pic_intr(env->apic_state, level); + } + env = env->next_cpu; + } + } else { + if (level) + cpu_interrupt(env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +/* PC cmos mappings */ + +#define REG_EQUIPMENT_BYTE 0x14 + +static int cmos_get_fd_drive_type(FDriveType fd0) +{ + int val; + + switch (fd0) { + case FDRIVE_DRV_144: + /* 1.44 Mb 3"5 drive */ + val = 4; + break; + case FDRIVE_DRV_288: + /* 2.88 Mb 3"5 drive */ + val = 5; + break; + case FDRIVE_DRV_120: + /* 1.2 Mb 5"5 drive */ + val = 2; + break; + case FDRIVE_DRV_NONE: + default: + val = 0; + break; + } + return val; +} + +static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs, + int16_t cylinders, int8_t heads, int8_t sectors) +{ + rtc_set_memory(s, type_ofs, 47); + rtc_set_memory(s, info_ofs, cylinders); + rtc_set_memory(s, info_ofs + 1, cylinders >> 8); + rtc_set_memory(s, info_ofs + 2, heads); + rtc_set_memory(s, info_ofs + 3, 0xff); + rtc_set_memory(s, info_ofs + 4, 0xff); + rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); + rtc_set_memory(s, info_ofs + 6, cylinders); + rtc_set_memory(s, info_ofs + 7, cylinders >> 8); + rtc_set_memory(s, info_ofs + 8, sectors); +} + +/* convert boot_device letter to something recognizable by the bios */ +static int boot_device2nibble(char boot_device) +{ + switch(boot_device) { + case 'a': + case 'b': + return 0x01; /* floppy boot */ + case 'c': + return 0x02; /* hard drive boot */ + case 'd': + return 0x03; /* CD-ROM boot */ + case 'n': + return 0x04; /* Network boot */ + } + return 0; +} + +static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk) +{ +#define PC_MAX_BOOT_DEVICES 3 + int nbds, bds[3] = { 0, }; + int i; + + nbds = strlen(boot_device); + if (nbds > PC_MAX_BOOT_DEVICES) { + error_report("Too many boot devices for PC"); + return(1); + } + for (i = 0; i < nbds; i++) { + bds[i] = boot_device2nibble(boot_device[i]); + if (bds[i] == 0) { + error_report("Invalid boot device for PC: '%c'", + boot_device[i]); + return(1); + } + } + rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); + rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1)); + return(0); +} + +static int pc_boot_set(void *opaque, const char *boot_device) +{ + return set_boot_dev(opaque, boot_device, 0); +} + +typedef struct pc_cmos_init_late_arg { + ISADevice *rtc_state; + BusState *idebus[2]; +} pc_cmos_init_late_arg; + +static void pc_cmos_init_late(void *opaque) +{ + pc_cmos_init_late_arg *arg = opaque; + ISADevice *s = arg->rtc_state; + int16_t cylinders; + int8_t heads, sectors; + int val; + int i, trans; + + val = 0; + if (ide_get_geometry(arg->idebus[0], 0, + &cylinders, &heads, §ors) >= 0) { + cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors); + val |= 0xf0; + } + if (ide_get_geometry(arg->idebus[0], 1, + &cylinders, &heads, §ors) >= 0) { + cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors); + val |= 0x0f; + } + rtc_set_memory(s, 0x12, val); + + val = 0; + for (i = 0; i < 4; i++) { + /* NOTE: ide_get_geometry() returns the physical + geometry. It is always such that: 1 <= sects <= 63, 1 + <= heads <= 16, 1 <= cylinders <= 16383. The BIOS + geometry can be different if a translation is done. */ + if (ide_get_geometry(arg->idebus[i / 2], i % 2, + &cylinders, &heads, §ors) >= 0) { + trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1; + assert((trans & ~3) == 0); + val |= trans << (i * 2); + } + } + rtc_set_memory(s, 0x39, val); + + qemu_unregister_reset(pc_cmos_init_late, opaque); +} + +void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, + const char *boot_device, + ISADevice *floppy, BusState *idebus0, BusState *idebus1, + ISADevice *s) +{ + int val, nb, i; + FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE }; + static pc_cmos_init_late_arg arg; + + /* various important CMOS locations needed by PC/Bochs bios */ + + /* memory size */ + /* base memory (first MiB) */ + val = MIN(ram_size / 1024, 640); + rtc_set_memory(s, 0x15, val); + rtc_set_memory(s, 0x16, val >> 8); + /* extended memory (next 64MiB) */ + if (ram_size > 1024 * 1024) { + val = (ram_size - 1024 * 1024) / 1024; + } else { + val = 0; + } + if (val > 65535) + val = 65535; + rtc_set_memory(s, 0x17, val); + rtc_set_memory(s, 0x18, val >> 8); + rtc_set_memory(s, 0x30, val); + rtc_set_memory(s, 0x31, val >> 8); + /* memory between 16MiB and 4GiB */ + if (ram_size > 16 * 1024 * 1024) { + val = (ram_size - 16 * 1024 * 1024) / 65536; + } else { + val = 0; + } + if (val > 65535) + val = 65535; + rtc_set_memory(s, 0x34, val); + rtc_set_memory(s, 0x35, val >> 8); + /* memory above 4GiB */ + val = above_4g_mem_size / 65536; + rtc_set_memory(s, 0x5b, val); + rtc_set_memory(s, 0x5c, val >> 8); + rtc_set_memory(s, 0x5d, val >> 16); + + /* set the number of CPU */ + rtc_set_memory(s, 0x5f, smp_cpus - 1); + + /* set boot devices, and disable floppy signature check if requested */ + if (set_boot_dev(s, boot_device, fd_bootchk)) { + exit(1); + } + + /* floppy type */ + if (floppy) { + for (i = 0; i < 2; i++) { + fd_type[i] = isa_fdc_get_drive_type(floppy, i); + } + } + val = (cmos_get_fd_drive_type(fd_type[0]) << 4) | + cmos_get_fd_drive_type(fd_type[1]); + rtc_set_memory(s, 0x10, val); + + val = 0; + nb = 0; + if (fd_type[0] < FDRIVE_DRV_NONE) { + nb++; + } + if (fd_type[1] < FDRIVE_DRV_NONE) { + nb++; + } + switch (nb) { + case 0: + break; + case 1: + val |= 0x01; /* 1 drive, ready for boot */ + break; + case 2: + val |= 0x41; /* 2 drives, ready for boot */ + break; + } + val |= 0x02; /* FPU is there */ + val |= 0x04; /* PS/2 mouse installed */ + rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); + + /* hard drives */ + arg.rtc_state = s; + arg.idebus[0] = idebus0; + arg.idebus[1] = idebus1; + qemu_register_reset(pc_cmos_init_late, &arg); +} + +/* port 92 stuff: could be split off */ +typedef struct Port92State { + ISADevice dev; + MemoryRegion io; + uint8_t outport; + qemu_irq *a20_out; +} Port92State; + +static void port92_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + Port92State *s = opaque; + + DPRINTF("port92: write 0x%02x\n", val); + s->outport = val; + qemu_set_irq(*s->a20_out, (val >> 1) & 1); + if (val & 1) { + qemu_system_reset_request(); + } +} + +static uint64_t port92_read(void *opaque, hwaddr addr, + unsigned size) +{ + Port92State *s = opaque; + uint32_t ret; + + ret = s->outport; + DPRINTF("port92: read 0x%02x\n", ret); + return ret; +} + +static void port92_init(ISADevice *dev, qemu_irq *a20_out) +{ + Port92State *s = DO_UPCAST(Port92State, dev, dev); + + s->a20_out = a20_out; +} + +static const VMStateDescription vmstate_port92_isa = { + .name = "port92", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT8(outport, Port92State), + VMSTATE_END_OF_LIST() + } +}; + +static void port92_reset(DeviceState *d) +{ + Port92State *s = container_of(d, Port92State, dev.qdev); + + s->outport &= ~1; +} + +static const MemoryRegionOps port92_ops = { + .read = port92_read, + .write = port92_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int port92_initfn(ISADevice *dev) +{ + Port92State *s = DO_UPCAST(Port92State, dev, dev); + + memory_region_init_io(&s->io, &port92_ops, s, "port92", 1); + isa_register_ioport(dev, &s->io, 0x92); + + s->outport = 0; + return 0; +} + +static void port92_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = port92_initfn; + dc->no_user = 1; + dc->reset = port92_reset; + dc->vmsd = &vmstate_port92_isa; +} + +static const TypeInfo port92_info = { + .name = "port92", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(Port92State), + .class_init = port92_class_initfn, +}; + +static void port92_register_types(void) +{ + type_register_static(&port92_info); +} + +type_init(port92_register_types) + +static void handle_a20_line_change(void *opaque, int irq, int level) +{ + X86CPU *cpu = opaque; + + /* XXX: send to all CPUs ? */ + /* XXX: add logic to handle multiple A20 line sources */ + x86_cpu_set_a20(cpu, level); +} + +int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) +{ + int index = le32_to_cpu(e820_table.count); + struct e820_entry *entry; + + if (index >= E820_NR_ENTRIES) + return -EBUSY; + entry = &e820_table.entry[index++]; + + entry->address = cpu_to_le64(address); + entry->length = cpu_to_le64(length); + entry->type = cpu_to_le32(type); + + e820_table.count = cpu_to_le32(index); + return index; +} + +/* Calculates the limit to CPU APIC ID values + * + * This function returns the limit for the APIC ID value, so that all + * CPU APIC IDs are < pc_apic_id_limit(). + * + * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). + */ +static unsigned int pc_apic_id_limit(unsigned int max_cpus) +{ + return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; +} + +static void *bochs_bios_init(void) +{ + void *fw_cfg; + uint8_t *smbios_table; + size_t smbios_len; + uint64_t *numa_fw_cfg; + int i, j; + unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); + + fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); + /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: + * + * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug + * QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC + * ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the + * "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS + * may see". + * + * So, this means we must not use max_cpus, here, but the maximum possible + * APIC ID value, plus one. + * + * [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is + * the APIC ID, not the "CPU index" + */ + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, + acpi_tables, acpi_tables_len); + fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); + + smbios_table = smbios_get_table(&smbios_len); + if (smbios_table) + fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, + smbios_table, smbios_len); + fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, + &e820_table, sizeof(e820_table)); + + fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg)); + /* allocate memory for the NUMA channel: one (64bit) word for the number + * of nodes, one word for each VCPU->node and one word for each node to + * hold the amount of memory. + */ + numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes); + numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); + for (i = 0; i < max_cpus; i++) { + unsigned int apic_id = x86_cpu_apic_id_from_index(i); + assert(apic_id < apic_id_limit); + for (j = 0; j < nb_numa_nodes; j++) { + if (test_bit(i, node_cpumask[j])) { + numa_fw_cfg[apic_id + 1] = cpu_to_le64(j); + break; + } + } + } + for (i = 0; i < nb_numa_nodes; i++) { + numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]); + } + fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, + (1 + apic_id_limit + nb_numa_nodes) * + sizeof(*numa_fw_cfg)); + + return fw_cfg; +} + +static long get_file_size(FILE *f) +{ + long where, size; + + /* XXX: on Unix systems, using fstat() probably makes more sense */ + + where = ftell(f); + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, where, SEEK_SET); + + return size; +} + +static void load_linux(void *fw_cfg, + const char *kernel_filename, + const char *initrd_filename, + const char *kernel_cmdline, + hwaddr max_ram_size) +{ + uint16_t protocol; + int setup_size, kernel_size, initrd_size = 0, cmdline_size; + uint32_t initrd_max; + uint8_t header[8192], *setup, *kernel, *initrd_data; + hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; + FILE *f; + char *vmode; + + /* Align to 16 bytes as a paranoia measure */ + cmdline_size = (strlen(kernel_cmdline)+16) & ~15; + + /* load the kernel header */ + f = fopen(kernel_filename, "rb"); + if (!f || !(kernel_size = get_file_size(f)) || + fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) != + MIN(ARRAY_SIZE(header), kernel_size)) { + fprintf(stderr, "qemu: could not load kernel '%s': %s\n", + kernel_filename, strerror(errno)); + exit(1); + } + + /* kernel protocol version */ +#if 0 + fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202)); +#endif + if (ldl_p(header+0x202) == 0x53726448) + protocol = lduw_p(header+0x206); + else { + /* This looks like a multiboot kernel. If it is, let's stop + treating it like a Linux kernel. */ + if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename, + kernel_cmdline, kernel_size, header)) + return; + protocol = 0; + } + + if (protocol < 0x200 || !(header[0x211] & 0x01)) { + /* Low kernel */ + real_addr = 0x90000; + cmdline_addr = 0x9a000 - cmdline_size; + prot_addr = 0x10000; + } else if (protocol < 0x202) { + /* High but ancient kernel */ + real_addr = 0x90000; + cmdline_addr = 0x9a000 - cmdline_size; + prot_addr = 0x100000; + } else { + /* High and recent kernel */ + real_addr = 0x10000; + cmdline_addr = 0x20000; + prot_addr = 0x100000; + } + +#if 0 + fprintf(stderr, + "qemu: real_addr = 0x" TARGET_FMT_plx "\n" + "qemu: cmdline_addr = 0x" TARGET_FMT_plx "\n" + "qemu: prot_addr = 0x" TARGET_FMT_plx "\n", + real_addr, + cmdline_addr, + prot_addr); +#endif + + /* highest address for loading the initrd */ + if (protocol >= 0x203) + initrd_max = ldl_p(header+0x22c); + else + initrd_max = 0x37ffffff; + + if (initrd_max >= max_ram_size-ACPI_DATA_SIZE) + initrd_max = max_ram_size-ACPI_DATA_SIZE-1; + + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + + if (protocol >= 0x202) { + stl_p(header+0x228, cmdline_addr); + } else { + stw_p(header+0x20, 0xA33F); + stw_p(header+0x22, cmdline_addr-real_addr); + } + + /* handle vga= parameter */ + vmode = strstr(kernel_cmdline, "vga="); + if (vmode) { + unsigned int video_mode; + /* skip "vga=" */ + vmode += 4; + if (!strncmp(vmode, "normal", 6)) { + video_mode = 0xffff; + } else if (!strncmp(vmode, "ext", 3)) { + video_mode = 0xfffe; + } else if (!strncmp(vmode, "ask", 3)) { + video_mode = 0xfffd; + } else { + video_mode = strtol(vmode, NULL, 0); + } + stw_p(header+0x1fa, video_mode); + } + + /* loader type */ + /* High nybble = B reserved for QEMU; low nybble is revision number. + If this code is substantially changed, you may want to consider + incrementing the revision. */ + if (protocol >= 0x200) + header[0x210] = 0xB0; + + /* heap */ + if (protocol >= 0x201) { + header[0x211] |= 0x80; /* CAN_USE_HEAP */ + stw_p(header+0x224, cmdline_addr-real_addr-0x200); + } + + /* load initrd */ + if (initrd_filename) { + if (protocol < 0x200) { + fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n"); + exit(1); + } + + initrd_size = get_image_size(initrd_filename); + if (initrd_size < 0) { + fprintf(stderr, "qemu: error reading initrd %s\n", + initrd_filename); + exit(1); + } + + initrd_addr = (initrd_max-initrd_size) & ~4095; + + initrd_data = g_malloc(initrd_size); + load_image(initrd_filename, initrd_data); + + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size); + + stl_p(header+0x218, initrd_addr); + stl_p(header+0x21c, initrd_size); + } + + /* load kernel and setup */ + setup_size = header[0x1f1]; + if (setup_size == 0) + setup_size = 4; + setup_size = (setup_size+1)*512; + kernel_size -= setup_size; + + setup = g_malloc(setup_size); + kernel = g_malloc(kernel_size); + fseek(f, 0, SEEK_SET); + if (fread(setup, 1, setup_size, f) != setup_size) { + fprintf(stderr, "fread() failed\n"); + exit(1); + } + if (fread(kernel, 1, kernel_size, f) != kernel_size) { + fprintf(stderr, "fread() failed\n"); + exit(1); + } + fclose(f); + memcpy(setup, header, MIN(sizeof(header), setup_size)); + + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); + + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size); + + option_rom[nb_option_roms].name = "linuxboot.bin"; + option_rom[nb_option_roms].bootindex = 0; + nb_option_roms++; +} + +#define NE2000_NB_MAX 6 + +static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, + 0x280, 0x380 }; +static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; + +static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; +static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; + +void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd) +{ + static int nb_ne2k = 0; + + if (nb_ne2k == NE2000_NB_MAX) + return; + isa_ne2000_init(bus, ne2000_io[nb_ne2k], + ne2000_irq[nb_ne2k], nd); + nb_ne2k++; +} + +DeviceState *cpu_get_current_apic(void) +{ + if (cpu_single_env) { + return cpu_single_env->apic_state; + } else { + return NULL; + } +} + +void pc_acpi_smi_interrupt(void *opaque, int irq, int level) +{ + CPUX86State *s = opaque; + + if (level) { + cpu_interrupt(s, CPU_INTERRUPT_SMI); + } +} + +void pc_cpus_init(const char *cpu_model) +{ + int i; + + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_X86_64 + cpu_model = "qemu64"; +#else + cpu_model = "qemu32"; +#endif + } + + for (i = 0; i < smp_cpus; i++) { + if (!cpu_x86_init(cpu_model)) { + exit(1); + } + } +} + +void pc_acpi_init(const char *default_dsdt) +{ + char *filename = NULL, *arg = NULL; + + if (acpi_tables != NULL) { + /* manually set via -acpitable, leave it alone */ + return; + } + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt); + if (filename == NULL) { + fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt); + return; + } + + arg = g_strdup_printf("file=%s", filename); + if (acpi_table_add(arg) != 0) { + fprintf(stderr, "WARNING: failed to load %s\n", filename); + } + g_free(arg); + g_free(filename); +} + +void *pc_memory_init(MemoryRegion *system_memory, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + ram_addr_t below_4g_mem_size, + ram_addr_t above_4g_mem_size, + MemoryRegion *rom_memory, + MemoryRegion **ram_memory) +{ + int linux_boot, i; + MemoryRegion *ram, *option_rom_mr; + MemoryRegion *ram_below_4g, *ram_above_4g; + void *fw_cfg; + + linux_boot = (kernel_filename != NULL); + + /* Allocate RAM. We allocate it as a single memory region and use + * aliases to address portions of it, mostly for backwards compatibility + * with older qemus that used qemu_ram_alloc(). + */ + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, "pc.ram", + below_4g_mem_size + above_4g_mem_size); + vmstate_register_ram_global(ram); + *ram_memory = ram; + ram_below_4g = g_malloc(sizeof(*ram_below_4g)); + memory_region_init_alias(ram_below_4g, "ram-below-4g", ram, + 0, below_4g_mem_size); + memory_region_add_subregion(system_memory, 0, ram_below_4g); + if (above_4g_mem_size > 0) { + ram_above_4g = g_malloc(sizeof(*ram_above_4g)); + memory_region_init_alias(ram_above_4g, "ram-above-4g", ram, + below_4g_mem_size, above_4g_mem_size); + memory_region_add_subregion(system_memory, 0x100000000ULL, + ram_above_4g); + } + + + /* Initialize PC system firmware */ + pc_system_firmware_init(rom_memory); + + option_rom_mr = g_malloc(sizeof(*option_rom_mr)); + memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE); + vmstate_register_ram_global(option_rom_mr); + memory_region_add_subregion_overlap(rom_memory, + PC_ROM_MIN_VGA, + option_rom_mr, + 1); + + fw_cfg = bochs_bios_init(); + rom_set_fw(fw_cfg); + + if (linux_boot) { + load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size); + } + + for (i = 0; i < nb_option_roms; i++) { + rom_add_option(option_rom[i].name, option_rom[i].bootindex); + } + return fw_cfg; +} + +qemu_irq *pc_allocate_cpu_irq(void) +{ + return qemu_allocate_irqs(pic_irq_request, NULL, 1); +} + +DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) +{ + DeviceState *dev = NULL; + + if (pci_bus) { + PCIDevice *pcidev = pci_vga_init(pci_bus); + dev = pcidev ? &pcidev->qdev : NULL; + } else if (isa_bus) { + ISADevice *isadev = isa_vga_init(isa_bus); + dev = isadev ? &isadev->qdev : NULL; + } + return dev; +} + +static void cpu_request_exit(void *opaque, int irq, int level) +{ + CPUX86State *env = cpu_single_env; + + if (env && level) { + cpu_exit(env); + } +} + +static const MemoryRegionOps ioport80_io_ops = { + .write = ioport80_write, + .read = ioport80_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static const MemoryRegionOps ioportF0_io_ops = { + .write = ioportF0_write, + .read = ioportF0_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, + ISADevice **rtc_state, + ISADevice **floppy, + bool no_vmport) +{ + int i; + DriveInfo *fd[MAX_FD]; + DeviceState *hpet = NULL; + int pit_isa_irq = 0; + qemu_irq pit_alt_irq = NULL; + qemu_irq rtc_irq = NULL; + qemu_irq *a20_line; + ISADevice *i8042, *port92, *vmmouse, *pit = NULL; + qemu_irq *cpu_exit_irq; + MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); + MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); + + memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io); + + memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io); + + /* + * Check if an HPET shall be created. + * + * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT + * when the HPET wants to take over. Thus we have to disable the latter. + */ + if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) { + hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL); + + if (hpet) { + for (i = 0; i < GSI_NUM_PINS; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]); + } + pit_isa_irq = -1; + pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT); + rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT); + } + } + *rtc_state = rtc_init(isa_bus, 2000, rtc_irq); + + qemu_register_boot_set(pc_boot_set, *rtc_state); + + if (!xen_enabled()) { + if (kvm_irqchip_in_kernel()) { + pit = kvm_pit_init(isa_bus, 0x40); + } else { + pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq); + } + if (hpet) { + /* connect PIT to output control line of the HPET */ + qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0)); + } + pcspk_init(isa_bus, pit); + } + + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_isa_init(isa_bus, i, serial_hds[i]); + } + } + + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_hds[i]) { + parallel_init(isa_bus, i, parallel_hds[i]); + } + } + + a20_line = qemu_allocate_irqs(handle_a20_line_change, + x86_env_get_cpu(first_cpu), 2); + i8042 = isa_create_simple(isa_bus, "i8042"); + i8042_setup_a20_line(i8042, &a20_line[0]); + if (!no_vmport) { + vmport_init(isa_bus); + vmmouse = isa_try_create(isa_bus, "vmmouse"); + } else { + vmmouse = NULL; + } + if (vmmouse) { + qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042); + qdev_init_nofail(&vmmouse->qdev); + } + port92 = isa_create_simple(isa_bus, "port92"); + port92_init(port92, &a20_line[1]); + + cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); + DMA_init(0, cpu_exit_irq); + + for(i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); + } + *floppy = fdctrl_init_isa(isa_bus, fd); +} + +void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) +{ + int i; + + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) { + pc_init_ne2k_isa(isa_bus, nd); + } else { + pci_nic_init_nofail(nd, "e1000", NULL); + } + } +} + +void pc_pci_device_init(PCIBus *pci_bus) +{ + int max_bus; + int bus; + + max_bus = drive_get_max_bus(IF_SCSI); + for (bus = 0; bus <= max_bus; bus++) { + pci_create_simple(pci_bus, -1, "lsi53c895a"); + } +} + +void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) +{ + DeviceState *dev; + SysBusDevice *d; + unsigned int i; + + if (kvm_irqchip_in_kernel()) { + dev = qdev_create(NULL, "kvm-ioapic"); + } else { + dev = qdev_create(NULL, "ioapic"); + } + if (parent_name) { + object_property_add_child(object_resolve_path(parent_name, NULL), + "ioapic", OBJECT(dev), NULL); + } + qdev_init_nofail(dev); + d = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(d, 0, 0xfec00000); + + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); + } +} diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c new file mode 100644 index 0000000000..73a8656df8 --- /dev/null +++ b/hw/i386/pc_piix.c @@ -0,0 +1,713 @@ +/* + * QEMU PC System Emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/apic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_ids.h" +#include "hw/usb.h" +#include "net/net.h" +#include "hw/boards.h" +#include "hw/ide.h" +#include "sysemu/kvm.h" +#include "hw/kvm/clock.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "sysemu/arch_init.h" +#include "sysemu/blockdev.h" +#include "hw/smbus.h" +#include "hw/xen.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "cpu.h" +#ifdef CONFIG_XEN +# include +#endif + +#define MAX_IDE_BUS 2 + +static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; +static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; +static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; + +/* PC hardware initialisation */ +static void pc_init1(MemoryRegion *system_memory, + MemoryRegion *system_io, + ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model, + int pci_enabled, + int kvmclock_enabled) +{ + int i; + ram_addr_t below_4g_mem_size, above_4g_mem_size; + PCIBus *pci_bus; + ISABus *isa_bus; + PCII440FXState *i440fx_state; + int piix3_devfn = -1; + qemu_irq *cpu_irq; + qemu_irq *gsi; + qemu_irq *i8259; + qemu_irq *smi_irq; + GSIState *gsi_state; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BusState *idebus[MAX_IDE_BUS]; + ISADevice *rtc_state; + ISADevice *floppy; + MemoryRegion *ram_memory; + MemoryRegion *pci_memory; + MemoryRegion *rom_memory; + void *fw_cfg = NULL; + + pc_cpus_init(cpu_model); + pc_acpi_init("acpi-dsdt.aml"); + + if (kvmclock_enabled) { + kvmclock_create(); + } + + if (ram_size >= 0xe0000000 ) { + above_4g_mem_size = ram_size - 0xe0000000; + below_4g_mem_size = 0xe0000000; + } else { + above_4g_mem_size = 0; + below_4g_mem_size = ram_size; + } + + if (pci_enabled) { + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, "pci", INT64_MAX); + rom_memory = pci_memory; + } else { + pci_memory = NULL; + rom_memory = system_memory; + } + + /* allocate ram and load rom/bios */ + if (!xen_enabled()) { + fw_cfg = pc_memory_init(system_memory, + kernel_filename, kernel_cmdline, initrd_filename, + below_4g_mem_size, above_4g_mem_size, + rom_memory, &ram_memory); + } + + gsi_state = g_malloc0(sizeof(*gsi_state)); + if (kvm_irqchip_in_kernel()) { + kvm_pc_setup_irq_routing(pci_enabled); + gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, + GSI_NUM_PINS); + } else { + gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + } + + if (pci_enabled) { + pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, + system_memory, system_io, ram_size, + below_4g_mem_size, + 0x100000000ULL - below_4g_mem_size, + 0x100000000ULL + above_4g_mem_size, + (sizeof(hwaddr) == 4 + ? 0 + : ((uint64_t)1 << 62)), + pci_memory, ram_memory); + } else { + pci_bus = NULL; + i440fx_state = NULL; + isa_bus = isa_bus_new(NULL, system_io); + no_hpet = 1; + } + isa_bus_irqs(isa_bus, gsi); + + if (kvm_irqchip_in_kernel()) { + i8259 = kvm_i8259_init(isa_bus); + } else if (xen_enabled()) { + i8259 = xen_interrupt_controller_init(); + } else { + cpu_irq = pc_allocate_cpu_irq(); + i8259 = i8259_init(isa_bus, cpu_irq[0]); + } + + for (i = 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] = i8259[i]; + } + if (pci_enabled) { + ioapic_init_gsi(gsi_state, "i440fx"); + } + + pc_register_ferr_irq(gsi[13]); + + pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); + if (xen_enabled()) { + pci_create_simple(pci_bus, -1, "xen-platform"); + } + + /* init basic PC hardware */ + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled()); + + pc_nic_init(isa_bus, pci_bus); + + ide_drive_get(hd, MAX_IDE_BUS); + if (pci_enabled) { + PCIDevice *dev; + if (xen_enabled()) { + dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1); + } else { + dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1); + } + idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); + } else { + for(i = 0; i < MAX_IDE_BUS; i++) { + ISADevice *dev; + dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], + ide_irq[i], + hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); + idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0"); + } + } + + audio_init(isa_bus, pci_enabled ? pci_bus : NULL); + + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + floppy, idebus[0], idebus[1], rtc_state); + + if (pci_enabled && usb_enabled(false)) { + pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); + } + + if (pci_enabled && acpi_enabled) { + i2c_bus *smbus; + + smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1); + /* TODO: Populate SPD eeprom data. */ + smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, + gsi[9], *smi_irq, + kvm_enabled(), fw_cfg); + smbus_eeprom_init(smbus, 8, NULL, 0); + } + + if (pci_enabled) { + pc_pci_device_init(pci_bus); + } +} + +static void pc_init_pci(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + pc_init1(get_system_memory(), + get_system_io(), + ram_size, boot_device, + kernel_filename, kernel_cmdline, + initrd_filename, cpu_model, 1, 1); +} + +static void pc_init_pci_1_3(QEMUMachineInitArgs *args) +{ + enable_compat_apic_id_mode(); + pc_init_pci(args); +} + +/* PC machine init function for pc-0.14 to pc-1.2 */ +static void pc_init_pci_1_2(QEMUMachineInitArgs *args) +{ + disable_kvm_pv_eoi(); + pc_init_pci_1_3(args); +} + +/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ +static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + disable_kvm_pv_eoi(); + enable_compat_apic_id_mode(); + pc_init1(get_system_memory(), + get_system_io(), + ram_size, boot_device, + kernel_filename, kernel_cmdline, + initrd_filename, cpu_model, 1, 0); +} + +static void pc_init_isa(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + if (cpu_model == NULL) + cpu_model = "486"; + disable_kvm_pv_eoi(); + enable_compat_apic_id_mode(); + pc_init1(get_system_memory(), + get_system_io(), + ram_size, boot_device, + kernel_filename, kernel_cmdline, + initrd_filename, cpu_model, 0, 1); +} + +#ifdef CONFIG_XEN +static void pc_xen_hvm_init(QEMUMachineInitArgs *args) +{ + if (xen_hvm_init() != 0) { + hw_error("xen hardware virtual machine initialisation failed"); + } + pc_init_pci_no_kvmclock(args); + xen_vcpu_init(); +} +#endif + +static QEMUMachine pc_i440fx_machine_v1_5 = { + .name = "pc-i440fx-1.5", + .alias = "pc", + .desc = "Standard PC (i440FX + PIIX, 1996)", + .init = pc_init_pci, + .max_cpus = 255, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine pc_i440fx_machine_v1_4 = { + .name = "pc-i440fx-1.4", + .desc = "Standard PC (i440FX + PIIX, 1996)", + .init = pc_init_pci, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_4, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_1_3 \ + PC_COMPAT_1_4, \ + {\ + .driver = "usb-tablet",\ + .property = "usb_version",\ + .value = stringify(1),\ + },{\ + .driver = "virtio-net-pci",\ + .property = "ctrl_mac_addr",\ + .value = "off", \ + },{ \ + .driver = "virtio-net-pci", \ + .property = "mq", \ + .value = "off", \ + } + +static QEMUMachine pc_machine_v1_3 = { + .name = "pc-1.3", + .desc = "Standard PC", + .init = pc_init_pci_1_3, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_3, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_1_2 \ + PC_COMPAT_1_3,\ + {\ + .driver = "nec-usb-xhci",\ + .property = "msi",\ + .value = "off",\ + },{\ + .driver = "nec-usb-xhci",\ + .property = "msix",\ + .value = "off",\ + },{\ + .driver = "ivshmem",\ + .property = "use64",\ + .value = "0",\ + },{\ + .driver = "qxl",\ + .property = "revision",\ + .value = stringify(3),\ + },{\ + .driver = "qxl-vga",\ + .property = "revision",\ + .value = stringify(3),\ + },{\ + .driver = "VGA",\ + .property = "mmio",\ + .value = "off",\ + } + +static QEMUMachine pc_machine_v1_2 = { + .name = "pc-1.2", + .desc = "Standard PC", + .init = pc_init_pci_1_2, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_2, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_1_1 \ + PC_COMPAT_1_2,\ + {\ + .driver = "virtio-scsi-pci",\ + .property = "hotplug",\ + .value = "off",\ + },{\ + .driver = "virtio-scsi-pci",\ + .property = "param_change",\ + .value = "off",\ + },{\ + .driver = "VGA",\ + .property = "vgamem_mb",\ + .value = stringify(8),\ + },{\ + .driver = "vmware-svga",\ + .property = "vgamem_mb",\ + .value = stringify(8),\ + },{\ + .driver = "qxl-vga",\ + .property = "vgamem_mb",\ + .value = stringify(8),\ + },{\ + .driver = "qxl",\ + .property = "vgamem_mb",\ + .value = stringify(8),\ + },{\ + .driver = "virtio-blk-pci",\ + .property = "config-wce",\ + .value = "off",\ + } + +static QEMUMachine pc_machine_v1_1 = { + .name = "pc-1.1", + .desc = "Standard PC", + .init = pc_init_pci_1_2, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_1, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_1_0 \ + PC_COMPAT_1_1,\ + {\ + .driver = "pc-sysfw",\ + .property = "rom_only",\ + .value = stringify(1),\ + }, {\ + .driver = "isa-fdc",\ + .property = "check_media_rate",\ + .value = "off",\ + }, {\ + .driver = "virtio-balloon-pci",\ + .property = "class",\ + .value = stringify(PCI_CLASS_MEMORY_RAM),\ + },{\ + .driver = "apic",\ + .property = "vapic",\ + .value = "off",\ + },{\ + .driver = TYPE_USB_DEVICE,\ + .property = "full-path",\ + .value = "no",\ + } + +static QEMUMachine pc_machine_v1_0 = { + .name = "pc-1.0", + .desc = "Standard PC", + .init = pc_init_pci_1_2, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_0, + { /* end of list */ } + }, + .hw_version = "1.0", + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_0_15 \ + PC_COMPAT_1_0 + +static QEMUMachine pc_machine_v0_15 = { + .name = "pc-0.15", + .desc = "Standard PC", + .init = pc_init_pci_1_2, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_0_15, + { /* end of list */ } + }, + .hw_version = "0.15", + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_0_14 \ + PC_COMPAT_0_15,\ + {\ + .driver = "virtio-blk-pci",\ + .property = "event_idx",\ + .value = "off",\ + },{\ + .driver = "virtio-serial-pci",\ + .property = "event_idx",\ + .value = "off",\ + },{\ + .driver = "virtio-net-pci",\ + .property = "event_idx",\ + .value = "off",\ + },{\ + .driver = "virtio-balloon-pci",\ + .property = "event_idx",\ + .value = "off",\ + } + +static QEMUMachine pc_machine_v0_14 = { + .name = "pc-0.14", + .desc = "Standard PC", + .init = pc_init_pci_1_2, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_0_14, + { + .driver = "qxl", + .property = "revision", + .value = stringify(2), + },{ + .driver = "qxl-vga", + .property = "revision", + .value = stringify(2), + }, + { /* end of list */ } + }, + .hw_version = "0.14", + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_0_13 \ + PC_COMPAT_0_14,\ + {\ + .driver = TYPE_PCI_DEVICE,\ + .property = "command_serr_enable",\ + .value = "off",\ + },{\ + .driver = "AC97",\ + .property = "use_broken_id",\ + .value = stringify(1),\ + } + +static QEMUMachine pc_machine_v0_13 = { + .name = "pc-0.13", + .desc = "Standard PC", + .init = pc_init_pci_no_kvmclock, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_0_13, + { + .driver = "virtio-9p-pci", + .property = "vectors", + .value = stringify(0), + },{ + .driver = "VGA", + .property = "rombar", + .value = stringify(0), + },{ + .driver = "vmware-svga", + .property = "rombar", + .value = stringify(0), + }, + { /* end of list */ } + }, + .hw_version = "0.13", + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_0_12 \ + PC_COMPAT_0_13,\ + {\ + .driver = "virtio-serial-pci",\ + .property = "max_ports",\ + .value = stringify(1),\ + },{\ + .driver = "virtio-serial-pci",\ + .property = "vectors",\ + .value = stringify(0),\ + } + +static QEMUMachine pc_machine_v0_12 = { + .name = "pc-0.12", + .desc = "Standard PC", + .init = pc_init_pci_no_kvmclock, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_0_12, + { + .driver = "VGA", + .property = "rombar", + .value = stringify(0), + },{ + .driver = "vmware-svga", + .property = "rombar", + .value = stringify(0), + }, + { /* end of list */ } + }, + .hw_version = "0.12", + DEFAULT_MACHINE_OPTIONS, +}; + +#define PC_COMPAT_0_11 \ + PC_COMPAT_0_12,\ + {\ + .driver = "virtio-blk-pci",\ + .property = "vectors",\ + .value = stringify(0),\ + },{\ + .driver = TYPE_PCI_DEVICE,\ + .property = "rombar",\ + .value = stringify(0),\ + } + +static QEMUMachine pc_machine_v0_11 = { + .name = "pc-0.11", + .desc = "Standard PC, qemu 0.11", + .init = pc_init_pci_no_kvmclock, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_0_11, + { + .driver = "ide-drive", + .property = "ver", + .value = "0.11", + },{ + .driver = "scsi-disk", + .property = "ver", + .value = "0.11", + }, + { /* end of list */ } + }, + .hw_version = "0.11", + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine pc_machine_v0_10 = { + .name = "pc-0.10", + .desc = "Standard PC, qemu 0.10", + .init = pc_init_pci_no_kvmclock, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_0_11, + { + .driver = "virtio-blk-pci", + .property = "class", + .value = stringify(PCI_CLASS_STORAGE_OTHER), + },{ + .driver = "virtio-serial-pci", + .property = "class", + .value = stringify(PCI_CLASS_DISPLAY_OTHER), + },{ + .driver = "virtio-net-pci", + .property = "vectors", + .value = stringify(0), + },{ + .driver = "ide-drive", + .property = "ver", + .value = "0.10", + },{ + .driver = "scsi-disk", + .property = "ver", + .value = "0.10", + }, + { /* end of list */ } + }, + .hw_version = "0.10", + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine isapc_machine = { + .name = "isapc", + .desc = "ISA-only PC", + .init = pc_init_isa, + .max_cpus = 1, + .compat_props = (GlobalProperty[]) { + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + +#ifdef CONFIG_XEN +static QEMUMachine xenfv_machine = { + .name = "xenfv", + .desc = "Xen Fully-virtualized PC", + .init = pc_xen_hvm_init, + .max_cpus = HVM_MAX_VCPUS, + .default_machine_opts = "accel=xen", + DEFAULT_MACHINE_OPTIONS, +}; +#endif + +static void pc_machine_init(void) +{ + qemu_register_machine(&pc_i440fx_machine_v1_5); + qemu_register_machine(&pc_i440fx_machine_v1_4); + qemu_register_machine(&pc_machine_v1_3); + qemu_register_machine(&pc_machine_v1_2); + qemu_register_machine(&pc_machine_v1_1); + qemu_register_machine(&pc_machine_v1_0); + qemu_register_machine(&pc_machine_v0_15); + qemu_register_machine(&pc_machine_v0_14); + qemu_register_machine(&pc_machine_v0_13); + qemu_register_machine(&pc_machine_v0_12); + qemu_register_machine(&pc_machine_v0_11); + qemu_register_machine(&pc_machine_v0_10); + qemu_register_machine(&isapc_machine); +#ifdef CONFIG_XEN + qemu_register_machine(&xenfv_machine); +#endif +} + +machine_init(pc_machine_init); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c new file mode 100644 index 0000000000..4f5f347309 --- /dev/null +++ b/hw/i386/pc_q35.c @@ -0,0 +1,239 @@ +/* + * Q35 chipset based pc system emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2009, 2010 + * Isaku Yamahata + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron + * + * This is based on pc.c, but heavily modified. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "sysemu/arch_init.h" +#include "hw/smbus.h" +#include "hw/boards.h" +#include "hw/mc146818rtc.h" +#include "hw/xen.h" +#include "sysemu/kvm.h" +#include "hw/kvm/clock.h" +#include "hw/q35.h" +#include "exec/address-spaces.h" +#include "hw/ich9.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci.h" +#include "hw/usb.h" + +/* ICH9 AHCI has 6 ports */ +#define MAX_SATA_PORTS 6 + +/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) + * BIOS will read it and start S3 resume at POST Entry */ +static void pc_cmos_set_s3_resume(void *opaque, int irq, int level) +{ + ISADevice *s = opaque; + + if (level) { + rtc_set_memory(s, 0xF, 0xFE); + } +} + +/* PC hardware initialisation */ +static void pc_q35_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + ram_addr_t below_4g_mem_size, above_4g_mem_size; + Q35PCIHost *q35_host; + PCIBus *host_bus; + PCIDevice *lpc; + BusState *idebus[MAX_SATA_PORTS]; + ISADevice *rtc_state; + ISADevice *floppy; + MemoryRegion *pci_memory; + MemoryRegion *rom_memory; + MemoryRegion *ram_memory; + GSIState *gsi_state; + ISABus *isa_bus; + int pci_enabled = 1; + qemu_irq *cpu_irq; + qemu_irq *gsi; + qemu_irq *i8259; + int i; + ICH9LPCState *ich9_lpc; + PCIDevice *ahci; + qemu_irq *cmos_s3; + + pc_cpus_init(cpu_model); + pc_acpi_init("q35-acpi-dsdt.aml"); + + kvmclock_create(); + + if (ram_size >= 0xb0000000) { + above_4g_mem_size = ram_size - 0xb0000000; + below_4g_mem_size = 0xb0000000; + } else { + above_4g_mem_size = 0; + below_4g_mem_size = ram_size; + } + + /* pci enabled */ + if (pci_enabled) { + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, "pci", INT64_MAX); + rom_memory = pci_memory; + } else { + pci_memory = NULL; + rom_memory = get_system_memory(); + } + + /* allocate ram and load rom/bios */ + if (!xen_enabled()) { + pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline, + initrd_filename, below_4g_mem_size, above_4g_mem_size, + rom_memory, &ram_memory); + } + + /* irq lines */ + gsi_state = g_malloc0(sizeof(*gsi_state)); + if (kvm_irqchip_in_kernel()) { + kvm_pc_setup_irq_routing(pci_enabled); + gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, + GSI_NUM_PINS); + } else { + gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + } + + /* create pci host bus */ + q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); + + q35_host->mch.ram_memory = ram_memory; + q35_host->mch.pci_address_space = pci_memory; + q35_host->mch.system_memory = get_system_memory(); + q35_host->mch.address_space_io = get_system_io();; + q35_host->mch.below_4g_mem_size = below_4g_mem_size; + q35_host->mch.above_4g_mem_size = above_4g_mem_size; + /* pci */ + qdev_init_nofail(DEVICE(q35_host)); + host_bus = q35_host->host.pci.bus; + /* create ISA bus */ + lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV, + ICH9_LPC_FUNC), true, + TYPE_ICH9_LPC_DEVICE); + ich9_lpc = ICH9_LPC_DEVICE(lpc); + ich9_lpc->pic = gsi; + ich9_lpc->ioapic = gsi_state->ioapic_irq; + pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc, + ICH9_LPC_NB_PIRQS); + pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq); + isa_bus = ich9_lpc->isa_bus; + + /*end early*/ + isa_bus_irqs(isa_bus, gsi); + + if (kvm_irqchip_in_kernel()) { + i8259 = kvm_i8259_init(isa_bus); + } else if (xen_enabled()) { + i8259 = xen_interrupt_controller_init(); + } else { + cpu_irq = pc_allocate_cpu_irq(); + i8259 = i8259_init(isa_bus, cpu_irq[0]); + } + + for (i = 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] = i8259[i]; + } + if (pci_enabled) { + ioapic_init_gsi(gsi_state, NULL); + } + + pc_register_ferr_irq(gsi[13]); + + /* init basic PC hardware */ + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false); + + /* connect pm stuff to lpc */ + cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); + ich9_lpc_pm_init(lpc, *cmos_s3); + + /* ahci and SATA device, for q35 1 ahci controller is built-in */ + ahci = pci_create_simple_multifunction(host_bus, + PCI_DEVFN(ICH9_SATA1_DEV, + ICH9_SATA1_FUNC), + true, "ich9-ahci"); + idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); + + if (usb_enabled(false)) { + /* Should we create 6 UHCI according to ich9 spec? */ + ehci_create_ich9_with_companions(host_bus, 0x1d); + } + + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(ich9_smb_init(host_bus, + PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), + 0xb100), + 8, NULL, 0); + + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + floppy, idebus[0], idebus[1], rtc_state); + + /* the rest devices to which pci devfn is automatically assigned */ + pc_vga_init(isa_bus, host_bus); + audio_init(isa_bus, host_bus); + pc_nic_init(isa_bus, host_bus); + if (pci_enabled) { + pc_pci_device_init(host_bus); + } +} + +static QEMUMachine pc_q35_machine_v1_5 = { + .name = "pc-q35-1.5", + .alias = "q35", + .desc = "Standard PC (Q35 + ICH9, 2009)", + .init = pc_q35_init, + .max_cpus = 255, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine pc_q35_machine_v1_4 = { + .name = "pc-q35-1.4", + .desc = "Standard PC (Q35 + ICH9, 2009)", + .init = pc_q35_init, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_4, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + +static void pc_q35_machine_init(void) +{ + qemu_register_machine(&pc_q35_machine_v1_5); + qemu_register_machine(&pc_q35_machine_v1_4); +} + +machine_init(pc_q35_machine_init); diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c new file mode 100644 index 0000000000..672ee9b0e7 --- /dev/null +++ b/hw/i386/smbios.c @@ -0,0 +1,241 @@ +/* + * SMBIOS Support + * + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * + * Authors: + * Alex Williamson + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "sysemu/sysemu.h" +#include "hw/smbios.h" +#include "hw/loader.h" + +/* + * Structures shared with the BIOS + */ +struct smbios_header { + uint16_t length; + uint8_t type; +} QEMU_PACKED; + +struct smbios_field { + struct smbios_header header; + uint8_t type; + uint16_t offset; + uint8_t data[]; +} QEMU_PACKED; + +struct smbios_table { + struct smbios_header header; + uint8_t data[]; +} QEMU_PACKED; + +#define SMBIOS_FIELD_ENTRY 0 +#define SMBIOS_TABLE_ENTRY 1 + + +static uint8_t *smbios_entries; +static size_t smbios_entries_len; +static int smbios_type4_count = 0; + +static void smbios_validate_table(void) +{ + if (smbios_type4_count && smbios_type4_count != smp_cpus) { + fprintf(stderr, + "Number of SMBIOS Type 4 tables must match cpu count.\n"); + exit(1); + } +} + +uint8_t *smbios_get_table(size_t *length) +{ + smbios_validate_table(); + *length = smbios_entries_len; + return smbios_entries; +} + +/* + * To avoid unresolvable overlaps in data, don't allow both + * tables and fields for the same smbios type. + */ +static void smbios_check_collision(int type, int entry) +{ + uint16_t *num_entries = (uint16_t *)smbios_entries; + struct smbios_header *header; + char *p; + int i; + + if (!num_entries) + return; + + p = (char *)(num_entries + 1); + + for (i = 0; i < *num_entries; i++) { + header = (struct smbios_header *)p; + if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) { + struct smbios_field *field = (void *)header; + if (type == field->type) { + fprintf(stderr, "SMBIOS type %d field already defined, " + "cannot add table\n", type); + exit(1); + } + } else if (entry == SMBIOS_FIELD_ENTRY && + header->type == SMBIOS_TABLE_ENTRY) { + struct smbios_structure_header *table = (void *)(header + 1); + if (type == table->type) { + fprintf(stderr, "SMBIOS type %d table already defined, " + "cannot add field\n", type); + exit(1); + } + } + p += le16_to_cpu(header->length); + } +} + +void smbios_add_field(int type, int offset, int len, void *data) +{ + struct smbios_field *field; + + smbios_check_collision(type, SMBIOS_FIELD_ENTRY); + + if (!smbios_entries) { + smbios_entries_len = sizeof(uint16_t); + smbios_entries = g_malloc0(smbios_entries_len); + } + smbios_entries = g_realloc(smbios_entries, smbios_entries_len + + sizeof(*field) + len); + field = (struct smbios_field *)(smbios_entries + smbios_entries_len); + field->header.type = SMBIOS_FIELD_ENTRY; + field->header.length = cpu_to_le16(sizeof(*field) + len); + + field->type = type; + field->offset = cpu_to_le16(offset); + memcpy(field->data, data, len); + + smbios_entries_len += sizeof(*field) + len; + (*(uint16_t *)smbios_entries) = + cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); +} + +static void smbios_build_type_0_fields(const char *t) +{ + char buf[1024]; + + if (get_param_value(buf, sizeof(buf), "vendor", t)) + smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "version", t)) + smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "date", t)) + smbios_add_field(0, offsetof(struct smbios_type_0, + bios_release_date_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "release", t)) { + int major, minor; + sscanf(buf, "%d.%d", &major, &minor); + smbios_add_field(0, offsetof(struct smbios_type_0, + system_bios_major_release), 1, &major); + smbios_add_field(0, offsetof(struct smbios_type_0, + system_bios_minor_release), 1, &minor); + } +} + +static void smbios_build_type_1_fields(const char *t) +{ + char buf[1024]; + + if (get_param_value(buf, sizeof(buf), "manufacturer", t)) + smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "product", t)) + smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "version", t)) + smbios_add_field(1, offsetof(struct smbios_type_1, version_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "serial", t)) + smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "uuid", t)) { + if (qemu_uuid_parse(buf, qemu_uuid) != 0) { + fprintf(stderr, "Invalid SMBIOS UUID string\n"); + exit(1); + } + } + if (get_param_value(buf, sizeof(buf), "sku", t)) + smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str), + strlen(buf) + 1, buf); + if (get_param_value(buf, sizeof(buf), "family", t)) + smbios_add_field(1, offsetof(struct smbios_type_1, family_str), + strlen(buf) + 1, buf); +} + +int smbios_entry_add(const char *t) +{ + char buf[1024]; + + if (get_param_value(buf, sizeof(buf), "file", t)) { + struct smbios_structure_header *header; + struct smbios_table *table; + int size = get_image_size(buf); + + if (size == -1 || size < sizeof(struct smbios_structure_header)) { + fprintf(stderr, "Cannot read smbios file %s\n", buf); + exit(1); + } + + if (!smbios_entries) { + smbios_entries_len = sizeof(uint16_t); + smbios_entries = g_malloc0(smbios_entries_len); + } + + smbios_entries = g_realloc(smbios_entries, smbios_entries_len + + sizeof(*table) + size); + table = (struct smbios_table *)(smbios_entries + smbios_entries_len); + table->header.type = SMBIOS_TABLE_ENTRY; + table->header.length = cpu_to_le16(sizeof(*table) + size); + + if (load_image(buf, table->data) != size) { + fprintf(stderr, "Failed to load smbios file %s", buf); + exit(1); + } + + header = (struct smbios_structure_header *)(table->data); + smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY); + if (header->type == 4) { + smbios_type4_count++; + } + + smbios_entries_len += sizeof(*table) + size; + (*(uint16_t *)smbios_entries) = + cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); + return 0; + } + + if (get_param_value(buf, sizeof(buf), "type", t)) { + unsigned long type = strtoul(buf, NULL, 0); + switch (type) { + case 0: + smbios_build_type_0_fields(t); + return 0; + case 1: + smbios_build_type_1_fields(t); + return 0; + default: + fprintf(stderr, "Don't know how to build fields for SMBIOS type " + "%ld\n", type); + exit(1); + } + } + + fprintf(stderr, "smbios: must specify type= or file=\n"); + return -1; +} diff --git a/hw/i386/xen_domainbuild.c b/hw/i386/xen_domainbuild.c new file mode 100644 index 0000000000..d477061545 --- /dev/null +++ b/hw/i386/xen_domainbuild.c @@ -0,0 +1,299 @@ +#include +#include "hw/xen_backend.h" +#include "hw/xen_domainbuild.h" +#include "qemu/timer.h" +#include "qemu/log.h" + +#include + +static int xenstore_domain_mkdir(char *path) +{ + struct xs_permissions perms_ro[] = {{ + .id = 0, /* set owner: dom0 */ + },{ + .id = xen_domid, + .perms = XS_PERM_READ, + }}; + struct xs_permissions perms_rw[] = {{ + .id = 0, /* set owner: dom0 */ + },{ + .id = xen_domid, + .perms = XS_PERM_READ | XS_PERM_WRITE, + }}; + const char *writable[] = { "device", "control", "error", NULL }; + char subpath[256]; + int i; + + if (!xs_mkdir(xenstore, 0, path)) { + fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path); + return -1; + } + if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) { + fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__); + return -1; + } + + for (i = 0; writable[i]; i++) { + snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]); + if (!xs_mkdir(xenstore, 0, subpath)) { + fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath); + return -1; + } + if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) { + fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__); + return -1; + } + } + return 0; +} + +int xenstore_domain_init1(const char *kernel, const char *ramdisk, + const char *cmdline) +{ + char *dom, uuid_string[42], vm[256], path[256]; + int i; + + snprintf(uuid_string, sizeof(uuid_string), UUID_FMT, + qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3], + qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], + qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11], + qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]); + dom = xs_get_domain_path(xenstore, xen_domid); + snprintf(vm, sizeof(vm), "/vm/%s", uuid_string); + + xenstore_domain_mkdir(dom); + + xenstore_write_str(vm, "image/ostype", "linux"); + if (kernel) + xenstore_write_str(vm, "image/kernel", kernel); + if (ramdisk) + xenstore_write_str(vm, "image/ramdisk", ramdisk); + if (cmdline) + xenstore_write_str(vm, "image/cmdline", cmdline); + + /* name + id */ + xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name"); + xenstore_write_str(vm, "uuid", uuid_string); + xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name"); + xenstore_write_int(dom, "domid", xen_domid); + xenstore_write_str(dom, "vm", vm); + + /* memory */ + xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB + xenstore_write_int(vm, "memory", ram_size >> 20); // MB + xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB + + /* cpus */ + for (i = 0; i < smp_cpus; i++) { + snprintf(path, sizeof(path), "cpu/%d/availability",i); + xenstore_write_str(dom, path, "online"); + } + xenstore_write_int(vm, "vcpu_avail", smp_cpus); + xenstore_write_int(vm, "vcpus", smp_cpus); + + /* vnc password */ + xenstore_write_str(vm, "vncpassword", "" /* FIXME */); + + free(dom); + return 0; +} + +int xenstore_domain_init2(int xenstore_port, int xenstore_mfn, + int console_port, int console_mfn) +{ + char *dom; + + dom = xs_get_domain_path(xenstore, xen_domid); + + /* signal new domain */ + xs_introduce_domain(xenstore, + xen_domid, + xenstore_mfn, + xenstore_port); + + /* xenstore */ + xenstore_write_int(dom, "store/ring-ref", xenstore_mfn); + xenstore_write_int(dom, "store/port", xenstore_port); + + /* console */ + xenstore_write_str(dom, "console/type", "ioemu"); + xenstore_write_int(dom, "console/limit", 128 * 1024); + xenstore_write_int(dom, "console/ring-ref", console_mfn); + xenstore_write_int(dom, "console/port", console_port); + xen_config_dev_console(0); + + free(dom); + return 0; +} + +/* ------------------------------------------------------------- */ + +static QEMUTimer *xen_poll; + +/* check domain state once per second */ +static void xen_domain_poll(void *opaque) +{ + struct xc_dominfo info; + int rc; + + rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info); + if ((rc != 1) || (info.domid != xen_domid)) { + qemu_log("xen: domain %d is gone\n", xen_domid); + goto quit; + } + if (info.dying) { + qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid, + info.crashed ? "crashed" : "", + info.shutdown ? "shutdown" : ""); + goto quit; + } + + qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); + return; + +quit: + qemu_system_shutdown_request(); +} + +static int xen_domain_watcher(void) +{ + int qemu_running = 1; + int fd[2], i, n, rc; + char byte; + + if (pipe(fd) != 0) { + qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno)); + return -1; + } + if (fork() != 0) + return 0; /* not child */ + + /* close all file handles, except stdio/out/err, + * our watch pipe and the xen interface handle */ + n = getdtablesize(); + for (i = 3; i < n; i++) { + if (i == fd[0]) + continue; + if (i == xc_fd(xen_xc)) { + continue; + } + close(i); + } + + /* ignore term signals */ + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + + /* wait for qemu exiting */ + while (qemu_running) { + rc = read(fd[0], &byte, 1); + switch (rc) { + case -1: + if (errno == EINTR) + continue; + qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno)); + qemu_running = 0; + break; + case 0: + /* EOF -> qemu exited */ + qemu_running = 0; + break; + default: + qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__); + break; + } + } + + /* cleanup */ + qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid); + xc_domain_destroy(xen_xc, xen_domid); + _exit(0); +} + +/* normal cleanup */ +static void xen_domain_cleanup(void) +{ + char *dom; + + dom = xs_get_domain_path(xenstore, xen_domid); + if (dom) { + xs_rm(xenstore, 0, dom); + free(dom); + } + xs_release_domain(xenstore, xen_domid); +} + +int xen_domain_build_pv(const char *kernel, const char *ramdisk, + const char *cmdline) +{ + uint32_t ssidref = 0; + uint32_t flags = 0; + xen_domain_handle_t uuid; + unsigned int xenstore_port = 0, console_port = 0; + unsigned long xenstore_mfn = 0, console_mfn = 0; + int rc; + + memcpy(uuid, qemu_uuid, sizeof(uuid)); + rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid); + if (rc < 0) { + fprintf(stderr, "xen: xc_domain_create() failed\n"); + goto err; + } + qemu_log("xen: created domain %d\n", xen_domid); + atexit(xen_domain_cleanup); + if (xen_domain_watcher() == -1) { + goto err; + } + + xenstore_domain_init1(kernel, ramdisk, cmdline); + + rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus); + if (rc < 0) { + fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n"); + goto err; + } + +#if 0 + rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256); + if (rc < 0) { + fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n"); + goto err; + } +#endif + + rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10); + if (rc < 0) { + fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n"); + goto err; + } + + xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); + console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); + + rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20, + kernel, ramdisk, cmdline, + 0, flags, + xenstore_port, &xenstore_mfn, + console_port, &console_mfn); + if (rc < 0) { + fprintf(stderr, "xen: xc_linux_build() failed\n"); + goto err; + } + + xenstore_domain_init2(xenstore_port, xenstore_mfn, + console_port, console_mfn); + + qemu_log("xen: unpausing domain %d\n", xen_domid); + rc = xc_domain_unpause(xen_xc, xen_domid); + if (rc < 0) { + fprintf(stderr, "xen: xc_domain_unpause() failed\n"); + goto err; + } + + xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL); + qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); + return 0; + +err: + return -1; +} diff --git a/hw/i386/xen_machine_pv.c b/hw/i386/xen_machine_pv.c new file mode 100644 index 0000000000..a8177b6340 --- /dev/null +++ b/hw/i386/xen_machine_pv.c @@ -0,0 +1,126 @@ +/* + * QEMU Xen PV Machine + * + * Copyright (c) 2007 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/boards.h" +#include "hw/xen_backend.h" +#include "hw/xen_domainbuild.h" +#include "sysemu/blockdev.h" + +static void xen_init_pv(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + X86CPU *cpu; + CPUX86State *env; + DriveInfo *dinfo; + int i; + + /* Initialize a dummy CPU */ + if (cpu_model == NULL) { +#ifdef TARGET_X86_64 + cpu_model = "qemu64"; +#else + cpu_model = "qemu32"; +#endif + } + cpu = cpu_x86_init(cpu_model); + env = &cpu->env; + env->halted = 1; + + /* Initialize backend core & drivers */ + if (xen_be_init() != 0) { + fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); + exit(1); + } + + switch (xen_mode) { + case XEN_ATTACH: + /* nothing to do, xend handles everything */ + break; + case XEN_CREATE: + if (xen_domain_build_pv(kernel_filename, initrd_filename, + kernel_cmdline) < 0) { + fprintf(stderr, "xen pv domain creation failed\n"); + exit(1); + } + break; + case XEN_EMULATE: + fprintf(stderr, "xen emulation not implemented (yet)\n"); + exit(1); + break; + } + + xen_be_register("console", &xen_console_ops); + xen_be_register("vkbd", &xen_kbdmouse_ops); + xen_be_register("vfb", &xen_framebuffer_ops); + xen_be_register("qdisk", &xen_blkdev_ops); + xen_be_register("qnic", &xen_netdev_ops); + + /* configure framebuffer */ + if (xenfb_enabled) { + xen_config_dev_vfb(0, "vnc"); + xen_config_dev_vkbd(0); + } + + /* configure disks */ + for (i = 0; i < 16; i++) { + dinfo = drive_get(IF_XEN, 0, i); + if (!dinfo) + continue; + xen_config_dev_blk(dinfo); + } + + /* configure nics */ + for (i = 0; i < nb_nics; i++) { + if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen")) + continue; + xen_config_dev_nic(nd_table + i); + } + + /* config cleanup hook */ + atexit(xen_config_cleanup); + + /* setup framebuffer */ + xen_init_display(xen_domid); +} + +static QEMUMachine xenpv_machine = { + .name = "xenpv", + .desc = "Xen Para-virtualized PC", + .init = xen_init_pv, + .max_cpus = 1, + .default_machine_opts = "accel=xen", + DEFAULT_MACHINE_OPTIONS, +}; + +static void xenpv_machine_init(void) +{ + qemu_register_machine(&xenpv_machine); +} + +machine_init(xenpv_machine_init); diff --git a/hw/integratorcp.c b/hw/integratorcp.c deleted file mode 100644 index e0ba327a55..0000000000 --- a/hw/integratorcp.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * ARM Integrator CP System emulation. - * - * Copyright (c) 2005-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL - */ - -#include "hw/sysbus.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/arm-misc.h" -#include "net/net.h" -#include "exec/address-spaces.h" -#include "sysemu/sysemu.h" - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t memsz; - MemoryRegion flash; - 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 -}; - -static uint64_t integratorcm_read(void *opaque, hwaddr offset, - unsigned size) -{ - 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. */ - hw_error("integratorcm_read: CM_LMBUSCNT"); - 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. */ - hw_error("integratorcm_read: CM_REFCT"); - 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: - hw_error("integratorcm_read: Unimplemented offset 0x%x\n", - (int)offset); - return 0; - } -} - -static void integratorcm_do_remap(integratorcm_state *s) -{ - /* Sync memory region state with CM_CTRL REMAP bit: - * bit 0 => flash at address 0; bit 1 => RAM - */ - memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4)); -} - -static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) -{ - if (value & 8) { - qemu_system_reset_request(); - } - if ((s->cm_ctrl ^ value) & 1) { - /* (value & 1) != 0 means the green "MISC LED" is lit. - * We don't have any nice place to display LEDs. printf is a bad - * idea because Linux uses the LED as a heartbeat and the output - * will swamp anything else on the terminal. - */ - } - /* Note that the RESET bit [3] always reads as zero */ - s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5); - integratorcm_do_remap(s); -} - -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)) - hw_error("Core module interrupt\n"); -} - -static void integratorcm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - 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: - hw_error("integratorcm_write: Unimplemented offset 0x%x\n", - (int)offset); - break; - } -} - -/* Integrator/CM control registers. */ - -static const MemoryRegionOps integratorcm_ops = { - .read = integratorcm_read, - .write = integratorcm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int integratorcm_init(SysBusDevice *dev) -{ - integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev); - - s->cm_osc = 0x01000048; - /* ??? What should the high bits of this value be? */ - s->cm_auxosc = 0x0007feff; - s->cm_sdram = 0x00011122; - if (s->memsz >= 256) { - integrator_spd[31] = 64; - s->cm_sdram |= 0x10; - } else if (s->memsz >= 128) { - integrator_spd[31] = 32; - s->cm_sdram |= 0x0c; - } else if (s->memsz >= 64) { - integrator_spd[31] = 16; - s->cm_sdram |= 0x08; - } else if (s->memsz >= 32) { - integrator_spd[31] = 4; - s->cm_sdram |= 0x04; - } else { - integrator_spd[31] = 2; - } - memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); - s->cm_init = 0x00000112; - memory_region_init_ram(&s->flash, "integrator.flash", 0x100000); - vmstate_register_ram_global(&s->flash); - - memory_region_init_io(&s->iomem, &integratorcm_ops, s, - "integratorcm", 0x00800000); - sysbus_init_mmio(dev, &s->iomem); - - integratorcm_do_remap(s); - /* ??? Save/restore. */ - return 0; -} - -/* Integrator/CP hardware emulation. */ -/* Primary interrupt controller. */ - -typedef struct icp_pic_state -{ - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t level; - uint32_t irq_enabled; - uint32_t fiq_enabled; - qemu_irq parent_irq; - qemu_irq parent_fiq; -} icp_pic_state; - -static void icp_pic_update(icp_pic_state *s) -{ - uint32_t flags; - - 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); -} - -static void icp_pic_set_irq(void *opaque, int irq, int level) -{ - icp_pic_state *s = (icp_pic_state *)opaque; - if (level) - s->level |= 1 << irq; - else - s->level &= ~(1 << irq); - icp_pic_update(s); -} - -static uint64_t icp_pic_read(void *opaque, hwaddr offset, - unsigned size) -{ - 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: - printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); - return 0; - } -} - -static void icp_pic_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - 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) - icp_pic_set_irq(s, 0, 1); - break; - case 5: /* INT_SOFTCLR */ - if (value & 1) - icp_pic_set_irq(s, 0, 0); - 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: - printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); - return; - } - icp_pic_update(s); -} - -static const MemoryRegionOps icp_pic_ops = { - .read = icp_pic_read, - .write = icp_pic_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int icp_pic_init(SysBusDevice *dev) -{ - icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev); - - qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32); - sysbus_init_irq(dev, &s->parent_irq); - sysbus_init_irq(dev, &s->parent_fiq); - memory_region_init_io(&s->iomem, &icp_pic_ops, s, "icp-pic", 0x00800000); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -/* CP control registers. */ - -static uint64_t icp_control_read(void *opaque, hwaddr offset, - unsigned size) -{ - 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: - hw_error("icp_control_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -static void icp_control_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - switch (offset >> 2) { - case 1: /* CP_FLASHPROG */ - case 2: /* CP_INTREG */ - case 3: /* CP_DECODE */ - /* Nothing interesting implemented yet. */ - break; - default: - hw_error("icp_control_write: Bad offset %x\n", (int)offset); - } -} - -static const MemoryRegionOps icp_control_ops = { - .read = icp_control_read, - .write = icp_control_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void icp_control_init(hwaddr base) -{ - MemoryRegion *io; - - io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion)); - memory_region_init_io(io, &icp_control_ops, NULL, - "control", 0x00800000); - memory_region_add_subregion(get_system_memory(), base, io); - /* ??? Save/restore. */ -} - - -/* Board init. */ - -static struct arm_boot_info integrator_binfo = { - .loader_start = 0x0, - .board_id = 0x113, -}; - -static void integratorcp_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - ARMCPU *cpu; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *ram_alias = g_new(MemoryRegion, 1); - qemu_irq pic[32]; - qemu_irq *cpu_pic; - DeviceState *dev; - int i; - - if (!cpu_model) { - cpu_model = "arm926"; - } - cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - memory_region_init_ram(ram, "integrator.ram", ram_size); - vmstate_register_ram_global(ram); - /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ - /* ??? RAM should repeat to fill physical memory space. */ - /* SDRAM at address zero*/ - memory_region_add_subregion(address_space_mem, 0, ram); - /* And again at address 0x80000000 */ - memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size); - memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias); - - dev = qdev_create(NULL, "integrator_core"); - qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); - qdev_init_nofail(dev); - sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); - - cpu_pic = arm_pic_init_cpu(cpu); - 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++) { - pic[i] = qdev_get_gpio_in(dev, i); - } - sysbus_create_simple("integrator_pic", 0xca000000, pic[26]); - sysbus_create_varargs("integrator_pit", 0x13000000, - pic[5], pic[6], pic[7], NULL); - sysbus_create_simple("pl031", 0x15000000, pic[8]); - sysbus_create_simple("pl011", 0x16000000, pic[1]); - sysbus_create_simple("pl011", 0x17000000, pic[2]); - icp_control_init(0xcb000000); - sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); - sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]); - sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL); - if (nd_table[0].used) - smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); - - sysbus_create_simple("pl110", 0xc0000000, pic[22]); - - 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(cpu, &integrator_binfo); -} - -static QEMUMachine integratorcp_machine = { - .name = "integratorcp", - .desc = "ARM Integrator/CP (ARM926EJ-S)", - .init = integratorcp_init, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void integratorcp_machine_init(void) -{ - qemu_register_machine(&integratorcp_machine); -} - -machine_init(integratorcp_machine_init); - -static Property core_properties[] = { - DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void core_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = integratorcm_init; - dc->props = core_properties; -} - -static const TypeInfo core_info = { - .name = "integrator_core", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(integratorcm_state), - .class_init = core_class_init, -}; - -static void icp_pic_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = icp_pic_init; -} - -static const TypeInfo icp_pic_info = { - .name = "integrator_pic", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(icp_pic_state), - .class_init = icp_pic_class_init, -}; - -static void integratorcp_register_types(void) -{ - type_register_static(&icp_pic_info); - type_register_static(&core_info); -} - -type_init(integratorcp_register_types) diff --git a/hw/kzm.c b/hw/kzm.c deleted file mode 100644 index ec50a319ac..0000000000 --- a/hw/kzm.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * KZM Board System emulation. - * - * Copyright (c) 2008 OKL and 2011 NICTA - * Written by Hans at OK-Labs - * Updated by Peter Chubb. - * - * This code is licensed under the GPL, version 2 or later. - * See the file `COPYING' in the top level directory. - * - * It (partially) emulates a Kyoto Microcomputer - * KZM-ARM11-01 evaluation board, with a Freescale - * i.MX31 SoC - */ - -#include "hw/sysbus.h" -#include "exec/address-spaces.h" -#include "hw/hw.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/serial.h" -#include "hw/imx.h" - - /* Memory map for Kzm Emulation Baseboard: - * 0x00000000-0x00003fff 16k secure ROM IGNORED - * 0x00004000-0x00407fff Reserved IGNORED - * 0x00404000-0x00407fff ROM IGNORED - * 0x00408000-0x0fffffff Reserved IGNORED - * 0x10000000-0x1fffbfff RAM aliasing IGNORED - * 0x1fffc000-0x1fffffff RAM EMULATED - * 0x20000000-0x2fffffff Reserved IGNORED - * 0x30000000-0x7fffffff I.MX31 Internal Register Space - * 0x43f00000 IO_AREA0 - * 0x43f90000 UART1 EMULATED - * 0x43f94000 UART2 EMULATED - * 0x68000000 AVIC EMULATED - * 0x53f80000 CCM EMULATED - * 0x53f94000 PIT 1 EMULATED - * 0x53f98000 PIT 2 EMULATED - * 0x53f90000 GPT EMULATED - * 0x80000000-0x87ffffff RAM EMULATED - * 0x88000000-0x8fffffff RAM Aliasing EMULATED - * 0xa0000000-0xafffffff NAND Flash IGNORED - * 0xb0000000-0xb3ffffff Unavailable IGNORED - * 0xb4000000-0xb4000fff 8-bit free space IGNORED - * 0xb4001000-0xb400100f Board control IGNORED - * 0xb4001003 DIP switch - * 0xb4001010-0xb400101f 7-segment LED IGNORED - * 0xb4001020-0xb400102f LED IGNORED - * 0xb4001030-0xb400103f LED IGNORED - * 0xb4001040-0xb400104f FPGA, UART EMULATED - * 0xb4001050-0xb400105f FPGA, UART EMULATED - * 0xb4001060-0xb40fffff FPGA IGNORED - * 0xb6000000-0xb61fffff LAN controller EMULATED - * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED - * 0xb6300000-0xb7ffffff Free IGNORED - * 0xb8000000-0xb8004fff Memory control registers IGNORED - * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED - * 0xc4000000-0xffffffff Reserved IGNORED - */ - -#define KZM_RAMADDRESS (0x80000000) -#define KZM_FPGA (0xb4001040) - -static struct arm_boot_info kzm_binfo = { - .loader_start = KZM_RAMADDRESS, - .board_id = 1722, -}; - -static void kzm_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - ARMCPU *cpu; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - MemoryRegion *ram_alias = g_new(MemoryRegion, 1); - qemu_irq *cpu_pic; - DeviceState *dev; - DeviceState *ccm; - - if (!cpu_model) { - cpu_model = "arm1136"; - } - - cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - /* On a real system, the first 16k is a `secure boot rom' */ - - memory_region_init_ram(ram, "kzm.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram); - - memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size); - memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias); - - memory_region_init_ram(sram, "kzm.sram", 0x4000); - memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram); - - cpu_pic = arm_pic_init_cpu(cpu); - dev = sysbus_create_varargs("imx_avic", 0x68000000, - cpu_pic[ARM_PIC_CPU_IRQ], - cpu_pic[ARM_PIC_CPU_FIQ], NULL); - - - imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45)); - imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32)); - - ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL); - - imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm); - imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm); - imx_timerg_create(0x53f90000, qdev_get_gpio_in(dev, 29), ccm); - - if (nd_table[0].used) { - lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 52)); - } - - if (serial_hds[2]) { /* touchscreen */ - serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0, - qdev_get_gpio_in(dev, 52), - 14745600, serial_hds[2], - DEVICE_NATIVE_ENDIAN); - } - - kzm_binfo.ram_size = ram_size; - kzm_binfo.kernel_filename = kernel_filename; - kzm_binfo.kernel_cmdline = kernel_cmdline; - kzm_binfo.initrd_filename = initrd_filename; - kzm_binfo.nb_cpus = 1; - arm_load_kernel(cpu, &kzm_binfo); -} - -static QEMUMachine kzm_machine = { - .name = "kzm", - .desc = "ARM KZM Emulation Baseboard (ARM1136)", - .init = kzm_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void kzm_machine_init(void) -{ - qemu_register_machine(&kzm_machine); -} - -machine_init(kzm_machine_init) diff --git a/hw/leon3.c b/hw/leon3.c deleted file mode 100644 index f58061f8ed..0000000000 --- a/hw/leon3.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * QEMU Leon3 System Emulator - * - * Copyright (c) 2010-2011 AdaCore - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "char/char.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "trace.h" -#include "exec/address-spaces.h" - -#include "hw/grlib.h" - -/* Default system clock. */ -#define CPU_CLK (40 * 1000 * 1000) - -#define PROM_FILENAME "u-boot.bin" - -#define MAX_PILS 16 - -typedef struct ResetData { - SPARCCPU *cpu; - uint32_t entry; /* save kernel entry in case of reset */ -} ResetData; - -static void main_cpu_reset(void *opaque) -{ - ResetData *s = (ResetData *)opaque; - CPUSPARCState *env = &s->cpu->env; - - cpu_reset(CPU(s->cpu)); - - env->halted = 0; - env->pc = s->entry; - env->npc = s->entry + 4; -} - -void leon3_irq_ack(void *irq_manager, int intno) -{ - grlib_irqmp_ack((DeviceState *)irq_manager, intno); -} - -static void leon3_set_pil_in(void *opaque, uint32_t pil_in) -{ - CPUSPARCState *env = (CPUSPARCState *)opaque; - - assert(env != NULL); - - env->pil_in = pil_in; - - if (env->pil_in && (env->interrupt_index == 0 || - (env->interrupt_index & ~15) == TT_EXTINT)) { - unsigned int i; - - for (i = 15; i > 0; i--) { - if (env->pil_in & (1 << i)) { - int old_interrupt = env->interrupt_index; - - env->interrupt_index = TT_EXTINT | i; - if (old_interrupt != env->interrupt_index) { - trace_leon3_set_irq(i); - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - break; - } - } - } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { - trace_leon3_reset_irq(env->interrupt_index & 15); - env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -static void leon3_generic_hw_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - SPARCCPU *cpu; - CPUSPARCState *env; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *prom = g_new(MemoryRegion, 1); - int ret; - char *filename; - qemu_irq *cpu_irqs = NULL; - int bios_size; - int prom_size; - ResetData *reset_info; - - /* Init CPU */ - if (!cpu_model) { - cpu_model = "LEON3"; - } - - cpu = cpu_sparc_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); - exit(1); - } - env = &cpu->env; - - cpu_sparc_set_id(env, 0); - - /* Reset data */ - reset_info = g_malloc0(sizeof(ResetData)); - reset_info->cpu = cpu; - qemu_register_reset(main_cpu_reset, reset_info); - - /* Allocate IRQ manager */ - grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in); - - env->qemu_irq_ack = leon3_irq_manager; - - /* Allocate RAM */ - if ((uint64_t)ram_size > (1UL << 30)) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d, maximum 1G\n", - (unsigned int)(ram_size / (1024 * 1024))); - exit(1); - } - - memory_region_init_ram(ram, "leon3.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space_mem, 0x40000000, ram); - - /* Allocate BIOS */ - prom_size = 8 * 1024 * 1024; /* 8Mb */ - memory_region_init_ram(prom, "Leon3.bios", prom_size); - vmstate_register_ram_global(prom); - memory_region_set_readonly(prom, true); - memory_region_add_subregion(address_space_mem, 0x00000000, prom); - - /* Load boot prom */ - if (bios_name == NULL) { - bios_name = PROM_FILENAME; - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - - bios_size = get_image_size(filename); - - if (bios_size > prom_size) { - fprintf(stderr, "qemu: could not load prom '%s': file too big\n", - filename); - exit(1); - } - - if (bios_size > 0) { - ret = load_image_targphys(filename, 0x00000000, bios_size); - if (ret < 0 || ret > prom_size) { - fprintf(stderr, "qemu: could not load prom '%s'\n", filename); - exit(1); - } - } else if (kernel_filename == NULL) { - fprintf(stderr, "Can't read bios image %s\n", filename); - exit(1); - } - - /* Can directly load an application. */ - if (kernel_filename != NULL) { - long kernel_size; - uint64_t entry; - - kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, - 1 /* big endian */, ELF_MACHINE, 0); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - if (bios_size <= 0) { - /* If there is no bios/monitor, start the application. */ - env->pc = entry; - env->npc = entry + 4; - reset_info->entry = entry; - } - } - - /* Allocate timers */ - grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6); - - /* Allocate uart */ - if (serial_hds[0]) { - grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]); - } -} - -static QEMUMachine leon3_generic_machine = { - .name = "leon3_generic", - .desc = "Leon-3 generic", - .init = leon3_generic_hw_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void leon3_machine_init(void) -{ - qemu_register_machine(&leon3_generic_machine); -} - -machine_init(leon3_machine_init); diff --git a/hw/lm32/Makefile.objs b/hw/lm32/Makefile.objs index 4e1843c11d..4592fe5fc8 100644 --- a/hw/lm32/Makefile.objs +++ b/hw/lm32/Makefile.objs @@ -1,7 +1,3 @@ -# LM32 boards -obj-y += lm32_boards.o -obj-y += milkymist.o - # LM32 peripherals obj-y += lm32_pic.o obj-y += lm32_juart.o @@ -21,3 +17,7 @@ obj-y += milkymist-vgafb.o obj-y += framebuffer.o obj-y := $(addprefix ../,$(obj-y)) + +# LM32 boards +obj-y += lm32_boards.o +obj-y += milkymist.o diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c new file mode 100644 index 0000000000..1ce466a1b1 --- /dev/null +++ b/hw/lm32/lm32_boards.c @@ -0,0 +1,308 @@ +/* + * QEMU models for LatticeMico32 uclinux and evr32 boards. + * + * Copyright (c) 2010 Michael Walle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "sysemu/blockdev.h" +#include "elf.h" +#include "hw/lm32_hwsetup.h" +#include "hw/lm32.h" +#include "exec/address-spaces.h" + +typedef struct { + LM32CPU *cpu; + hwaddr bootstrap_pc; + hwaddr flash_base; + hwaddr hwsetup_base; + hwaddr initrd_base; + size_t initrd_size; + hwaddr cmdline_base; +} ResetInfo; + +static void cpu_irq_handler(void *opaque, int irq, int level) +{ + CPULM32State *env = opaque; + + if (level) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void main_cpu_reset(void *opaque) +{ + ResetInfo *reset_info = opaque; + CPULM32State *env = &reset_info->cpu->env; + + cpu_reset(CPU(reset_info->cpu)); + + /* init defaults */ + env->pc = (uint32_t)reset_info->bootstrap_pc; + env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base; + env->regs[R_R2] = (uint32_t)reset_info->cmdline_base; + env->regs[R_R3] = (uint32_t)reset_info->initrd_base; + env->regs[R_R4] = (uint32_t)(reset_info->initrd_base + + reset_info->initrd_size); + env->eba = reset_info->flash_base; + env->deba = reset_info->flash_base; +} + +static void lm32_evr_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + LM32CPU *cpu; + CPULM32State *env; + DriveInfo *dinfo; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *phys_ram = g_new(MemoryRegion, 1); + qemu_irq *cpu_irq, irq[32]; + ResetInfo *reset_info; + int i; + + /* memory map */ + hwaddr flash_base = 0x04000000; + size_t flash_sector_size = 256 * 1024; + size_t flash_size = 32 * 1024 * 1024; + hwaddr ram_base = 0x08000000; + size_t ram_size = 64 * 1024 * 1024; + hwaddr timer0_base = 0x80002000; + hwaddr uart0_base = 0x80006000; + hwaddr timer1_base = 0x8000a000; + int uart0_irq = 0; + int timer0_irq = 1; + int timer1_irq = 3; + + reset_info = g_malloc0(sizeof(ResetInfo)); + + if (cpu_model == NULL) { + cpu_model = "lm32-full"; + } + cpu = cpu_lm32_init(cpu_model); + env = &cpu->env; + reset_info->cpu = cpu; + + reset_info->flash_base = flash_base; + + memory_region_init_ram(phys_ram, "lm32_evr.sdram", ram_size); + vmstate_register_ram_global(phys_ram); + memory_region_add_subregion(address_space_mem, ram_base, phys_ram); + + dinfo = drive_get(IF_PFLASH, 0, 0); + /* Spansion S29NS128P */ + pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size, + dinfo ? dinfo->bdrv : NULL, flash_sector_size, + flash_size / flash_sector_size, 1, 2, + 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); + + /* create irq lines */ + cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); + env->pic_state = lm32_pic_init(*cpu_irq); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(env->pic_state, i); + } + + sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); + sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); + sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); + + /* make sure juart isn't the first chardev */ + env->juart_state = lm32_juart_init(); + + reset_info->bootstrap_pc = flash_base; + + if (kernel_filename) { + uint64_t entry; + int kernel_size; + + kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, + 1, ELF_MACHINE, 0); + reset_info->bootstrap_pc = entry; + + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, ram_base, + ram_size); + reset_info->bootstrap_pc = ram_base; + } + + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + qemu_register_reset(main_cpu_reset, reset_info); +} + +static void lm32_uclinux_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + LM32CPU *cpu; + CPULM32State *env; + DriveInfo *dinfo; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *phys_ram = g_new(MemoryRegion, 1); + qemu_irq *cpu_irq, irq[32]; + HWSetup *hw; + ResetInfo *reset_info; + int i; + + /* memory map */ + hwaddr flash_base = 0x04000000; + size_t flash_sector_size = 256 * 1024; + size_t flash_size = 32 * 1024 * 1024; + hwaddr ram_base = 0x08000000; + size_t ram_size = 64 * 1024 * 1024; + hwaddr uart0_base = 0x80000000; + hwaddr timer0_base = 0x80002000; + hwaddr timer1_base = 0x80010000; + hwaddr timer2_base = 0x80012000; + int uart0_irq = 0; + int timer0_irq = 1; + int timer1_irq = 20; + int timer2_irq = 21; + hwaddr hwsetup_base = 0x0bffe000; + hwaddr cmdline_base = 0x0bfff000; + hwaddr initrd_base = 0x08400000; + size_t initrd_max = 0x01000000; + + reset_info = g_malloc0(sizeof(ResetInfo)); + + if (cpu_model == NULL) { + cpu_model = "lm32-full"; + } + cpu = cpu_lm32_init(cpu_model); + env = &cpu->env; + reset_info->cpu = cpu; + + reset_info->flash_base = flash_base; + + memory_region_init_ram(phys_ram, "lm32_uclinux.sdram", ram_size); + vmstate_register_ram_global(phys_ram); + memory_region_add_subregion(address_space_mem, ram_base, phys_ram); + + dinfo = drive_get(IF_PFLASH, 0, 0); + /* Spansion S29NS128P */ + pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size, + dinfo ? dinfo->bdrv : NULL, flash_sector_size, + flash_size / flash_sector_size, 1, 2, + 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); + + /* create irq lines */ + cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); + env->pic_state = lm32_pic_init(*cpu_irq); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(env->pic_state, i); + } + + sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); + sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); + sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); + sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]); + + /* make sure juart isn't the first chardev */ + env->juart_state = lm32_juart_init(); + + reset_info->bootstrap_pc = flash_base; + + if (kernel_filename) { + uint64_t entry; + int kernel_size; + + kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, + 1, ELF_MACHINE, 0); + reset_info->bootstrap_pc = entry; + + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, ram_base, + ram_size); + reset_info->bootstrap_pc = ram_base; + } + + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + /* generate a rom with the hardware description */ + hw = hwsetup_init(); + hwsetup_add_cpu(hw, "LM32", 75000000); + hwsetup_add_flash(hw, "flash", flash_base, flash_size); + hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size); + hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq); + hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq); + hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq); + hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq); + hwsetup_add_trailer(hw); + hwsetup_create_rom(hw, hwsetup_base); + hwsetup_free(hw); + + reset_info->hwsetup_base = hwsetup_base; + + if (kernel_cmdline && strlen(kernel_cmdline)) { + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, + kernel_cmdline); + reset_info->cmdline_base = cmdline_base; + } + + if (initrd_filename) { + size_t initrd_size; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + initrd_max); + reset_info->initrd_base = initrd_base; + reset_info->initrd_size = initrd_size; + } + + qemu_register_reset(main_cpu_reset, reset_info); +} + +static QEMUMachine lm32_evr_machine = { + .name = "lm32-evr", + .desc = "LatticeMico32 EVR32 eval system", + .init = lm32_evr_init, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine lm32_uclinux_machine = { + .name = "lm32-uclinux", + .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems", + .init = lm32_uclinux_init, + .is_default = 0, + DEFAULT_MACHINE_OPTIONS, +}; + +static void lm32_machine_init(void) +{ + qemu_register_machine(&lm32_uclinux_machine); + qemu_register_machine(&lm32_evr_machine); +} + +machine_init(lm32_machine_init); diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c new file mode 100644 index 0000000000..fd36de57b5 --- /dev/null +++ b/hw/lm32/milkymist.c @@ -0,0 +1,218 @@ +/* + * QEMU model for the Milkymist board. + * + * Copyright (c) 2010 Michael Walle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "sysemu/sysemu.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "sysemu/blockdev.h" +#include "hw/milkymist-hw.h" +#include "hw/lm32.h" +#include "exec/address-spaces.h" + +#define BIOS_FILENAME "mmone-bios.bin" +#define BIOS_OFFSET 0x00860000 +#define BIOS_SIZE (512*1024) +#define KERNEL_LOAD_ADDR 0x40000000 + +typedef struct { + LM32CPU *cpu; + hwaddr bootstrap_pc; + hwaddr flash_base; + hwaddr initrd_base; + size_t initrd_size; + hwaddr cmdline_base; +} ResetInfo; + +static void cpu_irq_handler(void *opaque, int irq, int level) +{ + CPULM32State *env = opaque; + + if (level) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void main_cpu_reset(void *opaque) +{ + ResetInfo *reset_info = opaque; + CPULM32State *env = &reset_info->cpu->env; + + cpu_reset(CPU(reset_info->cpu)); + + /* init defaults */ + env->pc = reset_info->bootstrap_pc; + env->regs[R_R1] = reset_info->cmdline_base; + env->regs[R_R2] = reset_info->initrd_base; + env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size; + env->eba = reset_info->flash_base; + env->deba = reset_info->flash_base; +} + +static void +milkymist_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + LM32CPU *cpu; + CPULM32State *env; + int kernel_size; + DriveInfo *dinfo; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *phys_sdram = g_new(MemoryRegion, 1); + qemu_irq irq[32], *cpu_irq; + int i; + char *bios_filename; + ResetInfo *reset_info; + + /* memory map */ + hwaddr flash_base = 0x00000000; + size_t flash_sector_size = 128 * 1024; + size_t flash_size = 32 * 1024 * 1024; + hwaddr sdram_base = 0x40000000; + size_t sdram_size = 128 * 1024 * 1024; + + hwaddr initrd_base = sdram_base + 0x1002000; + hwaddr cmdline_base = sdram_base + 0x1000000; + size_t initrd_max = sdram_size - 0x1002000; + + reset_info = g_malloc0(sizeof(ResetInfo)); + + if (cpu_model == NULL) { + cpu_model = "lm32-full"; + } + cpu = cpu_lm32_init(cpu_model); + env = &cpu->env; + reset_info->cpu = cpu; + + cpu_lm32_set_phys_msb_ignore(env, 1); + + memory_region_init_ram(phys_sdram, "milkymist.sdram", sdram_size); + vmstate_register_ram_global(phys_sdram); + memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram); + + dinfo = drive_get(IF_PFLASH, 0, 0); + /* Numonyx JS28F256J3F105 */ + pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size, + dinfo ? dinfo->bdrv : NULL, flash_sector_size, + flash_size / flash_sector_size, 2, + 0x00, 0x89, 0x00, 0x1d, 1); + + /* create irq lines */ + cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); + env->pic_state = lm32_pic_init(*cpu_irq); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(env->pic_state, i); + } + + /* load bios rom */ + if (bios_name == NULL) { + bios_name = BIOS_FILENAME; + } + bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + + if (bios_filename) { + load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE); + } + + reset_info->bootstrap_pc = BIOS_OFFSET; + + /* if no kernel is given no valid bios rom is a fatal error */ + if (!kernel_filename && !dinfo && !bios_filename) { + fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n", + bios_name); + exit(1); + } + + milkymist_uart_create(0x60000000, irq[0]); + milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3], + 80000000, 0x10014d31, 0x0000041f, 0x00000001); + milkymist_hpdmc_create(0x60002000); + milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff); + milkymist_memcard_create(0x60004000); + milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]); + milkymist_pfpu_create(0x60006000, irq[8]); + milkymist_tmu2_create(0x60007000, irq[9]); + milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]); + milkymist_softusb_create(0x6000f000, irq[15], + 0x20000000, 0x1000, 0x20020000, 0x2000); + + /* make sure juart isn't the first chardev */ + env->juart_state = lm32_juart_init(); + + if (kernel_filename) { + uint64_t entry; + + /* Boots a kernel elf binary. */ + kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, + 1, ELF_MACHINE, 0); + reset_info->bootstrap_pc = entry; + + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, sdram_base, + sdram_size); + reset_info->bootstrap_pc = sdram_base; + } + + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + if (kernel_cmdline && strlen(kernel_cmdline)) { + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, + kernel_cmdline); + reset_info->cmdline_base = (uint32_t)cmdline_base; + } + + if (initrd_filename) { + size_t initrd_size; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + initrd_max); + reset_info->initrd_base = (uint32_t)initrd_base; + reset_info->initrd_size = (uint32_t)initrd_size; + } + + qemu_register_reset(main_cpu_reset, reset_info); +} + +static QEMUMachine milkymist_machine = { + .name = "milkymist", + .desc = "Milkymist One", + .init = milkymist_init, + .is_default = 0, + DEFAULT_MACHINE_OPTIONS, +}; + +static void milkymist_machine_init(void) +{ + qemu_register_machine(&milkymist_machine); +} + +machine_init(milkymist_machine_init); diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c deleted file mode 100644 index 1ce466a1b1..0000000000 --- a/hw/lm32_boards.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * QEMU models for LatticeMico32 uclinux and evr32 boards. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "hw/flash.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "sysemu/blockdev.h" -#include "elf.h" -#include "hw/lm32_hwsetup.h" -#include "hw/lm32.h" -#include "exec/address-spaces.h" - -typedef struct { - LM32CPU *cpu; - hwaddr bootstrap_pc; - hwaddr flash_base; - hwaddr hwsetup_base; - hwaddr initrd_base; - size_t initrd_size; - hwaddr cmdline_base; -} ResetInfo; - -static void cpu_irq_handler(void *opaque, int irq, int level) -{ - CPULM32State *env = opaque; - - if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -static void main_cpu_reset(void *opaque) -{ - ResetInfo *reset_info = opaque; - CPULM32State *env = &reset_info->cpu->env; - - cpu_reset(CPU(reset_info->cpu)); - - /* init defaults */ - env->pc = (uint32_t)reset_info->bootstrap_pc; - env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base; - env->regs[R_R2] = (uint32_t)reset_info->cmdline_base; - env->regs[R_R3] = (uint32_t)reset_info->initrd_base; - env->regs[R_R4] = (uint32_t)(reset_info->initrd_base + - reset_info->initrd_size); - env->eba = reset_info->flash_base; - env->deba = reset_info->flash_base; -} - -static void lm32_evr_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - LM32CPU *cpu; - CPULM32State *env; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *phys_ram = g_new(MemoryRegion, 1); - qemu_irq *cpu_irq, irq[32]; - ResetInfo *reset_info; - int i; - - /* memory map */ - hwaddr flash_base = 0x04000000; - size_t flash_sector_size = 256 * 1024; - size_t flash_size = 32 * 1024 * 1024; - hwaddr ram_base = 0x08000000; - size_t ram_size = 64 * 1024 * 1024; - hwaddr timer0_base = 0x80002000; - hwaddr uart0_base = 0x80006000; - hwaddr timer1_base = 0x8000a000; - int uart0_irq = 0; - int timer0_irq = 1; - int timer1_irq = 3; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - if (cpu_model == NULL) { - cpu_model = "lm32-full"; - } - cpu = cpu_lm32_init(cpu_model); - env = &cpu->env; - reset_info->cpu = cpu; - - reset_info->flash_base = flash_base; - - memory_region_init_ram(phys_ram, "lm32_evr.sdram", ram_size); - vmstate_register_ram_global(phys_ram); - memory_region_add_subregion(address_space_mem, ram_base, phys_ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Spansion S29NS128P */ - pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size, - dinfo ? dinfo->bdrv : NULL, flash_sector_size, - flash_size / flash_sector_size, 1, 2, - 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); - - /* create irq lines */ - cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); - env->pic_state = lm32_pic_init(*cpu_irq); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); - sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); - sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(); - - reset_info->bootstrap_pc = flash_base; - - if (kernel_filename) { - uint64_t entry; - int kernel_size; - - kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, - 1, ELF_MACHINE, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, ram_base, - ram_size); - reset_info->bootstrap_pc = ram_base; - } - - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static void lm32_uclinux_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - LM32CPU *cpu; - CPULM32State *env; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *phys_ram = g_new(MemoryRegion, 1); - qemu_irq *cpu_irq, irq[32]; - HWSetup *hw; - ResetInfo *reset_info; - int i; - - /* memory map */ - hwaddr flash_base = 0x04000000; - size_t flash_sector_size = 256 * 1024; - size_t flash_size = 32 * 1024 * 1024; - hwaddr ram_base = 0x08000000; - size_t ram_size = 64 * 1024 * 1024; - hwaddr uart0_base = 0x80000000; - hwaddr timer0_base = 0x80002000; - hwaddr timer1_base = 0x80010000; - hwaddr timer2_base = 0x80012000; - int uart0_irq = 0; - int timer0_irq = 1; - int timer1_irq = 20; - int timer2_irq = 21; - hwaddr hwsetup_base = 0x0bffe000; - hwaddr cmdline_base = 0x0bfff000; - hwaddr initrd_base = 0x08400000; - size_t initrd_max = 0x01000000; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - if (cpu_model == NULL) { - cpu_model = "lm32-full"; - } - cpu = cpu_lm32_init(cpu_model); - env = &cpu->env; - reset_info->cpu = cpu; - - reset_info->flash_base = flash_base; - - memory_region_init_ram(phys_ram, "lm32_uclinux.sdram", ram_size); - vmstate_register_ram_global(phys_ram); - memory_region_add_subregion(address_space_mem, ram_base, phys_ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Spansion S29NS128P */ - pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size, - dinfo ? dinfo->bdrv : NULL, flash_sector_size, - flash_size / flash_sector_size, 1, 2, - 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); - - /* create irq lines */ - cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); - env->pic_state = lm32_pic_init(*cpu_irq); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); - sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); - sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); - sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(); - - reset_info->bootstrap_pc = flash_base; - - if (kernel_filename) { - uint64_t entry; - int kernel_size; - - kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, - 1, ELF_MACHINE, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, ram_base, - ram_size); - reset_info->bootstrap_pc = ram_base; - } - - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - } - - /* generate a rom with the hardware description */ - hw = hwsetup_init(); - hwsetup_add_cpu(hw, "LM32", 75000000); - hwsetup_add_flash(hw, "flash", flash_base, flash_size); - hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size); - hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq); - hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq); - hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq); - hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq); - hwsetup_add_trailer(hw); - hwsetup_create_rom(hw, hwsetup_base); - hwsetup_free(hw); - - reset_info->hwsetup_base = hwsetup_base; - - if (kernel_cmdline && strlen(kernel_cmdline)) { - pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, - kernel_cmdline); - reset_info->cmdline_base = cmdline_base; - } - - if (initrd_filename) { - size_t initrd_size; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - initrd_max); - reset_info->initrd_base = initrd_base; - reset_info->initrd_size = initrd_size; - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static QEMUMachine lm32_evr_machine = { - .name = "lm32-evr", - .desc = "LatticeMico32 EVR32 eval system", - .init = lm32_evr_init, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine lm32_uclinux_machine = { - .name = "lm32-uclinux", - .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems", - .init = lm32_uclinux_init, - .is_default = 0, - DEFAULT_MACHINE_OPTIONS, -}; - -static void lm32_machine_init(void) -{ - qemu_register_machine(&lm32_uclinux_machine); - qemu_register_machine(&lm32_evr_machine); -} - -machine_init(lm32_machine_init); diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs index 93b6d25baf..7c033a886c 100644 --- a/hw/m68k/Makefile.objs +++ b/hw/m68k/Makefile.objs @@ -1,4 +1,7 @@ -obj-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o -obj-y += dummy_m68k.o +obj-y = mcf5206.o mcf_uart.o mcf_intc.o mcf_fec.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += an5206.o mcf5208.o +obj-y += dummy_m68k.o + diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c new file mode 100644 index 0000000000..7c21c66cde --- /dev/null +++ b/hw/m68k/an5206.c @@ -0,0 +1,100 @@ +/* + * Arnewsh 5206 ColdFire system emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ + +#include "hw/hw.h" +#include "hw/mcf.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "exec/address-spaces.h" + +#define KERNEL_LOAD_ADDR 0x10000 +#define AN5206_MBAR_ADDR 0x10000000 +#define AN5206_RAMBAR_ADDR 0x20000000 + +/* Board init. */ + +static void an5206_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + M68kCPU *cpu; + CPUM68KState *env; + int kernel_size; + uint64_t elf_entry; + hwaddr entry; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); + + if (!cpu_model) { + cpu_model = "m5206"; + } + cpu = cpu_m68k_init(cpu_model); + if (!cpu) { + hw_error("Unable to find m68k CPU definition\n"); + } + env = &cpu->env; + + /* Initialize CPU registers. */ + env->vbr = 0; + /* TODO: allow changing MBAR and RAMBAR. */ + env->mbar = AN5206_MBAR_ADDR | 1; + env->rambar0 = AN5206_RAMBAR_ADDR | 1; + + /* DRAM at address zero */ + memory_region_init_ram(ram, "an5206.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, 0, ram); + + /* Internal SRAM. */ + memory_region_init_ram(sram, "an5206.sram", 512); + vmstate_register_ram_global(sram); + memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram); + + mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, cpu); + + /* Load kernel. */ + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + + kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, + NULL, NULL, 1, ELF_MACHINE, 0); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); + entry = KERNEL_LOAD_ADDR; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + env->pc = entry; +} + +static QEMUMachine an5206_machine = { + .name = "an5206", + .desc = "Arnewsh 5206", + .init = an5206_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void an5206_machine_init(void) +{ + qemu_register_machine(&an5206_machine); +} + +machine_init(an5206_machine_init); diff --git a/hw/m68k/dummy_m68k.c b/hw/m68k/dummy_m68k.c new file mode 100644 index 0000000000..544d56b59d --- /dev/null +++ b/hw/m68k/dummy_m68k.c @@ -0,0 +1,84 @@ +/* + * Dummy board with just RAM and CPU for use as an ISS. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ + +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "exec/address-spaces.h" + +#define KERNEL_LOAD_ADDR 0x10000 + +/* Board init. */ + +static void dummy_m68k_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + CPUM68KState *env; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + int kernel_size; + uint64_t elf_entry; + hwaddr entry; + + if (!cpu_model) + cpu_model = "cfv4e"; + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find m68k CPU definition\n"); + exit(1); + } + + /* Initialize CPU registers. */ + env->vbr = 0; + + /* RAM at address zero */ + memory_region_init_ram(ram, "dummy_m68k.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, 0, ram); + + /* Load kernel. */ + if (kernel_filename) { + kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, + NULL, NULL, 1, ELF_MACHINE, 0); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); + entry = KERNEL_LOAD_ADDR; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } else { + entry = 0; + } + env->pc = entry; +} + +static QEMUMachine dummy_m68k_machine = { + .name = "dummy", + .desc = "Dummy board", + .init = dummy_m68k_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void dummy_m68k_machine_init(void) +{ + qemu_register_machine(&dummy_m68k_machine); +} + +machine_init(dummy_m68k_machine_init); diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c new file mode 100644 index 0000000000..748bf56983 --- /dev/null +++ b/hw/m68k/mcf5208.c @@ -0,0 +1,306 @@ +/* + * Motorola ColdFire MCF5208 SoC emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ +#include "hw/hw.h" +#include "hw/mcf.h" +#include "qemu/timer.h" +#include "hw/ptimer.h" +#include "sysemu/sysemu.h" +#include "net/net.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "exec/address-spaces.h" + +#define SYS_FREQ 66000000 + +#define PCSR_EN 0x0001 +#define PCSR_RLD 0x0002 +#define PCSR_PIF 0x0004 +#define PCSR_PIE 0x0008 +#define PCSR_OVW 0x0010 +#define PCSR_DBG 0x0020 +#define PCSR_DOZE 0x0040 +#define PCSR_PRE_SHIFT 8 +#define PCSR_PRE_MASK 0x0f00 + +typedef struct { + MemoryRegion iomem; + qemu_irq irq; + ptimer_state *timer; + uint16_t pcsr; + uint16_t pmr; + uint16_t pcntr; +} m5208_timer_state; + +static void m5208_timer_update(m5208_timer_state *s) +{ + if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF)) + qemu_irq_raise(s->irq); + else + qemu_irq_lower(s->irq); +} + +static void m5208_timer_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + m5208_timer_state *s = (m5208_timer_state *)opaque; + int prescale; + int limit; + switch (offset) { + case 0: + /* The PIF bit is set-to-clear. */ + if (value & PCSR_PIF) { + s->pcsr &= ~PCSR_PIF; + value &= ~PCSR_PIF; + } + /* Avoid frobbing the timer if we're just twiddling IRQ bits. */ + if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) { + s->pcsr = value; + m5208_timer_update(s); + return; + } + + if (s->pcsr & PCSR_EN) + ptimer_stop(s->timer); + + s->pcsr = value; + + prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT); + ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale); + if (s->pcsr & PCSR_RLD) + limit = s->pmr; + else + limit = 0xffff; + ptimer_set_limit(s->timer, limit, 0); + + if (s->pcsr & PCSR_EN) + ptimer_run(s->timer, 0); + break; + case 2: + s->pmr = value; + s->pcsr &= ~PCSR_PIF; + if ((s->pcsr & PCSR_RLD) == 0) { + if (s->pcsr & PCSR_OVW) + ptimer_set_count(s->timer, value); + } else { + ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW); + } + break; + case 4: + break; + default: + hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset); + break; + } + m5208_timer_update(s); +} + +static void m5208_timer_trigger(void *opaque) +{ + m5208_timer_state *s = (m5208_timer_state *)opaque; + s->pcsr |= PCSR_PIF; + m5208_timer_update(s); +} + +static uint64_t m5208_timer_read(void *opaque, hwaddr addr, + unsigned size) +{ + m5208_timer_state *s = (m5208_timer_state *)opaque; + switch (addr) { + case 0: + return s->pcsr; + case 2: + return s->pmr; + case 4: + return ptimer_get_count(s->timer); + default: + hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr); + return 0; + } +} + +static const MemoryRegionOps m5208_timer_ops = { + .read = m5208_timer_read, + .write = m5208_timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static uint64_t m5208_sys_read(void *opaque, hwaddr addr, + unsigned size) +{ + switch (addr) { + case 0x110: /* SDCS0 */ + { + int n; + for (n = 0; n < 32; n++) { + if (ram_size < (2u << n)) + break; + } + return (n - 1) | 0x40000000; + } + case 0x114: /* SDCS1 */ + return 0; + + default: + hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr); + return 0; + } +} + +static void m5208_sys_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr); +} + +static const MemoryRegionOps m5208_sys_ops = { + .read = m5208_sys_read, + .write = m5208_sys_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) +{ + MemoryRegion *iomem = g_new(MemoryRegion, 1); + m5208_timer_state *s; + QEMUBH *bh; + int i; + + /* SDRAMC. */ + memory_region_init_io(iomem, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000); + memory_region_add_subregion(address_space, 0xfc0a8000, iomem); + /* Timers. */ + for (i = 0; i < 2; i++) { + s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state)); + bh = qemu_bh_new(m5208_timer_trigger, s); + s->timer = ptimer_init(bh); + memory_region_init_io(&s->iomem, &m5208_timer_ops, s, + "m5208-timer", 0x00004000); + memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i, + &s->iomem); + s->irq = pic[4 + i]; + } +} + +static void mcf5208evb_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + M68kCPU *cpu; + CPUM68KState *env; + int kernel_size; + uint64_t elf_entry; + hwaddr entry; + qemu_irq *pic; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); + + if (!cpu_model) { + cpu_model = "m5208"; + } + cpu = cpu_m68k_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find m68k CPU definition\n"); + exit(1); + } + env = &cpu->env; + + /* Initialize CPU registers. */ + env->vbr = 0; + /* TODO: Configure BARs. */ + + /* DRAM at 0x40000000 */ + memory_region_init_ram(ram, "mcf5208.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, 0x40000000, ram); + + /* Internal SRAM. */ + memory_region_init_ram(sram, "mcf5208.sram", 16384); + vmstate_register_ram_global(sram); + memory_region_add_subregion(address_space_mem, 0x80000000, sram); + + /* Internal peripherals. */ + pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu); + + mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]); + mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]); + mcf_uart_mm_init(address_space_mem, 0xfc068000, pic[28], serial_hds[2]); + + mcf5208_sys_init(address_space_mem, pic); + + if (nb_nics > 1) { + fprintf(stderr, "Too many NICs\n"); + exit(1); + } + if (nd_table[0].used) + mcf_fec_init(address_space_mem, &nd_table[0], + 0xfc030000, pic + 36); + + /* 0xfc000000 SCM. */ + /* 0xfc004000 XBS. */ + /* 0xfc008000 FlexBus CS. */ + /* 0xfc030000 FEC. */ + /* 0xfc040000 SCM + Power management. */ + /* 0xfc044000 eDMA. */ + /* 0xfc048000 INTC. */ + /* 0xfc058000 I2C. */ + /* 0xfc05c000 QSPI. */ + /* 0xfc060000 UART0. */ + /* 0xfc064000 UART0. */ + /* 0xfc068000 UART0. */ + /* 0xfc070000 DMA timers. */ + /* 0xfc080000 PIT0. */ + /* 0xfc084000 PIT1. */ + /* 0xfc088000 EPORT. */ + /* 0xfc08c000 Watchdog. */ + /* 0xfc090000 clock module. */ + /* 0xfc0a0000 CCM + reset. */ + /* 0xfc0a4000 GPIO. */ + /* 0xfc0a8000 SDRAM controller. */ + + /* Load kernel. */ + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + + kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, + NULL, NULL, 1, ELF_MACHINE, 0); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, 0x40000000, + ram_size); + entry = 0x40000000; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + env->pc = entry; +} + +static QEMUMachine mcf5208evb_machine = { + .name = "mcf5208evb", + .desc = "MCF5206EVB", + .init = mcf5208evb_init, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void mcf5208evb_machine_init(void) +{ + qemu_register_machine(&mcf5208evb_machine); +} + +machine_init(mcf5208evb_machine_init); diff --git a/hw/mainstone.c b/hw/mainstone.c deleted file mode 100644 index aea908f036..0000000000 --- a/hw/mainstone.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * PXA270-based Intel Mainstone platforms. - * - * Copyright (c) 2007 by Armin Kuster or - * - * - * Code based on spitz platform by Andrzej Zaborowski - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "hw/hw.h" -#include "hw/pxa.h" -#include "hw/arm-misc.h" -#include "net/net.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/flash.h" -#include "sysemu/blockdev.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -/* Device addresses */ -#define MST_FPGA_PHYS 0x08000000 -#define MST_ETH_PHYS 0x10000300 -#define MST_FLASH_0 0x00000000 -#define MST_FLASH_1 0x04000000 - -/* IRQ definitions */ -#define MMC_IRQ 0 -#define USIM_IRQ 1 -#define USBC_IRQ 2 -#define ETHERNET_IRQ 3 -#define AC97_IRQ 4 -#define PEN_IRQ 5 -#define MSINS_IRQ 6 -#define EXBRD_IRQ 7 -#define S0_CD_IRQ 9 -#define S0_STSCHG_IRQ 10 -#define S0_IRQ 11 -#define S1_CD_IRQ 13 -#define S1_STSCHG_IRQ 14 -#define S1_IRQ 15 - -static struct keymap map[0xE0] = { - [0 ... 0xDF] = { -1, -1 }, - [0x1e] = {0,0}, /* a */ - [0x30] = {0,1}, /* b */ - [0x2e] = {0,2}, /* c */ - [0x20] = {0,3}, /* d */ - [0x12] = {0,4}, /* e */ - [0x21] = {0,5}, /* f */ - [0x22] = {1,0}, /* g */ - [0x23] = {1,1}, /* h */ - [0x17] = {1,2}, /* i */ - [0x24] = {1,3}, /* j */ - [0x25] = {1,4}, /* k */ - [0x26] = {1,5}, /* l */ - [0x32] = {2,0}, /* m */ - [0x31] = {2,1}, /* n */ - [0x18] = {2,2}, /* o */ - [0x19] = {2,3}, /* p */ - [0x10] = {2,4}, /* q */ - [0x13] = {2,5}, /* r */ - [0x1f] = {3,0}, /* s */ - [0x14] = {3,1}, /* t */ - [0x16] = {3,2}, /* u */ - [0x2f] = {3,3}, /* v */ - [0x11] = {3,4}, /* w */ - [0x2d] = {3,5}, /* x */ - [0x15] = {4,2}, /* y */ - [0x2c] = {4,3}, /* z */ - [0xc7] = {5,0}, /* Home */ - [0x2a] = {5,1}, /* shift */ - [0x39] = {5,2}, /* space */ - [0x39] = {5,3}, /* space */ - [0x1c] = {5,5}, /* enter */ - [0xc8] = {6,0}, /* up */ - [0xd0] = {6,1}, /* down */ - [0xcb] = {6,2}, /* left */ - [0xcd] = {6,3}, /* right */ -}; - -enum mainstone_model_e { mainstone }; - -#define MAINSTONE_RAM 0x04000000 -#define MAINSTONE_ROM 0x00800000 -#define MAINSTONE_FLASH 0x02000000 - -static struct arm_boot_info mainstone_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = 0x04000000, -}; - -static void mainstone_common_init(MemoryRegion *address_space_mem, - QEMUMachineInitArgs *args, - enum mainstone_model_e model, int arm_id) -{ - uint32_t sector_len = 256 * 1024; - hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; - PXA2xxState *mpu; - DeviceState *mst_irq; - DriveInfo *dinfo; - int i; - int be; - MemoryRegion *rom = g_new(MemoryRegion, 1); - const char *cpu_model = args->cpu_model; - - if (!cpu_model) - cpu_model = "pxa270-c5"; - - /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); - memory_region_init_ram(rom, "mainstone.rom", MAINSTONE_ROM); - vmstate_register_ram_global(rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(address_space_mem, 0, rom); - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - /* There are two 32MiB flash devices on the board */ - for (i = 0; i < 2; i ++) { - dinfo = drive_get(IF_PFLASH, 0, i); - if (!dinfo) { - fprintf(stderr, "Two flash images must be given with the " - "'pflash' parameter\n"); - exit(1); - } - - if (!pflash_cfi01_register(mainstone_flash_base[i], NULL, - i ? "mainstone.flash1" : "mainstone.flash0", - MAINSTONE_FLASH, - dinfo->bdrv, sector_len, - MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0, - be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - } - - mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS, - qdev_get_gpio_in(mpu->gpio, 0)); - - /* setup keypad */ - printf("map addr %p\n", &map); - pxa27x_register_keypad(mpu->kp, map, 0xe0); - - /* MMC/SD host */ - pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); - - pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0], - qdev_get_gpio_in(mst_irq, S0_IRQ), - qdev_get_gpio_in(mst_irq, S0_CD_IRQ)); - pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1], - qdev_get_gpio_in(mst_irq, S1_IRQ), - qdev_get_gpio_in(mst_irq, S1_CD_IRQ)); - - smc91c111_init(&nd_table[0], MST_ETH_PHYS, - qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); - - mainstone_binfo.kernel_filename = args->kernel_filename; - mainstone_binfo.kernel_cmdline = args->kernel_cmdline; - mainstone_binfo.initrd_filename = args->initrd_filename; - mainstone_binfo.board_id = arm_id; - arm_load_kernel(mpu->cpu, &mainstone_binfo); -} - -static void mainstone_init(QEMUMachineInitArgs *args) -{ - mainstone_common_init(get_system_memory(), args, mainstone, 0x196); -} - -static QEMUMachine mainstone2_machine = { - .name = "mainstone", - .desc = "Mainstone II (PXA27x)", - .init = mainstone_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void mainstone_machine_init(void) -{ - qemu_register_machine(&mainstone2_machine); -} - -machine_init(mainstone_machine_init); diff --git a/hw/mcf5208.c b/hw/mcf5208.c deleted file mode 100644 index 748bf56983..0000000000 --- a/hw/mcf5208.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Motorola ColdFire MCF5208 SoC emulation. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ -#include "hw/hw.h" -#include "hw/mcf.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "sysemu/sysemu.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "exec/address-spaces.h" - -#define SYS_FREQ 66000000 - -#define PCSR_EN 0x0001 -#define PCSR_RLD 0x0002 -#define PCSR_PIF 0x0004 -#define PCSR_PIE 0x0008 -#define PCSR_OVW 0x0010 -#define PCSR_DBG 0x0020 -#define PCSR_DOZE 0x0040 -#define PCSR_PRE_SHIFT 8 -#define PCSR_PRE_MASK 0x0f00 - -typedef struct { - MemoryRegion iomem; - qemu_irq irq; - ptimer_state *timer; - uint16_t pcsr; - uint16_t pmr; - uint16_t pcntr; -} m5208_timer_state; - -static void m5208_timer_update(m5208_timer_state *s) -{ - if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF)) - qemu_irq_raise(s->irq); - else - qemu_irq_lower(s->irq); -} - -static void m5208_timer_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - m5208_timer_state *s = (m5208_timer_state *)opaque; - int prescale; - int limit; - switch (offset) { - case 0: - /* The PIF bit is set-to-clear. */ - if (value & PCSR_PIF) { - s->pcsr &= ~PCSR_PIF; - value &= ~PCSR_PIF; - } - /* Avoid frobbing the timer if we're just twiddling IRQ bits. */ - if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) { - s->pcsr = value; - m5208_timer_update(s); - return; - } - - if (s->pcsr & PCSR_EN) - ptimer_stop(s->timer); - - s->pcsr = value; - - prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT); - ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale); - if (s->pcsr & PCSR_RLD) - limit = s->pmr; - else - limit = 0xffff; - ptimer_set_limit(s->timer, limit, 0); - - if (s->pcsr & PCSR_EN) - ptimer_run(s->timer, 0); - break; - case 2: - s->pmr = value; - s->pcsr &= ~PCSR_PIF; - if ((s->pcsr & PCSR_RLD) == 0) { - if (s->pcsr & PCSR_OVW) - ptimer_set_count(s->timer, value); - } else { - ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW); - } - break; - case 4: - break; - default: - hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset); - break; - } - m5208_timer_update(s); -} - -static void m5208_timer_trigger(void *opaque) -{ - m5208_timer_state *s = (m5208_timer_state *)opaque; - s->pcsr |= PCSR_PIF; - m5208_timer_update(s); -} - -static uint64_t m5208_timer_read(void *opaque, hwaddr addr, - unsigned size) -{ - m5208_timer_state *s = (m5208_timer_state *)opaque; - switch (addr) { - case 0: - return s->pcsr; - case 2: - return s->pmr; - case 4: - return ptimer_get_count(s->timer); - default: - hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr); - return 0; - } -} - -static const MemoryRegionOps m5208_timer_ops = { - .read = m5208_timer_read, - .write = m5208_timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static uint64_t m5208_sys_read(void *opaque, hwaddr addr, - unsigned size) -{ - switch (addr) { - case 0x110: /* SDCS0 */ - { - int n; - for (n = 0; n < 32; n++) { - if (ram_size < (2u << n)) - break; - } - return (n - 1) | 0x40000000; - } - case 0x114: /* SDCS1 */ - return 0; - - default: - hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr); - return 0; - } -} - -static void m5208_sys_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr); -} - -static const MemoryRegionOps m5208_sys_ops = { - .read = m5208_sys_read, - .write = m5208_sys_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) -{ - MemoryRegion *iomem = g_new(MemoryRegion, 1); - m5208_timer_state *s; - QEMUBH *bh; - int i; - - /* SDRAMC. */ - memory_region_init_io(iomem, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000); - memory_region_add_subregion(address_space, 0xfc0a8000, iomem); - /* Timers. */ - for (i = 0; i < 2; i++) { - s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state)); - bh = qemu_bh_new(m5208_timer_trigger, s); - s->timer = ptimer_init(bh); - memory_region_init_io(&s->iomem, &m5208_timer_ops, s, - "m5208-timer", 0x00004000); - memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i, - &s->iomem); - s->irq = pic[4 + i]; - } -} - -static void mcf5208evb_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - M68kCPU *cpu; - CPUM68KState *env; - int kernel_size; - uint64_t elf_entry; - hwaddr entry; - qemu_irq *pic; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - - if (!cpu_model) { - cpu_model = "m5208"; - } - cpu = cpu_m68k_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find m68k CPU definition\n"); - exit(1); - } - env = &cpu->env; - - /* Initialize CPU registers. */ - env->vbr = 0; - /* TODO: Configure BARs. */ - - /* DRAM at 0x40000000 */ - memory_region_init_ram(ram, "mcf5208.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space_mem, 0x40000000, ram); - - /* Internal SRAM. */ - memory_region_init_ram(sram, "mcf5208.sram", 16384); - vmstate_register_ram_global(sram); - memory_region_add_subregion(address_space_mem, 0x80000000, sram); - - /* Internal peripherals. */ - pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu); - - mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]); - mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]); - mcf_uart_mm_init(address_space_mem, 0xfc068000, pic[28], serial_hds[2]); - - mcf5208_sys_init(address_space_mem, pic); - - if (nb_nics > 1) { - fprintf(stderr, "Too many NICs\n"); - exit(1); - } - if (nd_table[0].used) - mcf_fec_init(address_space_mem, &nd_table[0], - 0xfc030000, pic + 36); - - /* 0xfc000000 SCM. */ - /* 0xfc004000 XBS. */ - /* 0xfc008000 FlexBus CS. */ - /* 0xfc030000 FEC. */ - /* 0xfc040000 SCM + Power management. */ - /* 0xfc044000 eDMA. */ - /* 0xfc048000 INTC. */ - /* 0xfc058000 I2C. */ - /* 0xfc05c000 QSPI. */ - /* 0xfc060000 UART0. */ - /* 0xfc064000 UART0. */ - /* 0xfc068000 UART0. */ - /* 0xfc070000 DMA timers. */ - /* 0xfc080000 PIT0. */ - /* 0xfc084000 PIT1. */ - /* 0xfc088000 EPORT. */ - /* 0xfc08c000 Watchdog. */ - /* 0xfc090000 clock module. */ - /* 0xfc0a0000 CCM + reset. */ - /* 0xfc0a4000 GPIO. */ - /* 0xfc0a8000 SDRAM controller. */ - - /* Load kernel. */ - if (!kernel_filename) { - fprintf(stderr, "Kernel image must be specified\n"); - exit(1); - } - - kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, - NULL, NULL, 1, ELF_MACHINE, 0); - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); - } - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, 0x40000000, - ram_size); - entry = 0x40000000; - } - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } - - env->pc = entry; -} - -static QEMUMachine mcf5208evb_machine = { - .name = "mcf5208evb", - .desc = "MCF5206EVB", - .init = mcf5208evb_init, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void mcf5208evb_machine_init(void) -{ - qemu_register_machine(&mcf5208evb_machine); -} - -machine_init(mcf5208evb_machine_init); diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index 2ff8048a98..9e7f249941 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -1,9 +1,9 @@ -obj-y = petalogix_s3adsp1800_mmu.o -obj-y += petalogix_ml605_mmu.o -obj-y += microblaze_boot.o obj-y += xilinx_spi.o - -obj-y += microblaze_pic_cpu.o obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += petalogix_s3adsp1800_mmu.o +obj-y += petalogix_ml605_mmu.o +obj-y += boot.o +obj-y += pic_cpu.o diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c new file mode 100644 index 0000000000..e13b3e13bb --- /dev/null +++ b/hw/microblaze/boot.c @@ -0,0 +1,177 @@ +/* + * Microblaze kernel loader + * + * Copyright (c) 2012 Peter Crosthwaite + * Copyright (c) 2012 PetaLogix + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "qemu-common.h" +#include "sysemu/device_tree.h" +#include "hw/loader.h" +#include "elf.h" + +#include "hw/microblaze_boot.h" + +static struct +{ + void (*machine_cpu_reset)(MicroBlazeCPU *); + uint32_t bootstrap_pc; + uint32_t cmdline; + uint32_t fdt; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ + MicroBlazeCPU *cpu = opaque; + CPUMBState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + env->regs[5] = boot_info.cmdline; + env->regs[7] = boot_info.fdt; + env->sregs[SR_PC] = boot_info.bootstrap_pc; + if (boot_info.machine_cpu_reset) { + boot_info.machine_cpu_reset(cpu); + } +} + +static int microblaze_load_dtb(hwaddr addr, + uint32_t ramsize, + const char *kernel_cmdline, + const char *dtb_filename) +{ + int fdt_size; +#ifdef CONFIG_FDT + void *fdt = NULL; + int r; + + if (dtb_filename) { + fdt = load_device_tree(dtb_filename, &fdt_size); + } + if (!fdt) { + return 0; + } + + if (kernel_cmdline) { + r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", + kernel_cmdline); + if (r < 0) { + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + } + } + + cpu_physical_memory_write(addr, (void *)fdt, fdt_size); +#else + /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob + to the kernel. */ + if (dtb_filename) { + fdt_size = load_image_targphys(dtb_filename, addr, 0x10000); + } + if (kernel_cmdline) { + fprintf(stderr, + "Warning: missing libfdt, cannot pass cmdline to kernel!\n"); + } +#endif + return fdt_size; +} + +static uint64_t translate_kernel_address(void *opaque, uint64_t addr) +{ + return addr - 0x30000000LL; +} + +void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, + uint32_t ramsize, const char *dtb_filename, + void (*machine_cpu_reset)(MicroBlazeCPU *)) +{ + QemuOpts *machine_opts; + const char *kernel_filename = NULL; + const char *kernel_cmdline = NULL; + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + const char *dtb_arg; + kernel_filename = qemu_opt_get(machine_opts, "kernel"); + kernel_cmdline = qemu_opt_get(machine_opts, "append"); + dtb_arg = qemu_opt_get(machine_opts, "dtb"); + if (dtb_arg) { /* Preference a -dtb argument */ + dtb_filename = dtb_arg; + } else { /* default to pcbios dtb as passed by machine_init */ + dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); + } + } + + boot_info.machine_cpu_reset = machine_cpu_reset; + qemu_register_reset(main_cpu_reset, cpu); + + if (kernel_filename) { + int kernel_size; + uint64_t entry, low, high; + uint32_t base32; + int big_endian = 0; + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#endif + + /* Boots a kernel elf binary. */ + kernel_size = load_elf(kernel_filename, NULL, NULL, + &entry, &low, &high, + big_endian, ELF_MACHINE, 0); + base32 = entry; + if (base32 == 0xc0000000) { + kernel_size = load_elf(kernel_filename, translate_kernel_address, + NULL, &entry, NULL, NULL, + big_endian, ELF_MACHINE, 0); + } + /* Always boot into physical ram. */ + boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff); + + /* If it wasn't an ELF image, try an u-boot image. */ + if (kernel_size < 0) { + hwaddr uentry, loadaddr; + + kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0); + boot_info.bootstrap_pc = uentry; + high = (loadaddr + kernel_size + 3) & ~3; + } + + /* Not an ELF image nor an u-boot image, try a RAW image. */ + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, ddr_base, + ram_size); + boot_info.bootstrap_pc = ddr_base; + high = (ddr_base + kernel_size + 3) & ~3; + } + + boot_info.cmdline = high + 4096; + if (kernel_cmdline && strlen(kernel_cmdline)) { + pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline); + } + /* Provide a device-tree. */ + boot_info.fdt = boot_info.cmdline + 4096; + microblaze_load_dtb(boot_info.fdt, ram_size, kernel_cmdline, + dtb_filename); + } + +} diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c new file mode 100644 index 0000000000..cfc02207ab --- /dev/null +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -0,0 +1,186 @@ +/* + * Model of Petalogix linux reference design targeting Xilinx Spartan ml605 + * board. + * + * Copyright (c) 2011 Michal Simek + * Copyright (c) 2011 PetaLogix + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "net/net.h" +#include "hw/flash.h" +#include "sysemu/sysemu.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/xilinx.h" +#include "sysemu/blockdev.h" +#include "hw/serial.h" +#include "exec/address-spaces.h" +#include "hw/ssi.h" + +#include "hw/microblaze_boot.h" +#include "hw/microblaze_pic_cpu.h" + +#include "hw/stream.h" + +#define LMB_BRAM_SIZE (128 * 1024) +#define FLASH_SIZE (32 * 1024 * 1024) + +#define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb" + +#define NUM_SPI_FLASHES 4 + +#define MEMORY_BASEADDR 0x50000000 +#define FLASH_BASEADDR 0x86000000 +#define INTC_BASEADDR 0x81800000 +#define TIMER_BASEADDR 0x83c00000 +#define UART16550_BASEADDR 0x83e00000 +#define AXIENET_BASEADDR 0x82780000 +#define AXIDMA_BASEADDR 0x84600000 + +static void machine_cpu_reset(MicroBlazeCPU *cpu) +{ + CPUMBState *env = &cpu->env; + + env->pvr.regs[10] = 0x0e000000; /* virtex 6 */ + /* setup pvr to match kernel setting */ + env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK; + env->pvr.regs[0] |= PVR0_USE_FPU_MASK | PVR0_ENDI; + env->pvr.regs[0] = (env->pvr.regs[0] & ~PVR0_VERSION_MASK) | (0x14 << 8); + env->pvr.regs[2] ^= PVR2_USE_FPU2_MASK; + env->pvr.regs[4] = 0xc56b8000; + env->pvr.regs[5] = 0xc56be000; +} + +static void +petalogix_ml605_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + MemoryRegion *address_space_mem = get_system_memory(); + DeviceState *dev, *dma, *eth0; + MicroBlazeCPU *cpu; + SysBusDevice *busdev; + CPUMBState *env; + DriveInfo *dinfo; + int i; + hwaddr ddr_base = MEMORY_BASEADDR; + MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); + MemoryRegion *phys_ram = g_new(MemoryRegion, 1); + qemu_irq irq[32], *cpu_irq; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "microblaze"; + } + cpu = cpu_mb_init(cpu_model); + env = &cpu->env; + + /* Attach emulated BRAM through the LMB. */ + memory_region_init_ram(phys_lmb_bram, "petalogix_ml605.lmb_bram", + LMB_BRAM_SIZE); + vmstate_register_ram_global(phys_lmb_bram); + memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram); + + memory_region_init_ram(phys_ram, "petalogix_ml605.ram", ram_size); + vmstate_register_ram_global(phys_ram); + memory_region_add_subregion(address_space_mem, ddr_base, phys_ram); + + dinfo = drive_get(IF_PFLASH, 0, 0); + /* 5th parameter 2 means bank-width + * 10th paremeter 0 means little-endian */ + pflash_cfi01_register(FLASH_BASEADDR, + NULL, "petalogix_ml605.flash", FLASH_SIZE, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + FLASH_SIZE >> 16, + 2, 0x89, 0x18, 0x0000, 0x0, 0); + + + cpu_irq = microblaze_pic_init_cpu(env); + dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 4); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(dev, i); + } + + serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2, + irq[5], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN); + + /* 2 timers at irq 2 @ 100 Mhz. */ + xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000); + + /* axi ethernet and dma initialization. */ + qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet"); + eth0 = qdev_create(NULL, "xlnx.axi-ethernet"); + dma = qdev_create(NULL, "xlnx.axi-dma"); + + /* FIXME: attach to the sysbus instead */ + object_property_add_child(container_get(qdev_get_machine(), "/unattached"), + "xilinx-dma", OBJECT(dma), NULL); + + xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(dma), + 0x82780000, irq[3], 0x1000, 0x1000); + + xilinx_axidma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0], + 100 * 1000000); + + { + SSIBus *spi; + + dev = qdev_create(NULL, "xlnx.xps-spi"); + qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0x40a00000); + sysbus_connect_irq(busdev, 0, irq[4]); + + spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); + + for (i = 0; i < NUM_SPI_FLASHES; i++) { + qemu_irq cs_line; + + dev = ssi_create_slave_no_init(spi, "n25q128"); + qdev_init_nofail(dev); + cs_line = qdev_get_gpio_in(dev, 0); + sysbus_connect_irq(busdev, i+1, cs_line); + } + } + + microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, + machine_cpu_reset); + +} + +static QEMUMachine petalogix_ml605_machine = { + .name = "petalogix-ml605", + .desc = "PetaLogix linux refdesign for xilinx ml605 little endian", + .init = petalogix_ml605_init, + .is_default = 0, + DEFAULT_MACHINE_OPTIONS, +}; + +static void petalogix_ml605_machine_init(void) +{ + qemu_register_machine(&petalogix_ml605_machine); +} + +machine_init(petalogix_ml605_machine_init); diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c new file mode 100644 index 0000000000..24983621e5 --- /dev/null +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -0,0 +1,127 @@ +/* + * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800 + * boards. + * + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "net/net.h" +#include "hw/flash.h" +#include "sysemu/sysemu.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/xilinx.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#include "hw/microblaze_boot.h" +#include "hw/microblaze_pic_cpu.h" + +#define LMB_BRAM_SIZE (128 * 1024) +#define FLASH_SIZE (16 * 1024 * 1024) + +#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb" + +#define MEMORY_BASEADDR 0x90000000 +#define FLASH_BASEADDR 0xa0000000 +#define INTC_BASEADDR 0x81800000 +#define TIMER_BASEADDR 0x83c00000 +#define UARTLITE_BASEADDR 0x84000000 +#define ETHLITE_BASEADDR 0x81000000 + +static void machine_cpu_reset(MicroBlazeCPU *cpu) +{ + CPUMBState *env = &cpu->env; + + env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */ +} + +static void +petalogix_s3adsp1800_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + DeviceState *dev; + MicroBlazeCPU *cpu; + CPUMBState *env; + DriveInfo *dinfo; + int i; + hwaddr ddr_base = MEMORY_BASEADDR; + MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); + MemoryRegion *phys_ram = g_new(MemoryRegion, 1); + qemu_irq irq[32], *cpu_irq; + MemoryRegion *sysmem = get_system_memory(); + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "microblaze"; + } + cpu = cpu_mb_init(cpu_model); + env = &cpu->env; + + /* Attach emulated BRAM through the LMB. */ + memory_region_init_ram(phys_lmb_bram, + "petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE); + vmstate_register_ram_global(phys_lmb_bram); + memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram); + + memory_region_init_ram(phys_ram, "petalogix_s3adsp1800.ram", ram_size); + vmstate_register_ram_global(phys_ram); + memory_region_add_subregion(sysmem, ddr_base, phys_ram); + + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(FLASH_BASEADDR, + NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + FLASH_SIZE >> 16, + 1, 0x89, 0x18, 0x0000, 0x0, 1); + + cpu_irq = microblaze_pic_init_cpu(env); + dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 2); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(dev, i); + } + + sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, irq[3]); + /* 2 timers at irq 2 @ 62 Mhz. */ + xilinx_timer_create(TIMER_BASEADDR, irq[0], 0, 62 * 1000000); + xilinx_ethlite_create(&nd_table[0], ETHLITE_BASEADDR, irq[1], 0, 0); + + microblaze_load_kernel(cpu, ddr_base, ram_size, + BINARY_DEVICE_TREE_FILE, machine_cpu_reset); +} + +static QEMUMachine petalogix_s3adsp1800_machine = { + .name = "petalogix-s3adsp1800", + .desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800", + .init = petalogix_s3adsp1800_init, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void petalogix_s3adsp1800_machine_init(void) +{ + qemu_register_machine(&petalogix_s3adsp1800_machine); +} + +machine_init(petalogix_s3adsp1800_machine_init); diff --git a/hw/microblaze/pic_cpu.c b/hw/microblaze/pic_cpu.c new file mode 100644 index 0000000000..d4743ab390 --- /dev/null +++ b/hw/microblaze/pic_cpu.c @@ -0,0 +1,44 @@ +/* + * QEMU MicroBlaze CPU interrupt wrapper logic. + * + * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/microblaze_pic_cpu.h" + +#define D(x) + +static void microblaze_pic_cpu_handler(void *opaque, int irq, int level) +{ + CPUMBState *env = (CPUMBState *)opaque; + int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; + + if (level) + cpu_interrupt(env, type); + else + cpu_reset_interrupt(env, type); +} + +qemu_irq *microblaze_pic_init_cpu(CPUMBState *env) +{ + return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2); +} diff --git a/hw/microblaze_boot.c b/hw/microblaze_boot.c deleted file mode 100644 index e13b3e13bb..0000000000 --- a/hw/microblaze_boot.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Microblaze kernel loader - * - * Copyright (c) 2012 Peter Crosthwaite - * Copyright (c) 2012 PetaLogix - * Copyright (c) 2009 Edgar E. Iglesias. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/option.h" -#include "qemu/config-file.h" -#include "qemu-common.h" -#include "sysemu/device_tree.h" -#include "hw/loader.h" -#include "elf.h" - -#include "hw/microblaze_boot.h" - -static struct -{ - void (*machine_cpu_reset)(MicroBlazeCPU *); - uint32_t bootstrap_pc; - uint32_t cmdline; - uint32_t fdt; -} boot_info; - -static void main_cpu_reset(void *opaque) -{ - MicroBlazeCPU *cpu = opaque; - CPUMBState *env = &cpu->env; - - cpu_reset(CPU(cpu)); - env->regs[5] = boot_info.cmdline; - env->regs[7] = boot_info.fdt; - env->sregs[SR_PC] = boot_info.bootstrap_pc; - if (boot_info.machine_cpu_reset) { - boot_info.machine_cpu_reset(cpu); - } -} - -static int microblaze_load_dtb(hwaddr addr, - uint32_t ramsize, - const char *kernel_cmdline, - const char *dtb_filename) -{ - int fdt_size; -#ifdef CONFIG_FDT - void *fdt = NULL; - int r; - - if (dtb_filename) { - fdt = load_device_tree(dtb_filename, &fdt_size); - } - if (!fdt) { - return 0; - } - - if (kernel_cmdline) { - r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - kernel_cmdline); - if (r < 0) { - fprintf(stderr, "couldn't set /chosen/bootargs\n"); - } - } - - cpu_physical_memory_write(addr, (void *)fdt, fdt_size); -#else - /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob - to the kernel. */ - if (dtb_filename) { - fdt_size = load_image_targphys(dtb_filename, addr, 0x10000); - } - if (kernel_cmdline) { - fprintf(stderr, - "Warning: missing libfdt, cannot pass cmdline to kernel!\n"); - } -#endif - return fdt_size; -} - -static uint64_t translate_kernel_address(void *opaque, uint64_t addr) -{ - return addr - 0x30000000LL; -} - -void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, - uint32_t ramsize, const char *dtb_filename, - void (*machine_cpu_reset)(MicroBlazeCPU *)) -{ - QemuOpts *machine_opts; - const char *kernel_filename = NULL; - const char *kernel_cmdline = NULL; - - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - const char *dtb_arg; - kernel_filename = qemu_opt_get(machine_opts, "kernel"); - kernel_cmdline = qemu_opt_get(machine_opts, "append"); - dtb_arg = qemu_opt_get(machine_opts, "dtb"); - if (dtb_arg) { /* Preference a -dtb argument */ - dtb_filename = dtb_arg; - } else { /* default to pcbios dtb as passed by machine_init */ - dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); - } - } - - boot_info.machine_cpu_reset = machine_cpu_reset; - qemu_register_reset(main_cpu_reset, cpu); - - if (kernel_filename) { - int kernel_size; - uint64_t entry, low, high; - uint32_t base32; - int big_endian = 0; - -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#endif - - /* Boots a kernel elf binary. */ - kernel_size = load_elf(kernel_filename, NULL, NULL, - &entry, &low, &high, - big_endian, ELF_MACHINE, 0); - base32 = entry; - if (base32 == 0xc0000000) { - kernel_size = load_elf(kernel_filename, translate_kernel_address, - NULL, &entry, NULL, NULL, - big_endian, ELF_MACHINE, 0); - } - /* Always boot into physical ram. */ - boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff); - - /* If it wasn't an ELF image, try an u-boot image. */ - if (kernel_size < 0) { - hwaddr uentry, loadaddr; - - kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0); - boot_info.bootstrap_pc = uentry; - high = (loadaddr + kernel_size + 3) & ~3; - } - - /* Not an ELF image nor an u-boot image, try a RAW image. */ - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, ddr_base, - ram_size); - boot_info.bootstrap_pc = ddr_base; - high = (ddr_base + kernel_size + 3) & ~3; - } - - boot_info.cmdline = high + 4096; - if (kernel_cmdline && strlen(kernel_cmdline)) { - pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline); - } - /* Provide a device-tree. */ - boot_info.fdt = boot_info.cmdline + 4096; - microblaze_load_dtb(boot_info.fdt, ram_size, kernel_cmdline, - dtb_filename); - } - -} diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze_pic_cpu.c deleted file mode 100644 index d4743ab390..0000000000 --- a/hw/microblaze_pic_cpu.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * QEMU MicroBlaze CPU interrupt wrapper logic. - * - * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/microblaze_pic_cpu.h" - -#define D(x) - -static void microblaze_pic_cpu_handler(void *opaque, int irq, int level) -{ - CPUMBState *env = (CPUMBState *)opaque; - int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; - - if (level) - cpu_interrupt(env, type); - else - cpu_reset_interrupt(env, type); -} - -qemu_irq *microblaze_pic_init_cpu(CPUMBState *env) -{ - return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2); -} diff --git a/hw/milkymist.c b/hw/milkymist.c deleted file mode 100644 index fd36de57b5..0000000000 --- a/hw/milkymist.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * QEMU model for the Milkymist board. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "hw/flash.h" -#include "sysemu/sysemu.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "sysemu/blockdev.h" -#include "hw/milkymist-hw.h" -#include "hw/lm32.h" -#include "exec/address-spaces.h" - -#define BIOS_FILENAME "mmone-bios.bin" -#define BIOS_OFFSET 0x00860000 -#define BIOS_SIZE (512*1024) -#define KERNEL_LOAD_ADDR 0x40000000 - -typedef struct { - LM32CPU *cpu; - hwaddr bootstrap_pc; - hwaddr flash_base; - hwaddr initrd_base; - size_t initrd_size; - hwaddr cmdline_base; -} ResetInfo; - -static void cpu_irq_handler(void *opaque, int irq, int level) -{ - CPULM32State *env = opaque; - - if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -static void main_cpu_reset(void *opaque) -{ - ResetInfo *reset_info = opaque; - CPULM32State *env = &reset_info->cpu->env; - - cpu_reset(CPU(reset_info->cpu)); - - /* init defaults */ - env->pc = reset_info->bootstrap_pc; - env->regs[R_R1] = reset_info->cmdline_base; - env->regs[R_R2] = reset_info->initrd_base; - env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size; - env->eba = reset_info->flash_base; - env->deba = reset_info->flash_base; -} - -static void -milkymist_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - LM32CPU *cpu; - CPULM32State *env; - int kernel_size; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *phys_sdram = g_new(MemoryRegion, 1); - qemu_irq irq[32], *cpu_irq; - int i; - char *bios_filename; - ResetInfo *reset_info; - - /* memory map */ - hwaddr flash_base = 0x00000000; - size_t flash_sector_size = 128 * 1024; - size_t flash_size = 32 * 1024 * 1024; - hwaddr sdram_base = 0x40000000; - size_t sdram_size = 128 * 1024 * 1024; - - hwaddr initrd_base = sdram_base + 0x1002000; - hwaddr cmdline_base = sdram_base + 0x1000000; - size_t initrd_max = sdram_size - 0x1002000; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - if (cpu_model == NULL) { - cpu_model = "lm32-full"; - } - cpu = cpu_lm32_init(cpu_model); - env = &cpu->env; - reset_info->cpu = cpu; - - cpu_lm32_set_phys_msb_ignore(env, 1); - - memory_region_init_ram(phys_sdram, "milkymist.sdram", sdram_size); - vmstate_register_ram_global(phys_sdram); - memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Numonyx JS28F256J3F105 */ - pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size, - dinfo ? dinfo->bdrv : NULL, flash_sector_size, - flash_size / flash_sector_size, 2, - 0x00, 0x89, 0x00, 0x1d, 1); - - /* create irq lines */ - cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); - env->pic_state = lm32_pic_init(*cpu_irq); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - /* load bios rom */ - if (bios_name == NULL) { - bios_name = BIOS_FILENAME; - } - bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - - if (bios_filename) { - load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE); - } - - reset_info->bootstrap_pc = BIOS_OFFSET; - - /* if no kernel is given no valid bios rom is a fatal error */ - if (!kernel_filename && !dinfo && !bios_filename) { - fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n", - bios_name); - exit(1); - } - - milkymist_uart_create(0x60000000, irq[0]); - milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3], - 80000000, 0x10014d31, 0x0000041f, 0x00000001); - milkymist_hpdmc_create(0x60002000); - milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff); - milkymist_memcard_create(0x60004000); - milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]); - milkymist_pfpu_create(0x60006000, irq[8]); - milkymist_tmu2_create(0x60007000, irq[9]); - milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]); - milkymist_softusb_create(0x6000f000, irq[15], - 0x20000000, 0x1000, 0x20020000, 0x2000); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(); - - if (kernel_filename) { - uint64_t entry; - - /* Boots a kernel elf binary. */ - kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, - 1, ELF_MACHINE, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, sdram_base, - sdram_size); - reset_info->bootstrap_pc = sdram_base; - } - - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - } - - if (kernel_cmdline && strlen(kernel_cmdline)) { - pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, - kernel_cmdline); - reset_info->cmdline_base = (uint32_t)cmdline_base; - } - - if (initrd_filename) { - size_t initrd_size; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - initrd_max); - reset_info->initrd_base = (uint32_t)initrd_base; - reset_info->initrd_size = (uint32_t)initrd_size; - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static QEMUMachine milkymist_machine = { - .name = "milkymist", - .desc = "Milkymist One", - .init = milkymist_init, - .is_default = 0, - DEFAULT_MACHINE_OPTIONS, -}; - -static void milkymist_machine_init(void) -{ - qemu_register_machine(&milkymist_machine); -} - -machine_init(milkymist_machine_init); diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs index 29a5d0db04..1e3bca1c37 100644 --- a/hw/mips/Makefile.objs +++ b/hw/mips/Makefile.objs @@ -1,6 +1,8 @@ -obj-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o -obj-y += mips_addr.o mips_timer.o mips_int.o obj-y += gt64xxx.o mc146818rtc.o -obj-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o +obj-$(CONFIG_FULONG) += bonito.o vt82c686.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o +obj-y += addr.o cputimer.o mips_int.o +obj-$(CONFIG_FULONG) += mips_fulong2e.o diff --git a/hw/mips/addr.c b/hw/mips/addr.c new file mode 100644 index 0000000000..cddc25cf3f --- /dev/null +++ b/hw/mips/addr.c @@ -0,0 +1,34 @@ +/* + * QEMU MIPS address translation support + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" + +uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr) +{ + return addr & 0x7fffffffll; +} + +uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr) +{ + return addr | ~0x7fffffffll; +} diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c new file mode 100644 index 0000000000..9ad13f3924 --- /dev/null +++ b/hw/mips/cputimer.c @@ -0,0 +1,147 @@ +/* + * QEMU MIPS timer support + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" +#include "qemu/timer.h" + +#define TIMER_FREQ 100 * 1000 * 1000 + +/* XXX: do not use a global */ +uint32_t cpu_mips_get_random (CPUMIPSState *env) +{ + static uint32_t lfsr = 1; + static uint32_t prev_idx = 0; + uint32_t idx; + /* Don't return same value twice, so get another value */ + do { + lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u); + idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; + } while (idx == prev_idx); + prev_idx = idx; + return idx; +} + +/* MIPS R4K timer */ +static void cpu_mips_timer_update(CPUMIPSState *env) +{ + uint64_t now, next; + uint32_t wait; + + now = qemu_get_clock_ns(vm_clock); + wait = env->CP0_Compare - env->CP0_Count - + (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec()); + next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); + qemu_mod_timer(env->timer, next); +} + +/* Expire the timer. */ +static void cpu_mips_timer_expire(CPUMIPSState *env) +{ + cpu_mips_timer_update(env); + if (env->insn_flags & ISA_MIPS32R2) { + env->CP0_Cause |= 1 << CP0Ca_TI; + } + qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); +} + +uint32_t cpu_mips_get_count (CPUMIPSState *env) +{ + if (env->CP0_Cause & (1 << CP0Ca_DC)) { + return env->CP0_Count; + } else { + uint64_t now; + + now = qemu_get_clock_ns(vm_clock); + if (qemu_timer_pending(env->timer) + && qemu_timer_expired(env->timer, now)) { + /* The timer has already expired. */ + cpu_mips_timer_expire(env); + } + + return env->CP0_Count + + (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec()); + } +} + +void cpu_mips_store_count (CPUMIPSState *env, uint32_t count) +{ + if (env->CP0_Cause & (1 << CP0Ca_DC)) + env->CP0_Count = count; + else { + /* Store new count register */ + env->CP0_Count = + count - (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock), + TIMER_FREQ, get_ticks_per_sec()); + /* Update timer timer */ + cpu_mips_timer_update(env); + } +} + +void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value) +{ + env->CP0_Compare = value; + if (!(env->CP0_Cause & (1 << CP0Ca_DC))) + cpu_mips_timer_update(env); + if (env->insn_flags & ISA_MIPS32R2) + env->CP0_Cause &= ~(1 << CP0Ca_TI); + qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); +} + +void cpu_mips_start_count(CPUMIPSState *env) +{ + cpu_mips_store_count(env, env->CP0_Count); +} + +void cpu_mips_stop_count(CPUMIPSState *env) +{ + /* Store the current value */ + env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock), + TIMER_FREQ, get_ticks_per_sec()); +} + +static void mips_timer_cb (void *opaque) +{ + CPUMIPSState *env; + + env = opaque; +#if 0 + qemu_log("%s\n", __func__); +#endif + + if (env->CP0_Cause & (1 << CP0Ca_DC)) + return; + + /* ??? This callback should occur when the counter is exactly equal to + the comparator value. Offset the count by one to avoid immediately + retriggering the callback before any virtual time has passed. */ + env->CP0_Count++; + cpu_mips_timer_expire(env); + env->CP0_Count--; +} + +void cpu_mips_clock_init (CPUMIPSState *env) +{ + env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env); + env->CP0_Compare = 0; + cpu_mips_store_count(env, 1); +} diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c new file mode 100644 index 0000000000..766aa9dfb5 --- /dev/null +++ b/hw/mips/mips_fulong2e.c @@ -0,0 +1,411 @@ +/* + * QEMU fulong 2e mini pc support + * + * Copyright (c) 2008 yajin (yajin@vm-kernel.org) + * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn) + * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com) + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +/* + * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz) + * http://www.linux-mips.org/wiki/Fulong + * + * Loongson 2e user manual: + * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf + */ + +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/fdc.h" +#include "net/net.h" +#include "hw/boards.h" +#include "hw/smbus.h" +#include "block/block.h" +#include "hw/flash.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pci/pci.h" +#include "char/char.h" +#include "sysemu/sysemu.h" +#include "audio/audio.h" +#include "qemu/log.h" +#include "hw/loader.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" +#include "elf.h" +#include "hw/vt82c686.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#define DEBUG_FULONG2E_INIT + +#define ENVP_ADDR 0x80002000l +#define ENVP_NB_ENTRIES 16 +#define ENVP_ENTRY_SIZE 256 + +#define MAX_IDE_BUS 2 + +/* + * PMON is not part of qemu and released with BSD license, anyone + * who want to build a pmon binary please first git-clone the source + * from the git repository at: + * http://www.loongson.cn/support/git/pmon + * Then follow the "Compile Guide" available at: + * http://dev.lemote.com/code/pmon + * + * Notes: + * 1, don't use the source at http://dev.lemote.com/http_git/pmon.git + * 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware" + * in the "Compile Guide". + */ +#define FULONG_BIOSNAME "pmon_fulong2e.bin" + +/* PCI SLOT in fulong 2e */ +#define FULONG2E_VIA_SLOT 5 +#define FULONG2E_ATI_SLOT 6 +#define FULONG2E_RTL8139_SLOT 7 + +static ISADevice *pit; + +static struct _loaderparams { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + +static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, + const char *string, ...) +{ + va_list ap; + int32_t table_addr; + + if (index >= ENVP_NB_ENTRIES) + return; + + if (string == NULL) { + prom_buf[index] = 0; + return; + } + + table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; + prom_buf[index] = tswap32(ENVP_ADDR + table_addr); + + va_start(ap, string); + vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap); + va_end(ap); +} + +static int64_t load_kernel (CPUMIPSState *env) +{ + int64_t kernel_entry, kernel_low, kernel_high; + int index = 0; + long initrd_size; + ram_addr_t initrd_offset; + uint32_t *prom_buf; + long prom_size; + + if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL, + (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low, + (uint64_t *)&kernel_high, 0, ELF_MACHINE, 1) < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + loaderparams.kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + initrd_offset = 0; + if (loaderparams.initrd_filename) { + initrd_size = get_image_size (loaderparams.initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + initrd_size = load_image_targphys(loaderparams.initrd_filename, + initrd_offset, ram_size - initrd_offset); + } + if (initrd_size == (target_ulong) -1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + } + + /* Setup prom parameters. */ + prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE); + prom_buf = g_malloc(prom_size); + + prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename); + if (initrd_size > 0) { + prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", + cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, + loaderparams.kernel_cmdline); + } else { + prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline); + } + + /* Setup minimum environment variables */ + prom_set(prom_buf, index++, "busclock=33000000"); + prom_set(prom_buf, index++, "cpuclock=100000000"); + prom_set(prom_buf, index++, "memsize=%i", loaderparams.ram_size/1024/1024); + prom_set(prom_buf, index++, "modetty0=38400n8r"); + prom_set(prom_buf, index++, NULL); + + rom_add_blob_fixed("prom", prom_buf, prom_size, + cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR)); + + return kernel_entry; +} + +static void write_bootloader (CPUMIPSState *env, uint8_t *base, int64_t kernel_addr) +{ + uint32_t *p; + + /* Small bootloader */ + p = (uint32_t *) base; + + stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */ + stl_raw(p++, 0x00000000); /* nop */ + + /* Second part of the bootloader */ + p = (uint32_t *) (base + 0x040); + + stl_raw(p++, 0x3c040000); /* lui a0, 0 */ + stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */ + stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ + stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ + stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ + stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ + stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(env->ram_size) */ + stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ + stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */; + stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */ + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0x00000000); /* nop */ +} + + +static void main_cpu_reset(void *opaque) +{ + MIPSCPU *cpu = opaque; + CPUMIPSState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + /* TODO: 2E reset stuff */ + if (loaderparams.kernel_filename) { + env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); + } +} + +uint8_t eeprom_spd[0x80] = { + 0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70, + 0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01, + 0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50, + 0x2d,0x20,0xb0,0xb0,0x50,0x50,0x00,0x00,0x00,0x00, + 0x00,0x41,0x48,0x3c,0x32,0x75,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x9c,0x7b,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x48,0x42,0x35,0x34,0x41,0x32, + 0x35,0x36,0x38,0x4b,0x4e,0x2d,0x41,0x37,0x35,0x42, + 0x20,0x30,0x20 +}; + +/* Audio support */ +static void audio_init (PCIBus *pci_bus) +{ + vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5)); + vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6)); +} + +/* Network support */ +static void network_init (void) +{ + int i; + + for(i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + const char *default_devaddr = NULL; + + if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) { + /* The fulong board has a RTL8139 card using PCI SLOT 7 */ + default_devaddr = "07"; + } + + pci_nic_init_nofail(nd, "rtl8139", default_devaddr); + } +} + +static void cpu_request_exit(void *opaque, int irq, int level) +{ + CPUMIPSState *env = cpu_single_env; + + if (env && level) { + cpu_exit(env); + } +} + +static void mips_fulong2e_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + char *filename; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios = g_new(MemoryRegion, 1); + long bios_size; + int64_t kernel_entry; + qemu_irq *i8259; + qemu_irq *cpu_exit_irq; + PCIBus *pci_bus; + ISABus *isa_bus; + i2c_bus *smbus; + int i; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + MIPSCPU *cpu; + CPUMIPSState *env; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "Loongson-2E"; + } + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + qemu_register_reset(main_cpu_reset, cpu); + + /* fulong 2e has 256M ram. */ + ram_size = 256 * 1024 * 1024; + + /* fulong 2e has a 1M flash.Winbond W39L040AP70Z */ + bios_size = 1024 * 1024; + + /* allocate RAM */ + memory_region_init_ram(ram, "fulong2e.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_init_ram(bios, "fulong2e.bios", bios_size); + vmstate_register_ram_global(bios); + memory_region_set_readonly(bios, true); + + memory_region_add_subregion(address_space_mem, 0, ram); + memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); + + /* We do not support flash operation, just loading pmon.bin as raw BIOS. + * Please use -L to set the BIOS path and -bios to set bios name. */ + + if (kernel_filename) { + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + loaderparams.kernel_cmdline = kernel_cmdline; + loaderparams.initrd_filename = initrd_filename; + kernel_entry = load_kernel (env); + write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry); + } else { + if (bios_name == NULL) { + bios_name = FULONG_BIOSNAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = load_image_targphys(filename, 0x1fc00000LL, + BIOS_SIZE); + g_free(filename); + } else { + bios_size = -1; + } + + if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { + fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name); + exit(1); + } + } + + /* Init internal devices */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + + /* North bridge, Bonito --> IP2 */ + pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); + + /* South bridge */ + ide_drive_get(hd, MAX_IDE_BUS); + + isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); + if (!isa_bus) { + fprintf(stderr, "vt82c686b_init error\n"); + exit(1); + } + + /* Interrupt controller */ + /* The 8259 -> IP5 */ + i8259 = i8259_init(isa_bus, env->irq[5]); + isa_bus_irqs(isa_bus, i8259); + + vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1)); + pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2), + "vt82c686b-usb-uhci"); + pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3), + "vt82c686b-usb-uhci"); + + smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4), + 0xeee1, NULL); + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); + + /* init other devices */ + pit = pit_init(isa_bus, 0x40, 0, NULL); + cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); + DMA_init(0, cpu_exit_irq); + + /* Super I/O */ + isa_create_simple(isa_bus, "i8042"); + + rtc_init(isa_bus, 2000, NULL); + + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_isa_init(isa_bus, i, serial_hds[i]); + } + } + + if (parallel_hds[0]) { + parallel_init(isa_bus, 0, parallel_hds[0]); + } + + /* Sound card */ + audio_init(pci_bus); + /* Network card */ + network_init(); +} + +static QEMUMachine mips_fulong2e_machine = { + .name = "fulong2e", + .desc = "Fulong 2e mini pc", + .init = mips_fulong2e_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void mips_fulong2e_machine_init(void) +{ + qemu_register_machine(&mips_fulong2e_machine); +} + +machine_init(mips_fulong2e_machine_init); diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c new file mode 100644 index 0000000000..ddd3b1bb01 --- /dev/null +++ b/hw/mips/mips_int.c @@ -0,0 +1,65 @@ +/* + * QEMU MIPS interrupt support + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" +#include "cpu.h" + +static void cpu_mips_irq_request(void *opaque, int irq, int level) +{ + CPUMIPSState *env = (CPUMIPSState *)opaque; + + if (irq < 0 || irq > 7) + return; + + if (level) { + env->CP0_Cause |= 1 << (irq + CP0Ca_IP); + } else { + env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); + } + + if (env->CP0_Cause & CP0Ca_IP_mask) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +void cpu_mips_irq_init_cpu(CPUMIPSState *env) +{ + qemu_irq *qi; + int i; + + qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8); + for (i = 0; i < 8; i++) { + env->irq[i] = qi[i]; + } +} + +void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level) +{ + if (irq < 0 || irq > 2) { + return; + } + + qemu_set_irq(env->irq[irq], level); +} diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c new file mode 100644 index 0000000000..daeb985b1d --- /dev/null +++ b/hw/mips/mips_jazz.c @@ -0,0 +1,345 @@ +/* + * QEMU MIPS Jazz support + * + * Copyright (c) 2007-2008 Hervé Poussineau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/isa.h" +#include "hw/fdc.h" +#include "sysemu/sysemu.h" +#include "sysemu/arch_init.h" +#include "hw/boards.h" +#include "net/net.h" +#include "hw/esp.h" +#include "hw/mips-bios.h" +#include "hw/loader.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" +#include "sysemu/blockdev.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + +enum jazz_model_e +{ + JAZZ_MAGNUM, + JAZZ_PICA61, +}; + +static void main_cpu_reset(void *opaque) +{ + MIPSCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size) +{ + return cpu_inw(0x71); +} + +static void rtc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + cpu_outw(0x71, val & 0xff); +} + +static const MemoryRegionOps rtc_ops = { + .read = rtc_read, + .write = rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static uint64_t dma_dummy_read(void *opaque, hwaddr addr, + unsigned size) +{ + /* Nothing to do. That is only to ensure that + * the current DMA acknowledge cycle is completed. */ + return 0xff; +} + +static void dma_dummy_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + /* Nothing to do. That is only to ensure that + * the current DMA acknowledge cycle is completed. */ +} + +static const MemoryRegionOps dma_dummy_ops = { + .read = dma_dummy_read, + .write = dma_dummy_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +#define MAGNUM_BIOS_SIZE_MAX 0x7e000 +#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX) + +static void cpu_request_exit(void *opaque, int irq, int level) +{ + CPUMIPSState *env = cpu_single_env; + + if (env && level) { + cpu_exit(env); + } +} + +static void mips_jazz_init(MemoryRegion *address_space, + MemoryRegion *address_space_io, + ram_addr_t ram_size, + const char *cpu_model, + enum jazz_model_e jazz_model) +{ + char *filename; + int bios_size, n; + MIPSCPU *cpu; + CPUMIPSState *env; + qemu_irq *rc4030, *i8259; + rc4030_dma *dmas; + void* rc4030_opaque; + MemoryRegion *rtc = g_new(MemoryRegion, 1); + MemoryRegion *i8042 = g_new(MemoryRegion, 1); + MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); + NICInfo *nd; + DeviceState *dev; + SysBusDevice *sysbus; + ISABus *isa_bus; + ISADevice *pit; + DriveInfo *fds[MAX_FD]; + qemu_irq esp_reset, dma_enable; + qemu_irq *cpu_exit_irq; + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios = g_new(MemoryRegion, 1); + MemoryRegion *bios2 = g_new(MemoryRegion, 1); + + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_MIPS64 + cpu_model = "R4000"; +#else + /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */ + cpu_model = "24Kf"; +#endif + } + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + qemu_register_reset(main_cpu_reset, cpu); + + /* allocate RAM */ + memory_region_init_ram(ram, "mips_jazz.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space, 0, ram); + + memory_region_init_ram(bios, "mips_jazz.bios", MAGNUM_BIOS_SIZE); + vmstate_register_ram_global(bios); + memory_region_set_readonly(bios, true); + memory_region_init_alias(bios2, "mips_jazz.bios", bios, + 0, MAGNUM_BIOS_SIZE); + memory_region_add_subregion(address_space, 0x1fc00000LL, bios); + memory_region_add_subregion(address_space, 0xfff00000LL, bios2); + + /* load the BIOS image. */ + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = load_image_targphys(filename, 0xfff00000LL, + MAGNUM_BIOS_SIZE); + g_free(filename); + } else { + bios_size = -1; + } + if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) { + fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", + bios_name); + exit(1); + } + + /* Init CPU internal devices */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + + /* Chipset */ + rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas, + address_space); + memory_region_init_io(dma_dummy, &dma_dummy_ops, NULL, "dummy_dma", 0x1000); + memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); + + /* ISA devices */ + isa_bus = isa_bus_new(NULL, address_space_io); + i8259 = i8259_init(isa_bus, env->irq[4]); + isa_bus_irqs(isa_bus, i8259); + cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); + DMA_init(0, cpu_exit_irq); + pit = pit_init(isa_bus, 0x40, 0, NULL); + pcspk_init(isa_bus, pit); + + /* ISA IO space at 0x90000000 */ + isa_mmio_init(0x90000000, 0x01000000); + isa_mem_base = 0x11000000; + + /* Video card */ + switch (jazz_model) { + case JAZZ_MAGNUM: + dev = qdev_create(NULL, "sysbus-g364"); + qdev_init_nofail(dev); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sysbus, 0, 0x60080000); + sysbus_mmio_map(sysbus, 1, 0x40000000); + sysbus_connect_irq(sysbus, 0, rc4030[3]); + { + /* Simple ROM, so user doesn't have to provide one */ + MemoryRegion *rom_mr = g_new(MemoryRegion, 1); + memory_region_init_ram(rom_mr, "g364fb.rom", 0x80000); + vmstate_register_ram_global(rom_mr); + memory_region_set_readonly(rom_mr, true); + uint8_t *rom = memory_region_get_ram_ptr(rom_mr); + memory_region_add_subregion(address_space, 0x60000000, rom_mr); + rom[0] = 0x10; /* Mips G364 */ + } + break; + case JAZZ_PICA61: + isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory()); + break; + default: + break; + } + + /* Network controller */ + for (n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + if (!nd->model) + nd->model = g_strdup("dp83932"); + if (strcmp(nd->model, "dp83932") == 0) { + dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4], + rc4030_opaque, rc4030_dma_memory_rw); + break; + } else if (is_help_option(nd->model)) { + fprintf(stderr, "qemu: Supported NICs: dp83932\n"); + exit(1); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); + exit(1); + } + } + + /* SCSI adapter */ + esp_init(0x80002000, 0, + rc4030_dma_read, rc4030_dma_write, dmas[0], + rc4030[5], &esp_reset, &dma_enable); + + /* Floppy */ + if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) { + fprintf(stderr, "qemu: too many floppy drives\n"); + exit(1); + } + for (n = 0; n < MAX_FD; n++) { + fds[n] = drive_get(IF_FLOPPY, 0, n); + } + fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds); + + /* Real time clock */ + rtc_init(isa_bus, 1980, NULL); + memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000); + memory_region_add_subregion(address_space, 0x80004000, rtc); + + /* Keyboard (i8042) */ + i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1); + memory_region_add_subregion(address_space, 0x80005000, i8042); + + /* Serial ports */ + if (serial_hds[0]) { + serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16, + serial_hds[0], DEVICE_NATIVE_ENDIAN); + } + if (serial_hds[1]) { + serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16, + serial_hds[1], DEVICE_NATIVE_ENDIAN); + } + + /* Parallel port */ + if (parallel_hds[0]) + parallel_mm_init(address_space, 0x80008000, 0, rc4030[0], + parallel_hds[0]); + + /* Sound card */ + /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ + audio_init(isa_bus, NULL); + + /* NVRAM */ + dev = qdev_create(NULL, "ds1225y"); + qdev_init_nofail(dev); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sysbus, 0, 0x80009000); + + /* LED indicator */ + sysbus_create_simple("jazz-led", 0x8000f000, NULL); +} + +static +void mips_magnum_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + mips_jazz_init(get_system_memory(), get_system_io(), + ram_size, cpu_model, JAZZ_MAGNUM); +} + +static +void mips_pica61_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + mips_jazz_init(get_system_memory(), get_system_io(), + ram_size, cpu_model, JAZZ_PICA61); +} + +static QEMUMachine mips_magnum_machine = { + .name = "magnum", + .desc = "MIPS Magnum", + .init = mips_magnum_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine mips_pica61_machine = { + .name = "pica61", + .desc = "Acer Pica 61", + .init = mips_pica61_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static void mips_jazz_machine_init(void) +{ + qemu_register_machine(&mips_magnum_machine); + qemu_register_machine(&mips_pica61_machine); +} + +machine_init(mips_jazz_machine_init); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c new file mode 100644 index 0000000000..9a67dce207 --- /dev/null +++ b/hw/mips/mips_malta.c @@ -0,0 +1,1037 @@ +/* + * QEMU Malta board support + * + * Copyright (c) 2006 Aurelien Jarno + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/fdc.h" +#include "net/net.h" +#include "hw/boards.h" +#include "hw/smbus.h" +#include "block/block.h" +#include "hw/flash.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pci/pci.h" +#include "char/char.h" +#include "sysemu/sysemu.h" +#include "sysemu/arch_init.h" +#include "hw/boards.h" +#include "qemu/log.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" +#include "hw/sysbus.h" /* SysBusDevice */ + +//#define DEBUG_BOARD_INIT + +#define ENVP_ADDR 0x80002000l +#define ENVP_NB_ENTRIES 16 +#define ENVP_ENTRY_SIZE 256 + +/* Hardware addresses */ +#define FLASH_ADDRESS 0x1e000000ULL +#define FPGA_ADDRESS 0x1f000000ULL +#define RESET_ADDRESS 0x1fc00000ULL + +#define FLASH_SIZE 0x400000 + +#define MAX_IDE_BUS 2 + +typedef struct { + MemoryRegion iomem; + MemoryRegion iomem_lo; /* 0 - 0x900 */ + MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */ + uint32_t leds; + uint32_t brk; + uint32_t gpout; + uint32_t i2cin; + uint32_t i2coe; + uint32_t i2cout; + uint32_t i2csel; + CharDriverState *display; + char display_text[9]; + SerialState *uart; +} MaltaFPGAState; + +typedef struct { + SysBusDevice busdev; + qemu_irq *i8259; +} MaltaState; + +static ISADevice *pit; + +static struct _loaderparams { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + +/* Malta FPGA */ +static void malta_fpga_update_display(void *opaque) +{ + char leds_text[9]; + int i; + MaltaFPGAState *s = opaque; + + for (i = 7 ; i >= 0 ; i--) { + if (s->leds & (1 << i)) + leds_text[i] = '#'; + else + leds_text[i] = ' '; + } + leds_text[8] = '\0'; + + qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); + qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); +} + +/* + * EEPROM 24C01 / 24C02 emulation. + * + * Emulation for serial EEPROMs: + * 24C01 - 1024 bit (128 x 8) + * 24C02 - 2048 bit (256 x 8) + * + * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02. + */ + +//~ #define DEBUG + +#if defined(DEBUG) +# define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__) +#else +# define logout(fmt, ...) ((void)0) +#endif + +struct _eeprom24c0x_t { + uint8_t tick; + uint8_t address; + uint8_t command; + uint8_t ack; + uint8_t scl; + uint8_t sda; + uint8_t data; + //~ uint16_t size; + uint8_t contents[256]; +}; + +typedef struct _eeprom24c0x_t eeprom24c0x_t; + +static eeprom24c0x_t eeprom = { + .contents = { + /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00, + /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01, + /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00, + /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40, + /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00, + /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0, + /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4, + }, +}; + +static uint8_t eeprom24c0x_read(void) +{ + logout("%u: scl = %u, sda = %u, data = 0x%02x\n", + eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data); + return eeprom.sda; +} + +static void eeprom24c0x_write(int scl, int sda) +{ + if (eeprom.scl && scl && (eeprom.sda != sda)) { + logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n", + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start"); + if (!sda) { + eeprom.tick = 1; + eeprom.command = 0; + } + } else if (eeprom.tick == 0 && !eeprom.ack) { + /* Waiting for start. */ + logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n", + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); + } else if (!eeprom.scl && scl) { + logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n", + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); + if (eeprom.ack) { + logout("\ti2c ack bit = 0\n"); + sda = 0; + eeprom.ack = 0; + } else if (eeprom.sda == sda) { + uint8_t bit = (sda != 0); + logout("\ti2c bit = %d\n", bit); + if (eeprom.tick < 9) { + eeprom.command <<= 1; + eeprom.command += bit; + eeprom.tick++; + if (eeprom.tick == 9) { + logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write"); + eeprom.ack = 1; + } + } else if (eeprom.tick < 17) { + if (eeprom.command & 1) { + sda = ((eeprom.data & 0x80) != 0); + } + eeprom.address <<= 1; + eeprom.address += bit; + eeprom.tick++; + eeprom.data <<= 1; + if (eeprom.tick == 17) { + eeprom.data = eeprom.contents[eeprom.address]; + logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data); + eeprom.ack = 1; + eeprom.tick = 0; + } + } else if (eeprom.tick >= 17) { + sda = 0; + } + } else { + logout("\tsda changed with raising scl\n"); + } + } else { + logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); + } + eeprom.scl = scl; + eeprom.sda = sda; +} + +static uint64_t malta_fpga_read(void *opaque, hwaddr addr, + unsigned size) +{ + MaltaFPGAState *s = opaque; + uint32_t val = 0; + uint32_t saddr; + + saddr = (addr & 0xfffff); + + switch (saddr) { + + /* SWITCH Register */ + case 0x00200: + val = 0x00000000; /* All switches closed */ + break; + + /* STATUS Register */ + case 0x00208: +#ifdef TARGET_WORDS_BIGENDIAN + val = 0x00000012; +#else + val = 0x00000010; +#endif + break; + + /* JMPRS Register */ + case 0x00210: + val = 0x00; + break; + + /* LEDBAR Register */ + case 0x00408: + val = s->leds; + break; + + /* BRKRES Register */ + case 0x00508: + val = s->brk; + break; + + /* UART Registers are handled directly by the serial device */ + + /* GPOUT Register */ + case 0x00a00: + val = s->gpout; + break; + + /* XXX: implement a real I2C controller */ + + /* GPINP Register */ + case 0x00a08: + /* IN = OUT until a real I2C control is implemented */ + if (s->i2csel) + val = s->i2cout; + else + val = 0x00; + break; + + /* I2CINP Register */ + case 0x00b00: + val = ((s->i2cin & ~1) | eeprom24c0x_read()); + break; + + /* I2COE Register */ + case 0x00b08: + val = s->i2coe; + break; + + /* I2COUT Register */ + case 0x00b10: + val = s->i2cout; + break; + + /* I2CSEL Register */ + case 0x00b18: + val = s->i2csel; + break; + + default: +#if 0 + printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n", + addr); +#endif + break; + } + return val; +} + +static void malta_fpga_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MaltaFPGAState *s = opaque; + uint32_t saddr; + + saddr = (addr & 0xfffff); + + switch (saddr) { + + /* SWITCH Register */ + case 0x00200: + break; + + /* JMPRS Register */ + case 0x00210: + break; + + /* LEDBAR Register */ + case 0x00408: + s->leds = val & 0xff; + malta_fpga_update_display(s); + break; + + /* ASCIIWORD Register */ + case 0x00410: + snprintf(s->display_text, 9, "%08X", (uint32_t)val); + malta_fpga_update_display(s); + break; + + /* ASCIIPOS0 to ASCIIPOS7 Registers */ + case 0x00418: + case 0x00420: + case 0x00428: + case 0x00430: + case 0x00438: + case 0x00440: + case 0x00448: + case 0x00450: + s->display_text[(saddr - 0x00418) >> 3] = (char) val; + malta_fpga_update_display(s); + break; + + /* SOFTRES Register */ + case 0x00500: + if (val == 0x42) + qemu_system_reset_request (); + break; + + /* BRKRES Register */ + case 0x00508: + s->brk = val & 0xff; + break; + + /* UART Registers are handled directly by the serial device */ + + /* GPOUT Register */ + case 0x00a00: + s->gpout = val & 0xff; + break; + + /* I2COE Register */ + case 0x00b08: + s->i2coe = val & 0x03; + break; + + /* I2COUT Register */ + case 0x00b10: + eeprom24c0x_write(val & 0x02, val & 0x01); + s->i2cout = val; + break; + + /* I2CSEL Register */ + case 0x00b18: + s->i2csel = val & 0x01; + break; + + default: +#if 0 + printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n", + addr); +#endif + break; + } +} + +static const MemoryRegionOps malta_fpga_ops = { + .read = malta_fpga_read, + .write = malta_fpga_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void malta_fpga_reset(void *opaque) +{ + MaltaFPGAState *s = opaque; + + s->leds = 0x00; + s->brk = 0x0a; + s->gpout = 0x00; + s->i2cin = 0x3; + s->i2coe = 0x0; + s->i2cout = 0x3; + s->i2csel = 0x1; + + s->display_text[8] = '\0'; + snprintf(s->display_text, 9, " "); +} + +static void malta_fpga_led_init(CharDriverState *chr) +{ + qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n"); + qemu_chr_fe_printf(chr, "+--------+\r\n"); + qemu_chr_fe_printf(chr, "+ +\r\n"); + qemu_chr_fe_printf(chr, "+--------+\r\n"); + qemu_chr_fe_printf(chr, "\n"); + qemu_chr_fe_printf(chr, "Malta ASCII\r\n"); + qemu_chr_fe_printf(chr, "+--------+\r\n"); + qemu_chr_fe_printf(chr, "+ +\r\n"); + qemu_chr_fe_printf(chr, "+--------+\r\n"); +} + +static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space, + hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr) +{ + MaltaFPGAState *s; + + s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState)); + + memory_region_init_io(&s->iomem, &malta_fpga_ops, s, + "malta-fpga", 0x100000); + memory_region_init_alias(&s->iomem_lo, "malta-fpga", + &s->iomem, 0, 0x900); + memory_region_init_alias(&s->iomem_hi, "malta-fpga", + &s->iomem, 0xa00, 0x10000-0xa00); + + memory_region_add_subregion(address_space, base, &s->iomem_lo); + memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi); + + s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init); + + s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq, + 230400, uart_chr, DEVICE_NATIVE_ENDIAN); + + malta_fpga_reset(s); + qemu_register_reset(malta_fpga_reset, s); + + return s; +} + +/* Network support */ +static void network_init(void) +{ + int i; + + for(i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + const char *default_devaddr = NULL; + + if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0)) + /* The malta board has a PCNet card using PCI SLOT 11 */ + default_devaddr = "0b"; + + pci_nic_init_nofail(nd, "pcnet", default_devaddr); + } +} + +/* ROM and pseudo bootloader + + The following code implements a very very simple bootloader. It first + loads the registers a0 to a3 to the values expected by the OS, and + then jump at the kernel address. + + The bootloader should pass the locations of the kernel arguments and + environment variables tables. Those tables contain the 32-bit address + of NULL terminated strings. The environment variables table should be + terminated by a NULL address. + + For a simpler implementation, the number of kernel arguments is fixed + to two (the name of the kernel and the command line), and the two + tables are actually the same one. + + The registers a0 to a3 should contain the following values: + a0 - number of kernel arguments + a1 - 32-bit address of the kernel arguments table + a2 - 32-bit address of the environment variables table + a3 - RAM size in bytes +*/ + +static void write_bootloader (CPUMIPSState *env, uint8_t *base, + int64_t kernel_entry) +{ + uint32_t *p; + + /* Small bootloader */ + p = (uint32_t *)base; + stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */ + stl_raw(p++, 0x00000000); /* nop */ + + /* YAMON service vector */ + stl_raw(base + 0x500, 0xbfc00580); /* start: */ + stl_raw(base + 0x504, 0xbfc0083c); /* print_count: */ + stl_raw(base + 0x520, 0xbfc00580); /* start: */ + stl_raw(base + 0x52c, 0xbfc00800); /* flush_cache: */ + stl_raw(base + 0x534, 0xbfc00808); /* print: */ + stl_raw(base + 0x538, 0xbfc00800); /* reg_cpu_isr: */ + stl_raw(base + 0x53c, 0xbfc00800); /* unred_cpu_isr: */ + stl_raw(base + 0x540, 0xbfc00800); /* reg_ic_isr: */ + stl_raw(base + 0x544, 0xbfc00800); /* unred_ic_isr: */ + stl_raw(base + 0x548, 0xbfc00800); /* reg_esr: */ + stl_raw(base + 0x54c, 0xbfc00800); /* unreg_esr: */ + stl_raw(base + 0x550, 0xbfc00800); /* getchar: */ + stl_raw(base + 0x554, 0xbfc00800); /* syscon_read: */ + + + /* Second part of the bootloader */ + p = (uint32_t *) (base + 0x580); + stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */ + stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ + stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */ + stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ + stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */ + stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ + stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ + stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */ + stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */ + + /* Load BAR registers as done by YAMON */ + stl_raw(p++, 0x3c09b400); /* lui t1, 0xb400 */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c08df00); /* lui t0, 0xdf00 */ +#else + stl_raw(p++, 0x340800df); /* ori t0, r0, 0x00df */ +#endif + stl_raw(p++, 0xad280068); /* sw t0, 0x0068(t1) */ + + stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c08c000); /* lui t0, 0xc000 */ +#else + stl_raw(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */ +#endif + stl_raw(p++, 0xad280048); /* sw t0, 0x0048(t1) */ +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c084000); /* lui t0, 0x4000 */ +#else + stl_raw(p++, 0x34080040); /* ori t0, r0, 0x0040 */ +#endif + stl_raw(p++, 0xad280050); /* sw t0, 0x0050(t1) */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c088000); /* lui t0, 0x8000 */ +#else + stl_raw(p++, 0x34080080); /* ori t0, r0, 0x0080 */ +#endif + stl_raw(p++, 0xad280058); /* sw t0, 0x0058(t1) */ +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c083f00); /* lui t0, 0x3f00 */ +#else + stl_raw(p++, 0x3408003f); /* ori t0, r0, 0x003f */ +#endif + stl_raw(p++, 0xad280060); /* sw t0, 0x0060(t1) */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c08c100); /* lui t0, 0xc100 */ +#else + stl_raw(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */ +#endif + stl_raw(p++, 0xad280080); /* sw t0, 0x0080(t1) */ +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c085e00); /* lui t0, 0x5e00 */ +#else + stl_raw(p++, 0x3408005e); /* ori t0, r0, 0x005e */ +#endif + stl_raw(p++, 0xad280088); /* sw t0, 0x0088(t1) */ + + /* Jump to kernel code */ + stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */ + stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0x00000000); /* nop */ + + /* YAMON subroutines */ + p = (uint32_t *) (base + 0x800); + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0x24020000); /* li v0,0 */ + /* 808 YAMON print */ + stl_raw(p++, 0x03e06821); /* move t5,ra */ + stl_raw(p++, 0x00805821); /* move t3,a0 */ + stl_raw(p++, 0x00a05021); /* move t2,a1 */ + stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ + stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ + stl_raw(p++, 0x10800005); /* beqz a0,834 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x0ff0021c); /* jal 870 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x08000205); /* j 814 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x01a00008); /* jr t5 */ + stl_raw(p++, 0x01602021); /* move a0,t3 */ + /* 0x83c YAMON print_count */ + stl_raw(p++, 0x03e06821); /* move t5,ra */ + stl_raw(p++, 0x00805821); /* move t3,a0 */ + stl_raw(p++, 0x00a05021); /* move t2,a1 */ + stl_raw(p++, 0x00c06021); /* move t4,a2 */ + stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ + stl_raw(p++, 0x0ff0021c); /* jal 870 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ + stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */ + stl_raw(p++, 0x1580fffa); /* bnez t4,84c */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x01a00008); /* jr t5 */ + stl_raw(p++, 0x01602021); /* move a0,t3 */ + /* 0x870 */ + stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */ + stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */ + stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */ + stl_raw(p++, 0x1120fffc); /* beqz t1,878 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */ + +} + +static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, + const char *string, ...) +{ + va_list ap; + int32_t table_addr; + + if (index >= ENVP_NB_ENTRIES) + return; + + if (string == NULL) { + prom_buf[index] = 0; + return; + } + + table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; + prom_buf[index] = tswap32(ENVP_ADDR + table_addr); + + va_start(ap, string); + vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap); + va_end(ap); +} + +/* Kernel */ +static int64_t load_kernel (void) +{ + int64_t kernel_entry, kernel_high; + long initrd_size; + ram_addr_t initrd_offset; + int big_endian; + uint32_t *prom_buf; + long prom_size; + int prom_index = 0; + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + + if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL, + (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high, + big_endian, ELF_MACHINE, 1) < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + loaderparams.kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + initrd_offset = 0; + if (loaderparams.initrd_filename) { + initrd_size = get_image_size (loaderparams.initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + initrd_size = load_image_targphys(loaderparams.initrd_filename, + initrd_offset, + ram_size - initrd_offset); + } + if (initrd_size == (target_ulong) -1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + } + + /* Setup prom parameters. */ + prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE); + prom_buf = g_malloc(prom_size); + + prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename); + if (initrd_size > 0) { + prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", + cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, + loaderparams.kernel_cmdline); + } else { + prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline); + } + + prom_set(prom_buf, prom_index++, "memsize"); + prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size); + prom_set(prom_buf, prom_index++, "modetty0"); + prom_set(prom_buf, prom_index++, "38400n8r"); + prom_set(prom_buf, prom_index++, NULL); + + rom_add_blob_fixed("prom", prom_buf, prom_size, + cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR)); + + return kernel_entry; +} + +static void malta_mips_config(MIPSCPU *cpu) +{ + CPUMIPSState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) | + ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC); +} + +static void main_cpu_reset(void *opaque) +{ + MIPSCPU *cpu = opaque; + CPUMIPSState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + + /* The bootloader does not need to be rewritten as it is located in a + read only location. The kernel location and the arguments table + location does not change. */ + if (loaderparams.kernel_filename) { + env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); + } + + malta_mips_config(cpu); +} + +static void cpu_request_exit(void *opaque, int irq, int level) +{ + CPUMIPSState *env = cpu_single_env; + + if (env && level) { + cpu_exit(env); + } +} + +static +void mips_malta_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + char *filename; + pflash_t *fl; + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1); + target_long bios_size = FLASH_SIZE; + int64_t kernel_entry; + PCIBus *pci_bus; + ISABus *isa_bus; + MIPSCPU *cpu; + CPUMIPSState *env; + qemu_irq *isa_irq; + qemu_irq *cpu_exit_irq; + int piix4_devfn; + i2c_bus *smbus; + int i; + DriveInfo *dinfo; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + DriveInfo *fd[MAX_FD]; + int fl_idx = 0; + int fl_sectors = bios_size >> 16; + int be; + + DeviceState *dev = qdev_create(NULL, "mips-malta"); + MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev); + + qdev_init_nofail(dev); + + /* Make sure the first 3 serial ports are associated with a device. */ + for(i = 0; i < 3; i++) { + if (!serial_hds[i]) { + char label[32]; + snprintf(label, sizeof(label), "serial%d", i); + serial_hds[i] = qemu_chr_new(label, "null", NULL); + } + } + + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_MIPS64 + cpu_model = "20Kc"; +#else + cpu_model = "24Kf"; +#endif + } + + for (i = 0; i < smp_cpus; i++) { + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + /* Init internal devices */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + qemu_register_reset(main_cpu_reset, cpu); + } + env = first_cpu; + + /* allocate RAM */ + if (ram_size > (256 << 20)) { + fprintf(stderr, + "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n", + ((unsigned int)ram_size / (1 << 20))); + exit(1); + } + memory_region_init_ram(ram, "mips_malta.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(system_memory, 0, ram); + +#ifdef TARGET_WORDS_BIGENDIAN + be = 1; +#else + be = 0; +#endif + /* FPGA */ + /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */ + malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]); + + /* Load firmware in flash / BIOS. */ + dinfo = drive_get(IF_PFLASH, 0, fl_idx); +#ifdef DEBUG_BOARD_INIT + if (dinfo) { + printf("Register parallel flash %d size " TARGET_FMT_lx " at " + "addr %08llx '%s' %x\n", + fl_idx, bios_size, FLASH_ADDRESS, + bdrv_get_device_name(dinfo->bdrv), fl_sectors); + } +#endif + fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios", + BIOS_SIZE, dinfo ? dinfo->bdrv : NULL, + 65536, fl_sectors, + 4, 0x0000, 0x0000, 0x0000, 0x0000, be); + bios = pflash_cfi01_get_memory(fl); + fl_idx++; + if (kernel_filename) { + /* Write a small bootloader to the flash location. */ + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + loaderparams.kernel_cmdline = kernel_cmdline; + loaderparams.initrd_filename = initrd_filename; + kernel_entry = load_kernel(); + write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry); + } else { + /* Load firmware from flash. */ + if (!dinfo) { + /* Load a BIOS image. */ + if (bios_name == NULL) { + bios_name = BIOS_FILENAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = load_image_targphys(filename, FLASH_ADDRESS, + BIOS_SIZE); + g_free(filename); + } else { + bios_size = -1; + } + if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { + fprintf(stderr, + "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", + bios_name); + exit(1); + } + } + /* In little endian mode the 32bit words in the bios are swapped, + a neat trick which allows bi-endian firmware. */ +#ifndef TARGET_WORDS_BIGENDIAN + { + uint32_t *addr = memory_region_get_ram_ptr(bios); + uint32_t *end = addr + bios_size; + while (addr < end) { + bswap32s(addr); + addr++; + } + } +#endif + } + + /* Map the BIOS at a 2nd physical location, as on the real board. */ + memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE); + memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias); + + /* Board ID = 0x420 (Malta Board with CoreLV) + XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should + map to the board ID. */ + stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420); + + /* Init internal devices */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + + /* + * We have a circular dependency problem: pci_bus depends on isa_irq, + * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends + * on piix4, and piix4 depends on pci_bus. To stop the cycle we have + * qemu_irq_proxy() adds an extra bit of indirection, allowing us + * to resolve the isa_irq -> i8259 dependency after i8259 is initialized. + */ + isa_irq = qemu_irq_proxy(&s->i8259, 16); + + /* Northbridge */ + pci_bus = gt64120_register(isa_irq); + + /* Southbridge */ + ide_drive_get(hd, MAX_IDE_BUS); + + piix4_devfn = piix4_init(pci_bus, &isa_bus, 80); + + /* Interrupt controller */ + /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ + s->i8259 = i8259_init(isa_bus, env->irq[2]); + + isa_bus_irqs(isa_bus, s->i8259); + pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1); + pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci"); + smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, + isa_get_irq(NULL, 9), NULL, 0, NULL); + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(smbus, 8, NULL, 0); + pit = pit_init(isa_bus, 0x40, 0, NULL); + cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); + DMA_init(0, cpu_exit_irq); + + /* Super I/O */ + isa_create_simple(isa_bus, "i8042"); + + rtc_init(isa_bus, 2000, NULL); + serial_isa_init(isa_bus, 0, serial_hds[0]); + serial_isa_init(isa_bus, 1, serial_hds[1]); + if (parallel_hds[0]) + parallel_init(isa_bus, 0, parallel_hds[0]); + for(i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); + } + fdctrl_init_isa(isa_bus, fd); + + /* Sound card */ + audio_init(isa_bus, pci_bus); + + /* Network card */ + network_init(); + + /* Optional PCI video card */ + pci_vga_init(pci_bus); +} + +static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev) +{ + return 0; +} + +static void mips_malta_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mips_malta_sysbus_device_init; +} + +static const TypeInfo mips_malta_device = { + .name = "mips-malta", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MaltaState), + .class_init = mips_malta_class_init, +}; + +static QEMUMachine mips_malta_machine = { + .name = "malta", + .desc = "MIPS Malta Core LV", + .init = mips_malta_init, + .max_cpus = 16, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void mips_malta_register_types(void) +{ + type_register_static(&mips_malta_device); +} + +static void mips_malta_machine_init(void) +{ + qemu_register_machine(&mips_malta_machine); +} + +type_init(mips_malta_register_types) +machine_init(mips_malta_machine_init); diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c new file mode 100644 index 0000000000..4935c78c01 --- /dev/null +++ b/hw/mips/mips_mipssim.c @@ -0,0 +1,240 @@ +/* + * QEMU/mipssim emulation + * + * Emulates a very simple machine model similar to the one used by the + * proprietary MIPS emulator. + * + * Copyright (c) 2007 Thiemo Seufer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/serial.h" +#include "hw/isa.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/mips-bios.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + +static struct _loaderparams { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + +typedef struct ResetData { + MIPSCPU *cpu; + uint64_t vector; +} ResetData; + +static int64_t load_kernel(void) +{ + int64_t entry, kernel_high; + long kernel_size; + long initrd_size; + ram_addr_t initrd_offset; + int big_endian; + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + + kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, + NULL, (uint64_t *)&entry, NULL, + (uint64_t *)&kernel_high, big_endian, + ELF_MACHINE, 1); + if (kernel_size >= 0) { + if ((entry & ~0x7fffffffULL) == 0x80000000) + entry = (int32_t)entry; + } else { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + loaderparams.kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + initrd_offset = 0; + if (loaderparams.initrd_filename) { + initrd_size = get_image_size (loaderparams.initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > loaderparams.ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + initrd_size = load_image_targphys(loaderparams.initrd_filename, + initrd_offset, loaderparams.ram_size - initrd_offset); + } + if (initrd_size == (target_ulong) -1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + } + return entry; +} + +static void main_cpu_reset(void *opaque) +{ + ResetData *s = (ResetData *)opaque; + CPUMIPSState *env = &s->cpu->env; + + cpu_reset(CPU(s->cpu)); + env->active_tc.PC = s->vector & ~(target_ulong)1; + if (s->vector & 1) { + env->hflags |= MIPS_HFLAG_M16; + } +} + +static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "mipsnet"); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, irq); + memory_region_add_subregion(get_system_io(), + base, + sysbus_mmio_get_region(s, 0)); +} + +static void +mips_mipssim_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + char *filename; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios = g_new(MemoryRegion, 1); + MIPSCPU *cpu; + CPUMIPSState *env; + ResetData *reset_info; + int bios_size; + + /* Init CPUs. */ + if (cpu_model == NULL) { +#ifdef TARGET_MIPS64 + cpu_model = "5Kf"; +#else + cpu_model = "24Kf"; +#endif + } + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + reset_info = g_malloc0(sizeof(ResetData)); + reset_info->cpu = cpu; + reset_info->vector = env->active_tc.PC; + qemu_register_reset(main_cpu_reset, reset_info); + + /* Allocate RAM. */ + memory_region_init_ram(ram, "mips_mipssim.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_init_ram(bios, "mips_mipssim.bios", BIOS_SIZE); + vmstate_register_ram_global(bios); + memory_region_set_readonly(bios, true); + + memory_region_add_subregion(address_space_mem, 0, ram); + + /* Map the BIOS / boot exception handler. */ + memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); + /* Load a BIOS / boot exception handler image. */ + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE); + g_free(filename); + } else { + bios_size = -1; + } + if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { + /* Bail out if we have neither a kernel image nor boot vector code. */ + fprintf(stderr, + "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", + filename); + exit(1); + } else { + /* We have a boot vector start address. */ + env->active_tc.PC = (target_long)(int32_t)0xbfc00000; + } + + if (kernel_filename) { + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + loaderparams.kernel_cmdline = kernel_cmdline; + loaderparams.initrd_filename = initrd_filename; + reset_info->vector = load_kernel(); + } + + /* Init CPU internal devices. */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + + /* Register 64 KB of ISA IO space at 0x1fd00000. */ + isa_mmio_init(0x1fd00000, 0x00010000); + + /* A single 16450 sits at offset 0x3f8. It is attached to + MIPS CPU INT2, which is interrupt 4. */ + if (serial_hds[0]) + serial_init(0x3f8, env->irq[4], 115200, serial_hds[0], + get_system_io()); + + if (nd_table[0].used) + /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ + mipsnet_init(0x4200, env->irq[2], &nd_table[0]); +} + +static QEMUMachine mips_mipssim_machine = { + .name = "mipssim", + .desc = "MIPS MIPSsim platform", + .init = mips_mipssim_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void mips_mipssim_machine_init(void) +{ + qemu_register_machine(&mips_mipssim_machine); +} + +machine_init(mips_mipssim_machine_init); diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c new file mode 100644 index 0000000000..539a562620 --- /dev/null +++ b/hw/mips/mips_r4k.c @@ -0,0 +1,313 @@ +/* + * QEMU/MIPS pseudo-board + * + * emulates a simple machine with ISA-like bus. + * ISA IO space mapped to the 0x14000000 (PHYS) and + * ISA memory at the 0x10000000 (PHYS, 16Mb in size). + * All peripherial devices are attached to this "bus" with + * the standard PC ISA addresses. +*/ +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/isa.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/flash.h" +#include "qemu/log.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#define MAX_IDE_BUS 2 + +static const int ide_iobase[2] = { 0x1f0, 0x170 }; +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; +static const int ide_irq[2] = { 14, 15 }; + +static ISADevice *pit; /* PIT i8254 */ + +/* i8254 PIT is attached to the IRQ0 at PIC i8259 */ + +static struct _loaderparams { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + +static void mips_qemu_write (void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + if ((addr & 0xffff) == 0 && val == 42) + qemu_system_reset_request (); + else if ((addr & 0xffff) == 4 && val == 42) + qemu_system_shutdown_request (); +} + +static uint64_t mips_qemu_read (void *opaque, hwaddr addr, + unsigned size) +{ + return 0; +} + +static const MemoryRegionOps mips_qemu_ops = { + .read = mips_qemu_read, + .write = mips_qemu_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +typedef struct ResetData { + MIPSCPU *cpu; + uint64_t vector; +} ResetData; + +static int64_t load_kernel(void) +{ + int64_t entry, kernel_high; + long kernel_size, initrd_size, params_size; + ram_addr_t initrd_offset; + uint32_t *params_buf; + int big_endian; + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, + NULL, (uint64_t *)&entry, NULL, + (uint64_t *)&kernel_high, big_endian, + ELF_MACHINE, 1); + if (kernel_size >= 0) { + if ((entry & ~0x7fffffffULL) == 0x80000000) + entry = (int32_t)entry; + } else { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + loaderparams.kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + initrd_offset = 0; + if (loaderparams.initrd_filename) { + initrd_size = get_image_size (loaderparams.initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + initrd_size = load_image_targphys(loaderparams.initrd_filename, + initrd_offset, + ram_size - initrd_offset); + } + if (initrd_size == (target_ulong) -1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + loaderparams.initrd_filename); + exit(1); + } + } + + /* Store command line. */ + params_size = 264; + params_buf = g_malloc(params_size); + + params_buf[0] = tswap32(ram_size); + params_buf[1] = tswap32(0x12345678); + + if (initrd_size > 0) { + snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s", + cpu_mips_phys_to_kseg0(NULL, initrd_offset), + initrd_size, loaderparams.kernel_cmdline); + } else { + snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline); + } + + rom_add_blob_fixed("params", params_buf, params_size, + (16 << 20) - 264); + + return entry; +} + +static void main_cpu_reset(void *opaque) +{ + ResetData *s = (ResetData *)opaque; + CPUMIPSState *env = &s->cpu->env; + + cpu_reset(CPU(s->cpu)); + env->active_tc.PC = s->vector; +} + +static const int sector_len = 32 * 1024; +static +void mips_r4k_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + char *filename; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *bios; + MemoryRegion *iomem = g_new(MemoryRegion, 1); + int bios_size; + MIPSCPU *cpu; + CPUMIPSState *env; + ResetData *reset_info; + int i; + qemu_irq *i8259; + ISABus *isa_bus; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + DriveInfo *dinfo; + int be; + + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_MIPS64 + cpu_model = "R4000"; +#else + cpu_model = "24Kf"; +#endif + } + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + reset_info = g_malloc0(sizeof(ResetData)); + reset_info->cpu = cpu; + reset_info->vector = env->active_tc.PC; + qemu_register_reset(main_cpu_reset, reset_info); + + /* allocate RAM */ + if (ram_size > (256 << 20)) { + fprintf(stderr, + "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n", + ((unsigned int)ram_size / (1 << 20))); + exit(1); + } + memory_region_init_ram(ram, "mips_r4k.ram", ram_size); + vmstate_register_ram_global(ram); + + memory_region_add_subregion(address_space_mem, 0, ram); + + memory_region_init_io(iomem, &mips_qemu_ops, NULL, "mips-qemu", 0x10000); + memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem); + + /* Try to load a BIOS image. If this fails, we continue regardless, + but initialize the hardware ourselves. When a kernel gets + preloaded we also initialize the hardware, since the BIOS wasn't + run. */ + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = get_image_size(filename); + } else { + bios_size = -1; + } +#ifdef TARGET_WORDS_BIGENDIAN + be = 1; +#else + be = 0; +#endif + if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) { + bios = g_new(MemoryRegion, 1); + memory_region_init_ram(bios, "mips_r4k.bios", BIOS_SIZE); + vmstate_register_ram_global(bios); + memory_region_set_readonly(bios, true); + memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios); + + load_image_targphys(filename, 0x1fc00000, BIOS_SIZE); + } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) { + uint32_t mips_rom = 0x00400000; + if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom, + dinfo->bdrv, sector_len, + mips_rom / sector_len, + 4, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + } + } + else { + /* not fatal */ + fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", + bios_name); + } + if (filename) { + g_free(filename); + } + + if (kernel_filename) { + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + loaderparams.kernel_cmdline = kernel_cmdline; + loaderparams.initrd_filename = initrd_filename; + reset_info->vector = load_kernel(); + } + + /* Init CPU internal devices */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + + /* The PIC is attached to the MIPS CPU INT0 pin */ + isa_bus = isa_bus_new(NULL, get_system_io()); + i8259 = i8259_init(isa_bus, env->irq[2]); + isa_bus_irqs(isa_bus, i8259); + + rtc_init(isa_bus, 2000, NULL); + + /* Register 64 KB of ISA IO space at 0x14000000 */ + isa_mmio_init(0x14000000, 0x00010000); + isa_mem_base = 0x10000000; + + pit = pit_init(isa_bus, 0x40, 0, NULL); + + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_isa_init(isa_bus, i, serial_hds[i]); + } + } + + isa_vga_init(isa_bus); + + if (nd_table[0].used) + isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]); + + ide_drive_get(hd, MAX_IDE_BUS); + for(i = 0; i < MAX_IDE_BUS; i++) + isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i], + hd[MAX_IDE_DEVS * i], + hd[MAX_IDE_DEVS * i + 1]); + + isa_create_simple(isa_bus, "i8042"); +} + +static QEMUMachine mips_machine = { + .name = "mips", + .desc = "mips r4k platform", + .init = mips_r4k_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void mips_machine_init(void) +{ + qemu_register_machine(&mips_machine); +} + +machine_init(mips_machine_init); diff --git a/hw/mips_addr.c b/hw/mips_addr.c deleted file mode 100644 index cddc25cf3f..0000000000 --- a/hw/mips_addr.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * QEMU MIPS address translation support - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/mips_cpudevs.h" - -uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr) -{ - return addr & 0x7fffffffll; -} - -uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr) -{ - return addr | ~0x7fffffffll; -} diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c deleted file mode 100644 index 766aa9dfb5..0000000000 --- a/hw/mips_fulong2e.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * QEMU fulong 2e mini pc support - * - * Copyright (c) 2008 yajin (yajin@vm-kernel.org) - * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn) - * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com) - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -/* - * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz) - * http://www.linux-mips.org/wiki/Fulong - * - * Loongson 2e user manual: - * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf - */ - -#include "hw/hw.h" -#include "hw/pc.h" -#include "hw/serial.h" -#include "hw/fdc.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/smbus.h" -#include "block/block.h" -#include "hw/flash.h" -#include "hw/mips.h" -#include "hw/mips_cpudevs.h" -#include "hw/pci/pci.h" -#include "char/char.h" -#include "sysemu/sysemu.h" -#include "audio/audio.h" -#include "qemu/log.h" -#include "hw/loader.h" -#include "hw/mips-bios.h" -#include "hw/ide.h" -#include "elf.h" -#include "hw/vt82c686.h" -#include "hw/mc146818rtc.h" -#include "hw/i8254.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#define DEBUG_FULONG2E_INIT - -#define ENVP_ADDR 0x80002000l -#define ENVP_NB_ENTRIES 16 -#define ENVP_ENTRY_SIZE 256 - -#define MAX_IDE_BUS 2 - -/* - * PMON is not part of qemu and released with BSD license, anyone - * who want to build a pmon binary please first git-clone the source - * from the git repository at: - * http://www.loongson.cn/support/git/pmon - * Then follow the "Compile Guide" available at: - * http://dev.lemote.com/code/pmon - * - * Notes: - * 1, don't use the source at http://dev.lemote.com/http_git/pmon.git - * 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware" - * in the "Compile Guide". - */ -#define FULONG_BIOSNAME "pmon_fulong2e.bin" - -/* PCI SLOT in fulong 2e */ -#define FULONG2E_VIA_SLOT 5 -#define FULONG2E_ATI_SLOT 6 -#define FULONG2E_RTL8139_SLOT 7 - -static ISADevice *pit; - -static struct _loaderparams { - int ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; -} loaderparams; - -static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, - const char *string, ...) -{ - va_list ap; - int32_t table_addr; - - if (index >= ENVP_NB_ENTRIES) - return; - - if (string == NULL) { - prom_buf[index] = 0; - return; - } - - table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; - prom_buf[index] = tswap32(ENVP_ADDR + table_addr); - - va_start(ap, string); - vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap); - va_end(ap); -} - -static int64_t load_kernel (CPUMIPSState *env) -{ - int64_t kernel_entry, kernel_low, kernel_high; - int index = 0; - long initrd_size; - ram_addr_t initrd_offset; - uint32_t *prom_buf; - long prom_size; - - if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL, - (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low, - (uint64_t *)&kernel_high, 0, ELF_MACHINE, 1) < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - loaderparams.kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - initrd_offset = 0; - if (loaderparams.initrd_filename) { - initrd_size = get_image_size (loaderparams.initrd_filename); - if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - initrd_size = load_image_targphys(loaderparams.initrd_filename, - initrd_offset, ram_size - initrd_offset); - } - if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - } - - /* Setup prom parameters. */ - prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE); - prom_buf = g_malloc(prom_size); - - prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename); - if (initrd_size > 0) { - prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", - cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, - loaderparams.kernel_cmdline); - } else { - prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline); - } - - /* Setup minimum environment variables */ - prom_set(prom_buf, index++, "busclock=33000000"); - prom_set(prom_buf, index++, "cpuclock=100000000"); - prom_set(prom_buf, index++, "memsize=%i", loaderparams.ram_size/1024/1024); - prom_set(prom_buf, index++, "modetty0=38400n8r"); - prom_set(prom_buf, index++, NULL); - - rom_add_blob_fixed("prom", prom_buf, prom_size, - cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR)); - - return kernel_entry; -} - -static void write_bootloader (CPUMIPSState *env, uint8_t *base, int64_t kernel_addr) -{ - uint32_t *p; - - /* Small bootloader */ - p = (uint32_t *) base; - - stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */ - stl_raw(p++, 0x00000000); /* nop */ - - /* Second part of the bootloader */ - p = (uint32_t *) (base + 0x040); - - stl_raw(p++, 0x3c040000); /* lui a0, 0 */ - stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */ - stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ - stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ - stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ - stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ - stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(env->ram_size) */ - stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ - stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */; - stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */ - stl_raw(p++, 0x03e00008); /* jr ra */ - stl_raw(p++, 0x00000000); /* nop */ -} - - -static void main_cpu_reset(void *opaque) -{ - MIPSCPU *cpu = opaque; - CPUMIPSState *env = &cpu->env; - - cpu_reset(CPU(cpu)); - /* TODO: 2E reset stuff */ - if (loaderparams.kernel_filename) { - env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); - } -} - -uint8_t eeprom_spd[0x80] = { - 0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70, - 0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01, - 0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50, - 0x2d,0x20,0xb0,0xb0,0x50,0x50,0x00,0x00,0x00,0x00, - 0x00,0x41,0x48,0x3c,0x32,0x75,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x9c,0x7b,0x07,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x48,0x42,0x35,0x34,0x41,0x32, - 0x35,0x36,0x38,0x4b,0x4e,0x2d,0x41,0x37,0x35,0x42, - 0x20,0x30,0x20 -}; - -/* Audio support */ -static void audio_init (PCIBus *pci_bus) -{ - vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5)); - vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6)); -} - -/* Network support */ -static void network_init (void) -{ - int i; - - for(i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - const char *default_devaddr = NULL; - - if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) { - /* The fulong board has a RTL8139 card using PCI SLOT 7 */ - default_devaddr = "07"; - } - - pci_nic_init_nofail(nd, "rtl8139", default_devaddr); - } -} - -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUMIPSState *env = cpu_single_env; - - if (env && level) { - cpu_exit(env); - } -} - -static void mips_fulong2e_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - char *filename; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *bios = g_new(MemoryRegion, 1); - long bios_size; - int64_t kernel_entry; - qemu_irq *i8259; - qemu_irq *cpu_exit_irq; - PCIBus *pci_bus; - ISABus *isa_bus; - i2c_bus *smbus; - int i; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - MIPSCPU *cpu; - CPUMIPSState *env; - - /* init CPUs */ - if (cpu_model == NULL) { - cpu_model = "Loongson-2E"; - } - cpu = cpu_mips_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - qemu_register_reset(main_cpu_reset, cpu); - - /* fulong 2e has 256M ram. */ - ram_size = 256 * 1024 * 1024; - - /* fulong 2e has a 1M flash.Winbond W39L040AP70Z */ - bios_size = 1024 * 1024; - - /* allocate RAM */ - memory_region_init_ram(ram, "fulong2e.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_init_ram(bios, "fulong2e.bios", bios_size); - vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); - - memory_region_add_subregion(address_space_mem, 0, ram); - memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); - - /* We do not support flash operation, just loading pmon.bin as raw BIOS. - * Please use -L to set the BIOS path and -bios to set bios name. */ - - if (kernel_filename) { - loaderparams.ram_size = ram_size; - loaderparams.kernel_filename = kernel_filename; - loaderparams.kernel_cmdline = kernel_cmdline; - loaderparams.initrd_filename = initrd_filename; - kernel_entry = load_kernel (env); - write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry); - } else { - if (bios_name == NULL) { - bios_name = FULONG_BIOSNAME; - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = load_image_targphys(filename, 0x1fc00000LL, - BIOS_SIZE); - g_free(filename); - } else { - bios_size = -1; - } - - if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { - fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name); - exit(1); - } - } - - /* Init internal devices */ - cpu_mips_irq_init_cpu(env); - cpu_mips_clock_init(env); - - /* North bridge, Bonito --> IP2 */ - pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); - - /* South bridge */ - ide_drive_get(hd, MAX_IDE_BUS); - - isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); - if (!isa_bus) { - fprintf(stderr, "vt82c686b_init error\n"); - exit(1); - } - - /* Interrupt controller */ - /* The 8259 -> IP5 */ - i8259 = i8259_init(isa_bus, env->irq[5]); - isa_bus_irqs(isa_bus, i8259); - - vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1)); - pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2), - "vt82c686b-usb-uhci"); - pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3), - "vt82c686b-usb-uhci"); - - smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4), - 0xeee1, NULL); - /* TODO: Populate SPD eeprom data. */ - smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); - - /* init other devices */ - pit = pit_init(isa_bus, 0x40, 0, NULL); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); - - /* Super I/O */ - isa_create_simple(isa_bus, "i8042"); - - rtc_init(isa_bus, 2000, NULL); - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - - if (parallel_hds[0]) { - parallel_init(isa_bus, 0, parallel_hds[0]); - } - - /* Sound card */ - audio_init(pci_bus); - /* Network card */ - network_init(); -} - -static QEMUMachine mips_fulong2e_machine = { - .name = "fulong2e", - .desc = "Fulong 2e mini pc", - .init = mips_fulong2e_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void mips_fulong2e_machine_init(void) -{ - qemu_register_machine(&mips_fulong2e_machine); -} - -machine_init(mips_fulong2e_machine_init); diff --git a/hw/mips_int.c b/hw/mips_int.c deleted file mode 100644 index ddd3b1bb01..0000000000 --- a/hw/mips_int.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * QEMU MIPS interrupt support - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/mips_cpudevs.h" -#include "cpu.h" - -static void cpu_mips_irq_request(void *opaque, int irq, int level) -{ - CPUMIPSState *env = (CPUMIPSState *)opaque; - - if (irq < 0 || irq > 7) - return; - - if (level) { - env->CP0_Cause |= 1 << (irq + CP0Ca_IP); - } else { - env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); - } - - if (env->CP0_Cause & CP0Ca_IP_mask) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -void cpu_mips_irq_init_cpu(CPUMIPSState *env) -{ - qemu_irq *qi; - int i; - - qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8); - for (i = 0; i < 8; i++) { - env->irq[i] = qi[i]; - } -} - -void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level) -{ - if (irq < 0 || irq > 2) { - return; - } - - qemu_set_irq(env->irq[irq], level); -} diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c deleted file mode 100644 index daeb985b1d..0000000000 --- a/hw/mips_jazz.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * QEMU MIPS Jazz support - * - * Copyright (c) 2007-2008 Hervé Poussineau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/mips.h" -#include "hw/mips_cpudevs.h" -#include "hw/pc.h" -#include "hw/serial.h" -#include "hw/isa.h" -#include "hw/fdc.h" -#include "sysemu/sysemu.h" -#include "sysemu/arch_init.h" -#include "hw/boards.h" -#include "net/net.h" -#include "hw/esp.h" -#include "hw/mips-bios.h" -#include "hw/loader.h" -#include "hw/mc146818rtc.h" -#include "hw/i8254.h" -#include "hw/pcspk.h" -#include "sysemu/blockdev.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -enum jazz_model_e -{ - JAZZ_MAGNUM, - JAZZ_PICA61, -}; - -static void main_cpu_reset(void *opaque) -{ - MIPSCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size) -{ - return cpu_inw(0x71); -} - -static void rtc_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - cpu_outw(0x71, val & 0xff); -} - -static const MemoryRegionOps rtc_ops = { - .read = rtc_read, - .write = rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static uint64_t dma_dummy_read(void *opaque, hwaddr addr, - unsigned size) -{ - /* Nothing to do. That is only to ensure that - * the current DMA acknowledge cycle is completed. */ - return 0xff; -} - -static void dma_dummy_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - /* Nothing to do. That is only to ensure that - * the current DMA acknowledge cycle is completed. */ -} - -static const MemoryRegionOps dma_dummy_ops = { - .read = dma_dummy_read, - .write = dma_dummy_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -#define MAGNUM_BIOS_SIZE_MAX 0x7e000 -#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX) - -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUMIPSState *env = cpu_single_env; - - if (env && level) { - cpu_exit(env); - } -} - -static void mips_jazz_init(MemoryRegion *address_space, - MemoryRegion *address_space_io, - ram_addr_t ram_size, - const char *cpu_model, - enum jazz_model_e jazz_model) -{ - char *filename; - int bios_size, n; - MIPSCPU *cpu; - CPUMIPSState *env; - qemu_irq *rc4030, *i8259; - rc4030_dma *dmas; - void* rc4030_opaque; - MemoryRegion *rtc = g_new(MemoryRegion, 1); - MemoryRegion *i8042 = g_new(MemoryRegion, 1); - MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); - NICInfo *nd; - DeviceState *dev; - SysBusDevice *sysbus; - ISABus *isa_bus; - ISADevice *pit; - DriveInfo *fds[MAX_FD]; - qemu_irq esp_reset, dma_enable; - qemu_irq *cpu_exit_irq; - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *bios = g_new(MemoryRegion, 1); - MemoryRegion *bios2 = g_new(MemoryRegion, 1); - - /* init CPUs */ - if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 - cpu_model = "R4000"; -#else - /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */ - cpu_model = "24Kf"; -#endif - } - cpu = cpu_mips_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - qemu_register_reset(main_cpu_reset, cpu); - - /* allocate RAM */ - memory_region_init_ram(ram, "mips_jazz.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space, 0, ram); - - memory_region_init_ram(bios, "mips_jazz.bios", MAGNUM_BIOS_SIZE); - vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); - memory_region_init_alias(bios2, "mips_jazz.bios", bios, - 0, MAGNUM_BIOS_SIZE); - memory_region_add_subregion(address_space, 0x1fc00000LL, bios); - memory_region_add_subregion(address_space, 0xfff00000LL, bios2); - - /* load the BIOS image. */ - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = load_image_targphys(filename, 0xfff00000LL, - MAGNUM_BIOS_SIZE); - g_free(filename); - } else { - bios_size = -1; - } - if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) { - fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", - bios_name); - exit(1); - } - - /* Init CPU internal devices */ - cpu_mips_irq_init_cpu(env); - cpu_mips_clock_init(env); - - /* Chipset */ - rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas, - address_space); - memory_region_init_io(dma_dummy, &dma_dummy_ops, NULL, "dummy_dma", 0x1000); - memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); - - /* ISA devices */ - isa_bus = isa_bus_new(NULL, address_space_io); - i8259 = i8259_init(isa_bus, env->irq[4]); - isa_bus_irqs(isa_bus, i8259); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); - pit = pit_init(isa_bus, 0x40, 0, NULL); - pcspk_init(isa_bus, pit); - - /* ISA IO space at 0x90000000 */ - isa_mmio_init(0x90000000, 0x01000000); - isa_mem_base = 0x11000000; - - /* Video card */ - switch (jazz_model) { - case JAZZ_MAGNUM: - dev = qdev_create(NULL, "sysbus-g364"); - qdev_init_nofail(dev); - sysbus = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(sysbus, 0, 0x60080000); - sysbus_mmio_map(sysbus, 1, 0x40000000); - sysbus_connect_irq(sysbus, 0, rc4030[3]); - { - /* Simple ROM, so user doesn't have to provide one */ - MemoryRegion *rom_mr = g_new(MemoryRegion, 1); - memory_region_init_ram(rom_mr, "g364fb.rom", 0x80000); - vmstate_register_ram_global(rom_mr); - memory_region_set_readonly(rom_mr, true); - uint8_t *rom = memory_region_get_ram_ptr(rom_mr); - memory_region_add_subregion(address_space, 0x60000000, rom_mr); - rom[0] = 0x10; /* Mips G364 */ - } - break; - case JAZZ_PICA61: - isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory()); - break; - default: - break; - } - - /* Network controller */ - for (n = 0; n < nb_nics; n++) { - nd = &nd_table[n]; - if (!nd->model) - nd->model = g_strdup("dp83932"); - if (strcmp(nd->model, "dp83932") == 0) { - dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4], - rc4030_opaque, rc4030_dma_memory_rw); - break; - } else if (is_help_option(nd->model)) { - fprintf(stderr, "qemu: Supported NICs: dp83932\n"); - exit(1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); - exit(1); - } - } - - /* SCSI adapter */ - esp_init(0x80002000, 0, - rc4030_dma_read, rc4030_dma_write, dmas[0], - rc4030[5], &esp_reset, &dma_enable); - - /* Floppy */ - if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) { - fprintf(stderr, "qemu: too many floppy drives\n"); - exit(1); - } - for (n = 0; n < MAX_FD; n++) { - fds[n] = drive_get(IF_FLOPPY, 0, n); - } - fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds); - - /* Real time clock */ - rtc_init(isa_bus, 1980, NULL); - memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000); - memory_region_add_subregion(address_space, 0x80004000, rtc); - - /* Keyboard (i8042) */ - i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1); - memory_region_add_subregion(address_space, 0x80005000, i8042); - - /* Serial ports */ - if (serial_hds[0]) { - serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16, - serial_hds[0], DEVICE_NATIVE_ENDIAN); - } - if (serial_hds[1]) { - serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16, - serial_hds[1], DEVICE_NATIVE_ENDIAN); - } - - /* Parallel port */ - if (parallel_hds[0]) - parallel_mm_init(address_space, 0x80008000, 0, rc4030[0], - parallel_hds[0]); - - /* Sound card */ - /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ - audio_init(isa_bus, NULL); - - /* NVRAM */ - dev = qdev_create(NULL, "ds1225y"); - qdev_init_nofail(dev); - sysbus = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(sysbus, 0, 0x80009000); - - /* LED indicator */ - sysbus_create_simple("jazz-led", 0x8000f000, NULL); -} - -static -void mips_magnum_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - mips_jazz_init(get_system_memory(), get_system_io(), - ram_size, cpu_model, JAZZ_MAGNUM); -} - -static -void mips_pica61_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - mips_jazz_init(get_system_memory(), get_system_io(), - ram_size, cpu_model, JAZZ_PICA61); -} - -static QEMUMachine mips_magnum_machine = { - .name = "magnum", - .desc = "MIPS Magnum", - .init = mips_magnum_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine mips_pica61_machine = { - .name = "pica61", - .desc = "Acer Pica 61", - .init = mips_pica61_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static void mips_jazz_machine_init(void) -{ - qemu_register_machine(&mips_magnum_machine); - qemu_register_machine(&mips_pica61_machine); -} - -machine_init(mips_jazz_machine_init); diff --git a/hw/mips_malta.c b/hw/mips_malta.c deleted file mode 100644 index 9a67dce207..0000000000 --- a/hw/mips_malta.c +++ /dev/null @@ -1,1037 +0,0 @@ -/* - * QEMU Malta board support - * - * Copyright (c) 2006 Aurelien Jarno - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/pc.h" -#include "hw/serial.h" -#include "hw/fdc.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/smbus.h" -#include "block/block.h" -#include "hw/flash.h" -#include "hw/mips.h" -#include "hw/mips_cpudevs.h" -#include "hw/pci/pci.h" -#include "char/char.h" -#include "sysemu/sysemu.h" -#include "sysemu/arch_init.h" -#include "hw/boards.h" -#include "qemu/log.h" -#include "hw/mips-bios.h" -#include "hw/ide.h" -#include "hw/loader.h" -#include "elf.h" -#include "hw/mc146818rtc.h" -#include "hw/i8254.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" -#include "hw/sysbus.h" /* SysBusDevice */ - -//#define DEBUG_BOARD_INIT - -#define ENVP_ADDR 0x80002000l -#define ENVP_NB_ENTRIES 16 -#define ENVP_ENTRY_SIZE 256 - -/* Hardware addresses */ -#define FLASH_ADDRESS 0x1e000000ULL -#define FPGA_ADDRESS 0x1f000000ULL -#define RESET_ADDRESS 0x1fc00000ULL - -#define FLASH_SIZE 0x400000 - -#define MAX_IDE_BUS 2 - -typedef struct { - MemoryRegion iomem; - MemoryRegion iomem_lo; /* 0 - 0x900 */ - MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */ - uint32_t leds; - uint32_t brk; - uint32_t gpout; - uint32_t i2cin; - uint32_t i2coe; - uint32_t i2cout; - uint32_t i2csel; - CharDriverState *display; - char display_text[9]; - SerialState *uart; -} MaltaFPGAState; - -typedef struct { - SysBusDevice busdev; - qemu_irq *i8259; -} MaltaState; - -static ISADevice *pit; - -static struct _loaderparams { - int ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; -} loaderparams; - -/* Malta FPGA */ -static void malta_fpga_update_display(void *opaque) -{ - char leds_text[9]; - int i; - MaltaFPGAState *s = opaque; - - for (i = 7 ; i >= 0 ; i--) { - if (s->leds & (1 << i)) - leds_text[i] = '#'; - else - leds_text[i] = ' '; - } - leds_text[8] = '\0'; - - qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); - qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); -} - -/* - * EEPROM 24C01 / 24C02 emulation. - * - * Emulation for serial EEPROMs: - * 24C01 - 1024 bit (128 x 8) - * 24C02 - 2048 bit (256 x 8) - * - * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02. - */ - -//~ #define DEBUG - -#if defined(DEBUG) -# define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__) -#else -# define logout(fmt, ...) ((void)0) -#endif - -struct _eeprom24c0x_t { - uint8_t tick; - uint8_t address; - uint8_t command; - uint8_t ack; - uint8_t scl; - uint8_t sda; - uint8_t data; - //~ uint16_t size; - uint8_t contents[256]; -}; - -typedef struct _eeprom24c0x_t eeprom24c0x_t; - -static eeprom24c0x_t eeprom = { - .contents = { - /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00, - /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01, - /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00, - /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40, - /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00, - /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0, - /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4, - }, -}; - -static uint8_t eeprom24c0x_read(void) -{ - logout("%u: scl = %u, sda = %u, data = 0x%02x\n", - eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data); - return eeprom.sda; -} - -static void eeprom24c0x_write(int scl, int sda) -{ - if (eeprom.scl && scl && (eeprom.sda != sda)) { - logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n", - eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start"); - if (!sda) { - eeprom.tick = 1; - eeprom.command = 0; - } - } else if (eeprom.tick == 0 && !eeprom.ack) { - /* Waiting for start. */ - logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n", - eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); - } else if (!eeprom.scl && scl) { - logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n", - eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); - if (eeprom.ack) { - logout("\ti2c ack bit = 0\n"); - sda = 0; - eeprom.ack = 0; - } else if (eeprom.sda == sda) { - uint8_t bit = (sda != 0); - logout("\ti2c bit = %d\n", bit); - if (eeprom.tick < 9) { - eeprom.command <<= 1; - eeprom.command += bit; - eeprom.tick++; - if (eeprom.tick == 9) { - logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write"); - eeprom.ack = 1; - } - } else if (eeprom.tick < 17) { - if (eeprom.command & 1) { - sda = ((eeprom.data & 0x80) != 0); - } - eeprom.address <<= 1; - eeprom.address += bit; - eeprom.tick++; - eeprom.data <<= 1; - if (eeprom.tick == 17) { - eeprom.data = eeprom.contents[eeprom.address]; - logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data); - eeprom.ack = 1; - eeprom.tick = 0; - } - } else if (eeprom.tick >= 17) { - sda = 0; - } - } else { - logout("\tsda changed with raising scl\n"); - } - } else { - logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); - } - eeprom.scl = scl; - eeprom.sda = sda; -} - -static uint64_t malta_fpga_read(void *opaque, hwaddr addr, - unsigned size) -{ - MaltaFPGAState *s = opaque; - uint32_t val = 0; - uint32_t saddr; - - saddr = (addr & 0xfffff); - - switch (saddr) { - - /* SWITCH Register */ - case 0x00200: - val = 0x00000000; /* All switches closed */ - break; - - /* STATUS Register */ - case 0x00208: -#ifdef TARGET_WORDS_BIGENDIAN - val = 0x00000012; -#else - val = 0x00000010; -#endif - break; - - /* JMPRS Register */ - case 0x00210: - val = 0x00; - break; - - /* LEDBAR Register */ - case 0x00408: - val = s->leds; - break; - - /* BRKRES Register */ - case 0x00508: - val = s->brk; - break; - - /* UART Registers are handled directly by the serial device */ - - /* GPOUT Register */ - case 0x00a00: - val = s->gpout; - break; - - /* XXX: implement a real I2C controller */ - - /* GPINP Register */ - case 0x00a08: - /* IN = OUT until a real I2C control is implemented */ - if (s->i2csel) - val = s->i2cout; - else - val = 0x00; - break; - - /* I2CINP Register */ - case 0x00b00: - val = ((s->i2cin & ~1) | eeprom24c0x_read()); - break; - - /* I2COE Register */ - case 0x00b08: - val = s->i2coe; - break; - - /* I2COUT Register */ - case 0x00b10: - val = s->i2cout; - break; - - /* I2CSEL Register */ - case 0x00b18: - val = s->i2csel; - break; - - default: -#if 0 - printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n", - addr); -#endif - break; - } - return val; -} - -static void malta_fpga_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MaltaFPGAState *s = opaque; - uint32_t saddr; - - saddr = (addr & 0xfffff); - - switch (saddr) { - - /* SWITCH Register */ - case 0x00200: - break; - - /* JMPRS Register */ - case 0x00210: - break; - - /* LEDBAR Register */ - case 0x00408: - s->leds = val & 0xff; - malta_fpga_update_display(s); - break; - - /* ASCIIWORD Register */ - case 0x00410: - snprintf(s->display_text, 9, "%08X", (uint32_t)val); - malta_fpga_update_display(s); - break; - - /* ASCIIPOS0 to ASCIIPOS7 Registers */ - case 0x00418: - case 0x00420: - case 0x00428: - case 0x00430: - case 0x00438: - case 0x00440: - case 0x00448: - case 0x00450: - s->display_text[(saddr - 0x00418) >> 3] = (char) val; - malta_fpga_update_display(s); - break; - - /* SOFTRES Register */ - case 0x00500: - if (val == 0x42) - qemu_system_reset_request (); - break; - - /* BRKRES Register */ - case 0x00508: - s->brk = val & 0xff; - break; - - /* UART Registers are handled directly by the serial device */ - - /* GPOUT Register */ - case 0x00a00: - s->gpout = val & 0xff; - break; - - /* I2COE Register */ - case 0x00b08: - s->i2coe = val & 0x03; - break; - - /* I2COUT Register */ - case 0x00b10: - eeprom24c0x_write(val & 0x02, val & 0x01); - s->i2cout = val; - break; - - /* I2CSEL Register */ - case 0x00b18: - s->i2csel = val & 0x01; - break; - - default: -#if 0 - printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n", - addr); -#endif - break; - } -} - -static const MemoryRegionOps malta_fpga_ops = { - .read = malta_fpga_read, - .write = malta_fpga_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void malta_fpga_reset(void *opaque) -{ - MaltaFPGAState *s = opaque; - - s->leds = 0x00; - s->brk = 0x0a; - s->gpout = 0x00; - s->i2cin = 0x3; - s->i2coe = 0x0; - s->i2cout = 0x3; - s->i2csel = 0x1; - - s->display_text[8] = '\0'; - snprintf(s->display_text, 9, " "); -} - -static void malta_fpga_led_init(CharDriverState *chr) -{ - qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n"); - qemu_chr_fe_printf(chr, "+--------+\r\n"); - qemu_chr_fe_printf(chr, "+ +\r\n"); - qemu_chr_fe_printf(chr, "+--------+\r\n"); - qemu_chr_fe_printf(chr, "\n"); - qemu_chr_fe_printf(chr, "Malta ASCII\r\n"); - qemu_chr_fe_printf(chr, "+--------+\r\n"); - qemu_chr_fe_printf(chr, "+ +\r\n"); - qemu_chr_fe_printf(chr, "+--------+\r\n"); -} - -static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space, - hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr) -{ - MaltaFPGAState *s; - - s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState)); - - memory_region_init_io(&s->iomem, &malta_fpga_ops, s, - "malta-fpga", 0x100000); - memory_region_init_alias(&s->iomem_lo, "malta-fpga", - &s->iomem, 0, 0x900); - memory_region_init_alias(&s->iomem_hi, "malta-fpga", - &s->iomem, 0xa00, 0x10000-0xa00); - - memory_region_add_subregion(address_space, base, &s->iomem_lo); - memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi); - - s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init); - - s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq, - 230400, uart_chr, DEVICE_NATIVE_ENDIAN); - - malta_fpga_reset(s); - qemu_register_reset(malta_fpga_reset, s); - - return s; -} - -/* Network support */ -static void network_init(void) -{ - int i; - - for(i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - const char *default_devaddr = NULL; - - if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0)) - /* The malta board has a PCNet card using PCI SLOT 11 */ - default_devaddr = "0b"; - - pci_nic_init_nofail(nd, "pcnet", default_devaddr); - } -} - -/* ROM and pseudo bootloader - - The following code implements a very very simple bootloader. It first - loads the registers a0 to a3 to the values expected by the OS, and - then jump at the kernel address. - - The bootloader should pass the locations of the kernel arguments and - environment variables tables. Those tables contain the 32-bit address - of NULL terminated strings. The environment variables table should be - terminated by a NULL address. - - For a simpler implementation, the number of kernel arguments is fixed - to two (the name of the kernel and the command line), and the two - tables are actually the same one. - - The registers a0 to a3 should contain the following values: - a0 - number of kernel arguments - a1 - 32-bit address of the kernel arguments table - a2 - 32-bit address of the environment variables table - a3 - RAM size in bytes -*/ - -static void write_bootloader (CPUMIPSState *env, uint8_t *base, - int64_t kernel_entry) -{ - uint32_t *p; - - /* Small bootloader */ - p = (uint32_t *)base; - stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */ - stl_raw(p++, 0x00000000); /* nop */ - - /* YAMON service vector */ - stl_raw(base + 0x500, 0xbfc00580); /* start: */ - stl_raw(base + 0x504, 0xbfc0083c); /* print_count: */ - stl_raw(base + 0x520, 0xbfc00580); /* start: */ - stl_raw(base + 0x52c, 0xbfc00800); /* flush_cache: */ - stl_raw(base + 0x534, 0xbfc00808); /* print: */ - stl_raw(base + 0x538, 0xbfc00800); /* reg_cpu_isr: */ - stl_raw(base + 0x53c, 0xbfc00800); /* unred_cpu_isr: */ - stl_raw(base + 0x540, 0xbfc00800); /* reg_ic_isr: */ - stl_raw(base + 0x544, 0xbfc00800); /* unred_ic_isr: */ - stl_raw(base + 0x548, 0xbfc00800); /* reg_esr: */ - stl_raw(base + 0x54c, 0xbfc00800); /* unreg_esr: */ - stl_raw(base + 0x550, 0xbfc00800); /* getchar: */ - stl_raw(base + 0x554, 0xbfc00800); /* syscon_read: */ - - - /* Second part of the bootloader */ - p = (uint32_t *) (base + 0x580); - stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */ - stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ - stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */ - stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ - stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */ - stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ - stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ - stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */ - stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */ - - /* Load BAR registers as done by YAMON */ - stl_raw(p++, 0x3c09b400); /* lui t1, 0xb400 */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c08df00); /* lui t0, 0xdf00 */ -#else - stl_raw(p++, 0x340800df); /* ori t0, r0, 0x00df */ -#endif - stl_raw(p++, 0xad280068); /* sw t0, 0x0068(t1) */ - - stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c08c000); /* lui t0, 0xc000 */ -#else - stl_raw(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */ -#endif - stl_raw(p++, 0xad280048); /* sw t0, 0x0048(t1) */ -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c084000); /* lui t0, 0x4000 */ -#else - stl_raw(p++, 0x34080040); /* ori t0, r0, 0x0040 */ -#endif - stl_raw(p++, 0xad280050); /* sw t0, 0x0050(t1) */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c088000); /* lui t0, 0x8000 */ -#else - stl_raw(p++, 0x34080080); /* ori t0, r0, 0x0080 */ -#endif - stl_raw(p++, 0xad280058); /* sw t0, 0x0058(t1) */ -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c083f00); /* lui t0, 0x3f00 */ -#else - stl_raw(p++, 0x3408003f); /* ori t0, r0, 0x003f */ -#endif - stl_raw(p++, 0xad280060); /* sw t0, 0x0060(t1) */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c08c100); /* lui t0, 0xc100 */ -#else - stl_raw(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */ -#endif - stl_raw(p++, 0xad280080); /* sw t0, 0x0080(t1) */ -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c085e00); /* lui t0, 0x5e00 */ -#else - stl_raw(p++, 0x3408005e); /* ori t0, r0, 0x005e */ -#endif - stl_raw(p++, 0xad280088); /* sw t0, 0x0088(t1) */ - - /* Jump to kernel code */ - stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */ - stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ - stl_raw(p++, 0x03e00008); /* jr ra */ - stl_raw(p++, 0x00000000); /* nop */ - - /* YAMON subroutines */ - p = (uint32_t *) (base + 0x800); - stl_raw(p++, 0x03e00008); /* jr ra */ - stl_raw(p++, 0x24020000); /* li v0,0 */ - /* 808 YAMON print */ - stl_raw(p++, 0x03e06821); /* move t5,ra */ - stl_raw(p++, 0x00805821); /* move t3,a0 */ - stl_raw(p++, 0x00a05021); /* move t2,a1 */ - stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ - stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ - stl_raw(p++, 0x10800005); /* beqz a0,834 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x0ff0021c); /* jal 870 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x08000205); /* j 814 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x01a00008); /* jr t5 */ - stl_raw(p++, 0x01602021); /* move a0,t3 */ - /* 0x83c YAMON print_count */ - stl_raw(p++, 0x03e06821); /* move t5,ra */ - stl_raw(p++, 0x00805821); /* move t3,a0 */ - stl_raw(p++, 0x00a05021); /* move t2,a1 */ - stl_raw(p++, 0x00c06021); /* move t4,a2 */ - stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ - stl_raw(p++, 0x0ff0021c); /* jal 870 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ - stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */ - stl_raw(p++, 0x1580fffa); /* bnez t4,84c */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x01a00008); /* jr t5 */ - stl_raw(p++, 0x01602021); /* move a0,t3 */ - /* 0x870 */ - stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */ - stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */ - stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */ - stl_raw(p++, 0x1120fffc); /* beqz t1,878 */ - stl_raw(p++, 0x00000000); /* nop */ - stl_raw(p++, 0x03e00008); /* jr ra */ - stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */ - -} - -static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, - const char *string, ...) -{ - va_list ap; - int32_t table_addr; - - if (index >= ENVP_NB_ENTRIES) - return; - - if (string == NULL) { - prom_buf[index] = 0; - return; - } - - table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; - prom_buf[index] = tswap32(ENVP_ADDR + table_addr); - - va_start(ap, string); - vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap); - va_end(ap); -} - -/* Kernel */ -static int64_t load_kernel (void) -{ - int64_t kernel_entry, kernel_high; - long initrd_size; - ram_addr_t initrd_offset; - int big_endian; - uint32_t *prom_buf; - long prom_size; - int prom_index = 0; - -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - - if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL, - (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high, - big_endian, ELF_MACHINE, 1) < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - loaderparams.kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - initrd_offset = 0; - if (loaderparams.initrd_filename) { - initrd_size = get_image_size (loaderparams.initrd_filename); - if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - initrd_size = load_image_targphys(loaderparams.initrd_filename, - initrd_offset, - ram_size - initrd_offset); - } - if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - } - - /* Setup prom parameters. */ - prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE); - prom_buf = g_malloc(prom_size); - - prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename); - if (initrd_size > 0) { - prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", - cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, - loaderparams.kernel_cmdline); - } else { - prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline); - } - - prom_set(prom_buf, prom_index++, "memsize"); - prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size); - prom_set(prom_buf, prom_index++, "modetty0"); - prom_set(prom_buf, prom_index++, "38400n8r"); - prom_set(prom_buf, prom_index++, NULL); - - rom_add_blob_fixed("prom", prom_buf, prom_size, - cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR)); - - return kernel_entry; -} - -static void malta_mips_config(MIPSCPU *cpu) -{ - CPUMIPSState *env = &cpu->env; - CPUState *cs = CPU(cpu); - - env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) | - ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC); -} - -static void main_cpu_reset(void *opaque) -{ - MIPSCPU *cpu = opaque; - CPUMIPSState *env = &cpu->env; - - cpu_reset(CPU(cpu)); - - /* The bootloader does not need to be rewritten as it is located in a - read only location. The kernel location and the arguments table - location does not change. */ - if (loaderparams.kernel_filename) { - env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); - } - - malta_mips_config(cpu); -} - -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUMIPSState *env = cpu_single_env; - - if (env && level) { - cpu_exit(env); - } -} - -static -void mips_malta_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - char *filename; - pflash_t *fl; - MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1); - target_long bios_size = FLASH_SIZE; - int64_t kernel_entry; - PCIBus *pci_bus; - ISABus *isa_bus; - MIPSCPU *cpu; - CPUMIPSState *env; - qemu_irq *isa_irq; - qemu_irq *cpu_exit_irq; - int piix4_devfn; - i2c_bus *smbus; - int i; - DriveInfo *dinfo; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DriveInfo *fd[MAX_FD]; - int fl_idx = 0; - int fl_sectors = bios_size >> 16; - int be; - - DeviceState *dev = qdev_create(NULL, "mips-malta"); - MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev); - - qdev_init_nofail(dev); - - /* Make sure the first 3 serial ports are associated with a device. */ - for(i = 0; i < 3; i++) { - if (!serial_hds[i]) { - char label[32]; - snprintf(label, sizeof(label), "serial%d", i); - serial_hds[i] = qemu_chr_new(label, "null", NULL); - } - } - - /* init CPUs */ - if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 - cpu_model = "20Kc"; -#else - cpu_model = "24Kf"; -#endif - } - - for (i = 0; i < smp_cpus; i++) { - cpu = cpu_mips_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - /* Init internal devices */ - cpu_mips_irq_init_cpu(env); - cpu_mips_clock_init(env); - qemu_register_reset(main_cpu_reset, cpu); - } - env = first_cpu; - - /* allocate RAM */ - if (ram_size > (256 << 20)) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n", - ((unsigned int)ram_size / (1 << 20))); - exit(1); - } - memory_region_init_ram(ram, "mips_malta.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(system_memory, 0, ram); - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - /* FPGA */ - /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */ - malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]); - - /* Load firmware in flash / BIOS. */ - dinfo = drive_get(IF_PFLASH, 0, fl_idx); -#ifdef DEBUG_BOARD_INIT - if (dinfo) { - printf("Register parallel flash %d size " TARGET_FMT_lx " at " - "addr %08llx '%s' %x\n", - fl_idx, bios_size, FLASH_ADDRESS, - bdrv_get_device_name(dinfo->bdrv), fl_sectors); - } -#endif - fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios", - BIOS_SIZE, dinfo ? dinfo->bdrv : NULL, - 65536, fl_sectors, - 4, 0x0000, 0x0000, 0x0000, 0x0000, be); - bios = pflash_cfi01_get_memory(fl); - fl_idx++; - if (kernel_filename) { - /* Write a small bootloader to the flash location. */ - loaderparams.ram_size = ram_size; - loaderparams.kernel_filename = kernel_filename; - loaderparams.kernel_cmdline = kernel_cmdline; - loaderparams.initrd_filename = initrd_filename; - kernel_entry = load_kernel(); - write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry); - } else { - /* Load firmware from flash. */ - if (!dinfo) { - /* Load a BIOS image. */ - if (bios_name == NULL) { - bios_name = BIOS_FILENAME; - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = load_image_targphys(filename, FLASH_ADDRESS, - BIOS_SIZE); - g_free(filename); - } else { - bios_size = -1; - } - if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { - fprintf(stderr, - "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", - bios_name); - exit(1); - } - } - /* In little endian mode the 32bit words in the bios are swapped, - a neat trick which allows bi-endian firmware. */ -#ifndef TARGET_WORDS_BIGENDIAN - { - uint32_t *addr = memory_region_get_ram_ptr(bios); - uint32_t *end = addr + bios_size; - while (addr < end) { - bswap32s(addr); - addr++; - } - } -#endif - } - - /* Map the BIOS at a 2nd physical location, as on the real board. */ - memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE); - memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias); - - /* Board ID = 0x420 (Malta Board with CoreLV) - XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should - map to the board ID. */ - stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420); - - /* Init internal devices */ - cpu_mips_irq_init_cpu(env); - cpu_mips_clock_init(env); - - /* - * We have a circular dependency problem: pci_bus depends on isa_irq, - * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends - * on piix4, and piix4 depends on pci_bus. To stop the cycle we have - * qemu_irq_proxy() adds an extra bit of indirection, allowing us - * to resolve the isa_irq -> i8259 dependency after i8259 is initialized. - */ - isa_irq = qemu_irq_proxy(&s->i8259, 16); - - /* Northbridge */ - pci_bus = gt64120_register(isa_irq); - - /* Southbridge */ - ide_drive_get(hd, MAX_IDE_BUS); - - piix4_devfn = piix4_init(pci_bus, &isa_bus, 80); - - /* Interrupt controller */ - /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ - s->i8259 = i8259_init(isa_bus, env->irq[2]); - - isa_bus_irqs(isa_bus, s->i8259); - pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1); - pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci"); - smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, - isa_get_irq(NULL, 9), NULL, 0, NULL); - /* TODO: Populate SPD eeprom data. */ - smbus_eeprom_init(smbus, 8, NULL, 0); - pit = pit_init(isa_bus, 0x40, 0, NULL); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); - - /* Super I/O */ - isa_create_simple(isa_bus, "i8042"); - - rtc_init(isa_bus, 2000, NULL); - serial_isa_init(isa_bus, 0, serial_hds[0]); - serial_isa_init(isa_bus, 1, serial_hds[1]); - if (parallel_hds[0]) - parallel_init(isa_bus, 0, parallel_hds[0]); - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - } - fdctrl_init_isa(isa_bus, fd); - - /* Sound card */ - audio_init(isa_bus, pci_bus); - - /* Network card */ - network_init(); - - /* Optional PCI video card */ - pci_vga_init(pci_bus); -} - -static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev) -{ - return 0; -} - -static void mips_malta_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mips_malta_sysbus_device_init; -} - -static const TypeInfo mips_malta_device = { - .name = "mips-malta", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MaltaState), - .class_init = mips_malta_class_init, -}; - -static QEMUMachine mips_malta_machine = { - .name = "malta", - .desc = "MIPS Malta Core LV", - .init = mips_malta_init, - .max_cpus = 16, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void mips_malta_register_types(void) -{ - type_register_static(&mips_malta_device); -} - -static void mips_malta_machine_init(void) -{ - qemu_register_machine(&mips_malta_machine); -} - -type_init(mips_malta_register_types) -machine_init(mips_malta_machine_init); diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c deleted file mode 100644 index 4935c78c01..0000000000 --- a/hw/mips_mipssim.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * QEMU/mipssim emulation - * - * Emulates a very simple machine model similar to the one used by the - * proprietary MIPS emulator. - * - * Copyright (c) 2007 Thiemo Seufer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/mips.h" -#include "hw/mips_cpudevs.h" -#include "hw/serial.h" -#include "hw/isa.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/mips-bios.h" -#include "hw/loader.h" -#include "elf.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -static struct _loaderparams { - int ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; -} loaderparams; - -typedef struct ResetData { - MIPSCPU *cpu; - uint64_t vector; -} ResetData; - -static int64_t load_kernel(void) -{ - int64_t entry, kernel_high; - long kernel_size; - long initrd_size; - ram_addr_t initrd_offset; - int big_endian; - -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - - kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, - NULL, (uint64_t *)&entry, NULL, - (uint64_t *)&kernel_high, big_endian, - ELF_MACHINE, 1); - if (kernel_size >= 0) { - if ((entry & ~0x7fffffffULL) == 0x80000000) - entry = (int32_t)entry; - } else { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - loaderparams.kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - initrd_offset = 0; - if (loaderparams.initrd_filename) { - initrd_size = get_image_size (loaderparams.initrd_filename); - if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > loaderparams.ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - initrd_size = load_image_targphys(loaderparams.initrd_filename, - initrd_offset, loaderparams.ram_size - initrd_offset); - } - if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - } - return entry; -} - -static void main_cpu_reset(void *opaque) -{ - ResetData *s = (ResetData *)opaque; - CPUMIPSState *env = &s->cpu->env; - - cpu_reset(CPU(s->cpu)); - env->active_tc.PC = s->vector & ~(target_ulong)1; - if (s->vector & 1) { - env->hflags |= MIPS_HFLAG_M16; - } -} - -static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "mipsnet"); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, irq); - memory_region_add_subregion(get_system_io(), - base, - sysbus_mmio_get_region(s, 0)); -} - -static void -mips_mipssim_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - char *filename; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *bios = g_new(MemoryRegion, 1); - MIPSCPU *cpu; - CPUMIPSState *env; - ResetData *reset_info; - int bios_size; - - /* Init CPUs. */ - if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 - cpu_model = "5Kf"; -#else - cpu_model = "24Kf"; -#endif - } - cpu = cpu_mips_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - reset_info = g_malloc0(sizeof(ResetData)); - reset_info->cpu = cpu; - reset_info->vector = env->active_tc.PC; - qemu_register_reset(main_cpu_reset, reset_info); - - /* Allocate RAM. */ - memory_region_init_ram(ram, "mips_mipssim.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_init_ram(bios, "mips_mipssim.bios", BIOS_SIZE); - vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); - - memory_region_add_subregion(address_space_mem, 0, ram); - - /* Map the BIOS / boot exception handler. */ - memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); - /* Load a BIOS / boot exception handler image. */ - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE); - g_free(filename); - } else { - bios_size = -1; - } - if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { - /* Bail out if we have neither a kernel image nor boot vector code. */ - fprintf(stderr, - "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", - filename); - exit(1); - } else { - /* We have a boot vector start address. */ - env->active_tc.PC = (target_long)(int32_t)0xbfc00000; - } - - if (kernel_filename) { - loaderparams.ram_size = ram_size; - loaderparams.kernel_filename = kernel_filename; - loaderparams.kernel_cmdline = kernel_cmdline; - loaderparams.initrd_filename = initrd_filename; - reset_info->vector = load_kernel(); - } - - /* Init CPU internal devices. */ - cpu_mips_irq_init_cpu(env); - cpu_mips_clock_init(env); - - /* Register 64 KB of ISA IO space at 0x1fd00000. */ - isa_mmio_init(0x1fd00000, 0x00010000); - - /* A single 16450 sits at offset 0x3f8. It is attached to - MIPS CPU INT2, which is interrupt 4. */ - if (serial_hds[0]) - serial_init(0x3f8, env->irq[4], 115200, serial_hds[0], - get_system_io()); - - if (nd_table[0].used) - /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ - mipsnet_init(0x4200, env->irq[2], &nd_table[0]); -} - -static QEMUMachine mips_mipssim_machine = { - .name = "mipssim", - .desc = "MIPS MIPSsim platform", - .init = mips_mipssim_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void mips_mipssim_machine_init(void) -{ - qemu_register_machine(&mips_mipssim_machine); -} - -machine_init(mips_mipssim_machine_init); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c deleted file mode 100644 index 539a562620..0000000000 --- a/hw/mips_r4k.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * QEMU/MIPS pseudo-board - * - * emulates a simple machine with ISA-like bus. - * ISA IO space mapped to the 0x14000000 (PHYS) and - * ISA memory at the 0x10000000 (PHYS, 16Mb in size). - * All peripherial devices are attached to this "bus" with - * the standard PC ISA addresses. -*/ -#include "hw/hw.h" -#include "hw/mips.h" -#include "hw/mips_cpudevs.h" -#include "hw/pc.h" -#include "hw/serial.h" -#include "hw/isa.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/flash.h" -#include "qemu/log.h" -#include "hw/mips-bios.h" -#include "hw/ide.h" -#include "hw/loader.h" -#include "elf.h" -#include "hw/mc146818rtc.h" -#include "hw/i8254.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#define MAX_IDE_BUS 2 - -static const int ide_iobase[2] = { 0x1f0, 0x170 }; -static const int ide_iobase2[2] = { 0x3f6, 0x376 }; -static const int ide_irq[2] = { 14, 15 }; - -static ISADevice *pit; /* PIT i8254 */ - -/* i8254 PIT is attached to the IRQ0 at PIC i8259 */ - -static struct _loaderparams { - int ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; -} loaderparams; - -static void mips_qemu_write (void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - if ((addr & 0xffff) == 0 && val == 42) - qemu_system_reset_request (); - else if ((addr & 0xffff) == 4 && val == 42) - qemu_system_shutdown_request (); -} - -static uint64_t mips_qemu_read (void *opaque, hwaddr addr, - unsigned size) -{ - return 0; -} - -static const MemoryRegionOps mips_qemu_ops = { - .read = mips_qemu_read, - .write = mips_qemu_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -typedef struct ResetData { - MIPSCPU *cpu; - uint64_t vector; -} ResetData; - -static int64_t load_kernel(void) -{ - int64_t entry, kernel_high; - long kernel_size, initrd_size, params_size; - ram_addr_t initrd_offset; - uint32_t *params_buf; - int big_endian; - -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, - NULL, (uint64_t *)&entry, NULL, - (uint64_t *)&kernel_high, big_endian, - ELF_MACHINE, 1); - if (kernel_size >= 0) { - if ((entry & ~0x7fffffffULL) == 0x80000000) - entry = (int32_t)entry; - } else { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - loaderparams.kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - initrd_offset = 0; - if (loaderparams.initrd_filename) { - initrd_size = get_image_size (loaderparams.initrd_filename); - if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - initrd_size = load_image_targphys(loaderparams.initrd_filename, - initrd_offset, - ram_size - initrd_offset); - } - if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); - exit(1); - } - } - - /* Store command line. */ - params_size = 264; - params_buf = g_malloc(params_size); - - params_buf[0] = tswap32(ram_size); - params_buf[1] = tswap32(0x12345678); - - if (initrd_size > 0) { - snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s", - cpu_mips_phys_to_kseg0(NULL, initrd_offset), - initrd_size, loaderparams.kernel_cmdline); - } else { - snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline); - } - - rom_add_blob_fixed("params", params_buf, params_size, - (16 << 20) - 264); - - return entry; -} - -static void main_cpu_reset(void *opaque) -{ - ResetData *s = (ResetData *)opaque; - CPUMIPSState *env = &s->cpu->env; - - cpu_reset(CPU(s->cpu)); - env->active_tc.PC = s->vector; -} - -static const int sector_len = 32 * 1024; -static -void mips_r4k_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - char *filename; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *bios; - MemoryRegion *iomem = g_new(MemoryRegion, 1); - int bios_size; - MIPSCPU *cpu; - CPUMIPSState *env; - ResetData *reset_info; - int i; - qemu_irq *i8259; - ISABus *isa_bus; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DriveInfo *dinfo; - int be; - - /* init CPUs */ - if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 - cpu_model = "R4000"; -#else - cpu_model = "24Kf"; -#endif - } - cpu = cpu_mips_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - reset_info = g_malloc0(sizeof(ResetData)); - reset_info->cpu = cpu; - reset_info->vector = env->active_tc.PC; - qemu_register_reset(main_cpu_reset, reset_info); - - /* allocate RAM */ - if (ram_size > (256 << 20)) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n", - ((unsigned int)ram_size / (1 << 20))); - exit(1); - } - memory_region_init_ram(ram, "mips_r4k.ram", ram_size); - vmstate_register_ram_global(ram); - - memory_region_add_subregion(address_space_mem, 0, ram); - - memory_region_init_io(iomem, &mips_qemu_ops, NULL, "mips-qemu", 0x10000); - memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem); - - /* Try to load a BIOS image. If this fails, we continue regardless, - but initialize the hardware ourselves. When a kernel gets - preloaded we also initialize the hardware, since the BIOS wasn't - run. */ - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = get_image_size(filename); - } else { - bios_size = -1; - } -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) { - bios = g_new(MemoryRegion, 1); - memory_region_init_ram(bios, "mips_r4k.bios", BIOS_SIZE); - vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); - memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios); - - load_image_targphys(filename, 0x1fc00000, BIOS_SIZE); - } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) { - uint32_t mips_rom = 0x00400000; - if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom, - dinfo->bdrv, sector_len, - mips_rom / sector_len, - 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - } - } - else { - /* not fatal */ - fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", - bios_name); - } - if (filename) { - g_free(filename); - } - - if (kernel_filename) { - loaderparams.ram_size = ram_size; - loaderparams.kernel_filename = kernel_filename; - loaderparams.kernel_cmdline = kernel_cmdline; - loaderparams.initrd_filename = initrd_filename; - reset_info->vector = load_kernel(); - } - - /* Init CPU internal devices */ - cpu_mips_irq_init_cpu(env); - cpu_mips_clock_init(env); - - /* The PIC is attached to the MIPS CPU INT0 pin */ - isa_bus = isa_bus_new(NULL, get_system_io()); - i8259 = i8259_init(isa_bus, env->irq[2]); - isa_bus_irqs(isa_bus, i8259); - - rtc_init(isa_bus, 2000, NULL); - - /* Register 64 KB of ISA IO space at 0x14000000 */ - isa_mmio_init(0x14000000, 0x00010000); - isa_mem_base = 0x10000000; - - pit = pit_init(isa_bus, 0x40, 0, NULL); - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - - isa_vga_init(isa_bus); - - if (nd_table[0].used) - isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]); - - ide_drive_get(hd, MAX_IDE_BUS); - for(i = 0; i < MAX_IDE_BUS; i++) - isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i], - hd[MAX_IDE_DEVS * i], - hd[MAX_IDE_DEVS * i + 1]); - - isa_create_simple(isa_bus, "i8042"); -} - -static QEMUMachine mips_machine = { - .name = "mips", - .desc = "mips r4k platform", - .init = mips_r4k_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void mips_machine_init(void) -{ - qemu_register_machine(&mips_machine); -} - -machine_init(mips_machine_init); diff --git a/hw/mips_timer.c b/hw/mips_timer.c deleted file mode 100644 index 9ad13f3924..0000000000 --- a/hw/mips_timer.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * QEMU MIPS timer support - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/mips_cpudevs.h" -#include "qemu/timer.h" - -#define TIMER_FREQ 100 * 1000 * 1000 - -/* XXX: do not use a global */ -uint32_t cpu_mips_get_random (CPUMIPSState *env) -{ - static uint32_t lfsr = 1; - static uint32_t prev_idx = 0; - uint32_t idx; - /* Don't return same value twice, so get another value */ - do { - lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u); - idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; - } while (idx == prev_idx); - prev_idx = idx; - return idx; -} - -/* MIPS R4K timer */ -static void cpu_mips_timer_update(CPUMIPSState *env) -{ - uint64_t now, next; - uint32_t wait; - - now = qemu_get_clock_ns(vm_clock); - wait = env->CP0_Compare - env->CP0_Count - - (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec()); - next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); - qemu_mod_timer(env->timer, next); -} - -/* Expire the timer. */ -static void cpu_mips_timer_expire(CPUMIPSState *env) -{ - cpu_mips_timer_update(env); - if (env->insn_flags & ISA_MIPS32R2) { - env->CP0_Cause |= 1 << CP0Ca_TI; - } - qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); -} - -uint32_t cpu_mips_get_count (CPUMIPSState *env) -{ - if (env->CP0_Cause & (1 << CP0Ca_DC)) { - return env->CP0_Count; - } else { - uint64_t now; - - now = qemu_get_clock_ns(vm_clock); - if (qemu_timer_pending(env->timer) - && qemu_timer_expired(env->timer, now)) { - /* The timer has already expired. */ - cpu_mips_timer_expire(env); - } - - return env->CP0_Count + - (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec()); - } -} - -void cpu_mips_store_count (CPUMIPSState *env, uint32_t count) -{ - if (env->CP0_Cause & (1 << CP0Ca_DC)) - env->CP0_Count = count; - else { - /* Store new count register */ - env->CP0_Count = - count - (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock), - TIMER_FREQ, get_ticks_per_sec()); - /* Update timer timer */ - cpu_mips_timer_update(env); - } -} - -void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value) -{ - env->CP0_Compare = value; - if (!(env->CP0_Cause & (1 << CP0Ca_DC))) - cpu_mips_timer_update(env); - if (env->insn_flags & ISA_MIPS32R2) - env->CP0_Cause &= ~(1 << CP0Ca_TI); - qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); -} - -void cpu_mips_start_count(CPUMIPSState *env) -{ - cpu_mips_store_count(env, env->CP0_Count); -} - -void cpu_mips_stop_count(CPUMIPSState *env) -{ - /* Store the current value */ - env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock), - TIMER_FREQ, get_ticks_per_sec()); -} - -static void mips_timer_cb (void *opaque) -{ - CPUMIPSState *env; - - env = opaque; -#if 0 - qemu_log("%s\n", __func__); -#endif - - if (env->CP0_Cause & (1 << CP0Ca_DC)) - return; - - /* ??? This callback should occur when the counter is exactly equal to - the comparator value. Offset the count by one to avoid immediately - retriggering the callback before any virtual time has passed. */ - env->CP0_Count++; - cpu_mips_timer_expire(env); - env->CP0_Count--; -} - -void cpu_mips_clock_init (CPUMIPSState *env) -{ - env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env); - env->CP0_Compare = 0; - cpu_mips_store_count(env, 1); -} diff --git a/hw/multiboot.c b/hw/multiboot.c deleted file mode 100644 index 3cb228f0ca..0000000000 --- a/hw/multiboot.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * QEMU PC System Emulator - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/fw_cfg.h" -#include "hw/multiboot.h" -#include "hw/loader.h" -#include "elf.h" -#include "sysemu/sysemu.h" - -/* Show multiboot debug output */ -//#define DEBUG_MULTIBOOT - -#ifdef DEBUG_MULTIBOOT -#define mb_debug(a...) fprintf(stderr, ## a) -#else -#define mb_debug(a...) -#endif - -#define MULTIBOOT_STRUCT_ADDR 0x9000 - -#if MULTIBOOT_STRUCT_ADDR > 0xf0000 -#error multiboot struct needs to fit in 16 bit real mode -#endif - -enum { - /* Multiboot info */ - MBI_FLAGS = 0, - MBI_MEM_LOWER = 4, - MBI_MEM_UPPER = 8, - MBI_BOOT_DEVICE = 12, - MBI_CMDLINE = 16, - MBI_MODS_COUNT = 20, - MBI_MODS_ADDR = 24, - MBI_MMAP_ADDR = 48, - - MBI_SIZE = 88, - - /* Multiboot modules */ - MB_MOD_START = 0, - MB_MOD_END = 4, - MB_MOD_CMDLINE = 8, - - MB_MOD_SIZE = 16, - - /* Region offsets */ - ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0, - ADDR_MBI = ADDR_E820_MAP + 0x500, - - /* Multiboot flags */ - MULTIBOOT_FLAGS_MEMORY = 1 << 0, - MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1, - MULTIBOOT_FLAGS_CMDLINE = 1 << 2, - MULTIBOOT_FLAGS_MODULES = 1 << 3, - MULTIBOOT_FLAGS_MMAP = 1 << 6, -}; - -typedef struct { - /* buffer holding kernel, cmdlines and mb_infos */ - void *mb_buf; - /* address in target */ - hwaddr mb_buf_phys; - /* size of mb_buf in bytes */ - unsigned mb_buf_size; - /* offset of mb-info's in bytes */ - hwaddr offset_mbinfo; - /* offset in buffer for cmdlines in bytes */ - hwaddr offset_cmdlines; - /* offset of modules in bytes */ - hwaddr offset_mods; - /* available slots for mb modules infos */ - int mb_mods_avail; - /* currently used slots of mb modules */ - int mb_mods_count; -} MultibootState; - -static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline) -{ - hwaddr p = s->offset_cmdlines; - char *b = (char *)s->mb_buf + p; - - get_opt_value(b, strlen(cmdline) + 1, cmdline); - s->offset_cmdlines += strlen(b) + 1; - return s->mb_buf_phys + p; -} - -static void mb_add_mod(MultibootState *s, - hwaddr start, hwaddr end, - hwaddr cmdline_phys) -{ - char *p; - assert(s->mb_mods_count < s->mb_mods_avail); - - p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count; - - stl_p(p + MB_MOD_START, start); - stl_p(p + MB_MOD_END, end); - stl_p(p + MB_MOD_CMDLINE, cmdline_phys); - - mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n", - s->mb_mods_count, start, end); - - s->mb_mods_count++; -} - -int load_multiboot(void *fw_cfg, - FILE *f, - const char *kernel_filename, - const char *initrd_filename, - const char *kernel_cmdline, - int kernel_file_size, - uint8_t *header) -{ - int i, is_multiboot = 0; - uint32_t flags = 0; - uint32_t mh_entry_addr; - uint32_t mh_load_addr; - uint32_t mb_kernel_size; - MultibootState mbs; - uint8_t bootinfo[MBI_SIZE]; - uint8_t *mb_bootinfo_data; - - /* Ok, let's see if it is a multiboot image. - The header is 12x32bit long, so the latest entry may be 8192 - 48. */ - for (i = 0; i < (8192 - 48); i += 4) { - if (ldl_p(header+i) == 0x1BADB002) { - uint32_t checksum = ldl_p(header+i+8); - flags = ldl_p(header+i+4); - checksum += flags; - checksum += (uint32_t)0x1BADB002; - if (!checksum) { - is_multiboot = 1; - break; - } - } - } - - if (!is_multiboot) - return 0; /* no multiboot */ - - mb_debug("qemu: I believe we found a multiboot image!\n"); - memset(bootinfo, 0, sizeof(bootinfo)); - memset(&mbs, 0, sizeof(mbs)); - - if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */ - fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n"); - } - if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */ - uint64_t elf_entry; - uint64_t elf_low, elf_high; - int kernel_size; - fclose(f); - - if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) { - fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n"); - exit(1); - } - - kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, - &elf_low, &elf_high, 0, ELF_MACHINE, 0); - if (kernel_size < 0) { - fprintf(stderr, "Error while loading elf kernel\n"); - exit(1); - } - mh_load_addr = elf_low; - mb_kernel_size = elf_high - elf_low; - mh_entry_addr = elf_entry; - - mbs.mb_buf = g_malloc(mb_kernel_size); - if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) { - fprintf(stderr, "Error while fetching elf kernel from rom\n"); - exit(1); - } - - mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n", - mb_kernel_size, (size_t)mh_entry_addr); - } else { - /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */ - uint32_t mh_header_addr = ldl_p(header+i+12); - uint32_t mh_load_end_addr = ldl_p(header+i+20); - uint32_t mh_bss_end_addr = ldl_p(header+i+24); - mh_load_addr = ldl_p(header+i+16); - uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); - uint32_t mb_load_size = 0; - mh_entry_addr = ldl_p(header+i+28); - - if (mh_load_end_addr) { - mb_kernel_size = mh_bss_end_addr - mh_load_addr; - mb_load_size = mh_load_end_addr - mh_load_addr; - } else { - mb_kernel_size = kernel_file_size - mb_kernel_text_offset; - mb_load_size = mb_kernel_size; - } - - /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. - uint32_t mh_mode_type = ldl_p(header+i+32); - uint32_t mh_width = ldl_p(header+i+36); - uint32_t mh_height = ldl_p(header+i+40); - uint32_t mh_depth = ldl_p(header+i+44); */ - - mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr); - mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr); - mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr); - mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr); - mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n", - mb_load_size, mh_load_addr); - - mbs.mb_buf = g_malloc(mb_kernel_size); - fseek(f, mb_kernel_text_offset, SEEK_SET); - if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) { - fprintf(stderr, "fread() failed\n"); - exit(1); - } - memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size); - fclose(f); - } - - mbs.mb_buf_phys = mh_load_addr; - - mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size); - mbs.offset_mbinfo = mbs.mb_buf_size; - - /* Calculate space for cmdlines and mb_mods */ - mbs.mb_buf_size += strlen(kernel_filename) + 1; - mbs.mb_buf_size += strlen(kernel_cmdline) + 1; - if (initrd_filename) { - const char *r = initrd_filename; - mbs.mb_buf_size += strlen(r) + 1; - mbs.mb_mods_avail = 1; - while (*(r = get_opt_value(NULL, 0, r))) { - mbs.mb_mods_avail++; - r++; - } - mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail; - } - - mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size); - - /* enlarge mb_buf to hold cmdlines and mb-info structs */ - mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); - mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE; - - if (initrd_filename) { - char *next_initrd, not_last; - - mbs.offset_mods = mbs.mb_buf_size; - - do { - char *next_space; - int mb_mod_length; - uint32_t offs = mbs.mb_buf_size; - - next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename); - not_last = *next_initrd; - *next_initrd = '\0'; - /* if a space comes after the module filename, treat everything - after that as parameters */ - hwaddr c = mb_add_cmdline(&mbs, initrd_filename); - if ((next_space = strchr(initrd_filename, ' '))) - *next_space = '\0'; - mb_debug("multiboot loading module: %s\n", initrd_filename); - mb_mod_length = get_image_size(initrd_filename); - if (mb_mod_length < 0) { - fprintf(stderr, "Failed to open file '%s'\n", initrd_filename); - exit(1); - } - - mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size); - mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); - - load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs); - mb_add_mod(&mbs, mbs.mb_buf_phys + offs, - mbs.mb_buf_phys + offs + mb_mod_length, c); - - mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx"\n", - (char *)mbs.mb_buf + offs, - (char *)mbs.mb_buf + offs + mb_mod_length, c); - initrd_filename = next_initrd+1; - } while (not_last); - } - - /* Commandline support */ - char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2]; - snprintf(kcmdline, sizeof(kcmdline), "%s %s", - kernel_filename, kernel_cmdline); - stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline)); - - stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo); - stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */ - - /* the kernel is where we want it to be now */ - stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY - | MULTIBOOT_FLAGS_BOOT_DEVICE - | MULTIBOOT_FLAGS_CMDLINE - | MULTIBOOT_FLAGS_MODULES - | MULTIBOOT_FLAGS_MMAP); - stl_p(bootinfo + MBI_MEM_LOWER, 640); - stl_p(bootinfo + MBI_MEM_UPPER, (ram_size / 1024) - 1024); - stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */ - stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP); - - mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr); - mb_debug(" mb_buf_phys = "TARGET_FMT_plx"\n", mbs.mb_buf_phys); - mb_debug(" mod_start = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods); - mb_debug(" mb_mods_count = %d\n", mbs.mb_mods_count); - - /* save bootinfo off the stack */ - mb_bootinfo_data = g_malloc(sizeof(bootinfo)); - memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo)); - - /* Pass variables to option rom */ - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, - mbs.mb_buf, mbs.mb_buf_size); - - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo)); - fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data, - sizeof(bootinfo)); - - option_rom[nb_option_roms].name = "multiboot.bin"; - option_rom[nb_option_roms].bootindex = 0; - nb_option_roms++; - - return 1; /* yes, we are multiboot */ -} diff --git a/hw/musicpal.c b/hw/musicpal.c deleted file mode 100644 index a37dbd7961..0000000000 --- a/hw/musicpal.c +++ /dev/null @@ -1,1697 +0,0 @@ -/* - * Marvell MV88W8618 / Freecom MusicPal emulation. - * - * Copyright (c) 2008 Jan Kiszka - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/serial.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "block/block.h" -#include "hw/flash.h" -#include "ui/console.h" -#include "hw/i2c.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" -#include "ui/pixel_ops.h" - -#define MP_MISC_BASE 0x80002000 -#define MP_MISC_SIZE 0x00001000 - -#define MP_ETH_BASE 0x80008000 -#define MP_ETH_SIZE 0x00001000 - -#define MP_WLAN_BASE 0x8000C000 -#define MP_WLAN_SIZE 0x00000800 - -#define MP_UART1_BASE 0x8000C840 -#define MP_UART2_BASE 0x8000C940 - -#define MP_GPIO_BASE 0x8000D000 -#define MP_GPIO_SIZE 0x00001000 - -#define MP_FLASHCFG_BASE 0x90006000 -#define MP_FLASHCFG_SIZE 0x00001000 - -#define MP_AUDIO_BASE 0x90007000 - -#define MP_PIC_BASE 0x90008000 -#define MP_PIC_SIZE 0x00001000 - -#define MP_PIT_BASE 0x90009000 -#define MP_PIT_SIZE 0x00001000 - -#define MP_LCD_BASE 0x9000c000 -#define MP_LCD_SIZE 0x00001000 - -#define MP_SRAM_BASE 0xC0000000 -#define MP_SRAM_SIZE 0x00020000 - -#define MP_RAM_DEFAULT_SIZE 32*1024*1024 -#define MP_FLASH_SIZE_MAX 32*1024*1024 - -#define MP_TIMER1_IRQ 4 -#define MP_TIMER2_IRQ 5 -#define MP_TIMER3_IRQ 6 -#define MP_TIMER4_IRQ 7 -#define MP_EHCI_IRQ 8 -#define MP_ETH_IRQ 9 -#define MP_UART1_IRQ 11 -#define MP_UART2_IRQ 11 -#define MP_GPIO_IRQ 12 -#define MP_RTC_IRQ 28 -#define MP_AUDIO_IRQ 30 - -/* Wolfson 8750 I2C address */ -#define MP_WM_ADDR 0x1A - -/* Ethernet register offsets */ -#define MP_ETH_SMIR 0x010 -#define MP_ETH_PCXR 0x408 -#define MP_ETH_SDCMR 0x448 -#define MP_ETH_ICR 0x450 -#define MP_ETH_IMR 0x458 -#define MP_ETH_FRDP0 0x480 -#define MP_ETH_FRDP1 0x484 -#define MP_ETH_FRDP2 0x488 -#define MP_ETH_FRDP3 0x48C -#define MP_ETH_CRDP0 0x4A0 -#define MP_ETH_CRDP1 0x4A4 -#define MP_ETH_CRDP2 0x4A8 -#define MP_ETH_CRDP3 0x4AC -#define MP_ETH_CTDP0 0x4E0 -#define MP_ETH_CTDP1 0x4E4 -#define MP_ETH_CTDP2 0x4E8 -#define MP_ETH_CTDP3 0x4EC - -/* MII PHY access */ -#define MP_ETH_SMIR_DATA 0x0000FFFF -#define MP_ETH_SMIR_ADDR 0x03FF0000 -#define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */ -#define MP_ETH_SMIR_RDVALID (1 << 27) - -/* PHY registers */ -#define MP_ETH_PHY1_BMSR 0x00210000 -#define MP_ETH_PHY1_PHYSID1 0x00410000 -#define MP_ETH_PHY1_PHYSID2 0x00610000 - -#define MP_PHY_BMSR_LINK 0x0004 -#define MP_PHY_BMSR_AUTONEG 0x0008 - -#define MP_PHY_88E3015 0x01410E20 - -/* TX descriptor status */ -#define MP_ETH_TX_OWN (1 << 31) - -/* RX descriptor status */ -#define MP_ETH_RX_OWN (1 << 31) - -/* Interrupt cause/mask bits */ -#define MP_ETH_IRQ_RX_BIT 0 -#define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT) -#define MP_ETH_IRQ_TXHI_BIT 2 -#define MP_ETH_IRQ_TXLO_BIT 3 - -/* Port config bits */ -#define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */ - -/* SDMA command bits */ -#define MP_ETH_CMD_TXHI (1 << 23) -#define MP_ETH_CMD_TXLO (1 << 22) - -typedef struct mv88w8618_tx_desc { - uint32_t cmdstat; - uint16_t res; - uint16_t bytes; - uint32_t buffer; - uint32_t next; -} mv88w8618_tx_desc; - -typedef struct mv88w8618_rx_desc { - uint32_t cmdstat; - uint16_t bytes; - uint16_t buffer_size; - uint32_t buffer; - uint32_t next; -} mv88w8618_rx_desc; - -typedef struct mv88w8618_eth_state { - SysBusDevice busdev; - MemoryRegion iomem; - qemu_irq irq; - uint32_t smir; - uint32_t icr; - uint32_t imr; - int mmio_index; - uint32_t vlan_header; - uint32_t tx_queue[2]; - uint32_t rx_queue[4]; - uint32_t frx_queue[4]; - uint32_t cur_rx[4]; - NICState *nic; - NICConf conf; -} mv88w8618_eth_state; - -static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc) -{ - cpu_to_le32s(&desc->cmdstat); - cpu_to_le16s(&desc->bytes); - cpu_to_le16s(&desc->buffer_size); - cpu_to_le32s(&desc->buffer); - cpu_to_le32s(&desc->next); - cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc)); -} - -static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) -{ - cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc)); - le32_to_cpus(&desc->cmdstat); - le16_to_cpus(&desc->bytes); - le16_to_cpus(&desc->buffer_size); - le32_to_cpus(&desc->buffer); - le32_to_cpus(&desc->next); -} - -static int eth_can_receive(NetClientState *nc) -{ - return 1; -} - -static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); - uint32_t desc_addr; - mv88w8618_rx_desc desc; - int i; - - for (i = 0; i < 4; i++) { - desc_addr = s->cur_rx[i]; - if (!desc_addr) { - continue; - } - do { - eth_rx_desc_get(desc_addr, &desc); - if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { - cpu_physical_memory_write(desc.buffer + s->vlan_header, - buf, size); - desc.bytes = size + s->vlan_header; - desc.cmdstat &= ~MP_ETH_RX_OWN; - s->cur_rx[i] = desc.next; - - s->icr |= MP_ETH_IRQ_RX; - if (s->icr & s->imr) { - qemu_irq_raise(s->irq); - } - eth_rx_desc_put(desc_addr, &desc); - return size; - } - desc_addr = desc.next; - } while (desc_addr != s->rx_queue[i]); - } - return size; -} - -static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc) -{ - cpu_to_le32s(&desc->cmdstat); - cpu_to_le16s(&desc->res); - cpu_to_le16s(&desc->bytes); - cpu_to_le32s(&desc->buffer); - cpu_to_le32s(&desc->next); - cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc)); -} - -static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc) -{ - cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc)); - le32_to_cpus(&desc->cmdstat); - le16_to_cpus(&desc->res); - le16_to_cpus(&desc->bytes); - le32_to_cpus(&desc->buffer); - le32_to_cpus(&desc->next); -} - -static void eth_send(mv88w8618_eth_state *s, int queue_index) -{ - uint32_t desc_addr = s->tx_queue[queue_index]; - mv88w8618_tx_desc desc; - uint32_t next_desc; - uint8_t buf[2048]; - int len; - - do { - eth_tx_desc_get(desc_addr, &desc); - next_desc = desc.next; - if (desc.cmdstat & MP_ETH_TX_OWN) { - len = desc.bytes; - if (len < 2048) { - cpu_physical_memory_read(desc.buffer, buf, len); - qemu_send_packet(qemu_get_queue(s->nic), buf, len); - } - desc.cmdstat &= ~MP_ETH_TX_OWN; - s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); - eth_tx_desc_put(desc_addr, &desc); - } - desc_addr = next_desc; - } while (desc_addr != s->tx_queue[queue_index]); -} - -static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset, - unsigned size) -{ - mv88w8618_eth_state *s = opaque; - - switch (offset) { - case MP_ETH_SMIR: - if (s->smir & MP_ETH_SMIR_OPCODE) { - switch (s->smir & MP_ETH_SMIR_ADDR) { - case MP_ETH_PHY1_BMSR: - return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG | - MP_ETH_SMIR_RDVALID; - case MP_ETH_PHY1_PHYSID1: - return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID; - case MP_ETH_PHY1_PHYSID2: - return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID; - default: - return MP_ETH_SMIR_RDVALID; - } - } - return 0; - - case MP_ETH_ICR: - return s->icr; - - case MP_ETH_IMR: - return s->imr; - - case MP_ETH_FRDP0 ... MP_ETH_FRDP3: - return s->frx_queue[(offset - MP_ETH_FRDP0)/4]; - - case MP_ETH_CRDP0 ... MP_ETH_CRDP3: - return s->rx_queue[(offset - MP_ETH_CRDP0)/4]; - - case MP_ETH_CTDP0 ... MP_ETH_CTDP3: - return s->tx_queue[(offset - MP_ETH_CTDP0)/4]; - - default: - return 0; - } -} - -static void mv88w8618_eth_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_eth_state *s = opaque; - - switch (offset) { - case MP_ETH_SMIR: - s->smir = value; - break; - - case MP_ETH_PCXR: - s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2; - break; - - case MP_ETH_SDCMR: - if (value & MP_ETH_CMD_TXHI) { - eth_send(s, 1); - } - if (value & MP_ETH_CMD_TXLO) { - eth_send(s, 0); - } - if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) { - qemu_irq_raise(s->irq); - } - break; - - case MP_ETH_ICR: - s->icr &= value; - break; - - case MP_ETH_IMR: - s->imr = value; - if (s->icr & s->imr) { - qemu_irq_raise(s->irq); - } - break; - - case MP_ETH_FRDP0 ... MP_ETH_FRDP3: - s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value; - break; - - case MP_ETH_CRDP0 ... MP_ETH_CRDP3: - s->rx_queue[(offset - MP_ETH_CRDP0)/4] = - s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value; - break; - - case MP_ETH_CTDP0 ... MP_ETH_CTDP3: - s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value; - break; - } -} - -static const MemoryRegionOps mv88w8618_eth_ops = { - .read = mv88w8618_eth_read, - .write = mv88w8618_eth_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void eth_cleanup(NetClientState *nc) -{ - mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); - - s->nic = NULL; -} - -static NetClientInfo net_mv88w8618_info = { - .type = NET_CLIENT_OPTIONS_KIND_NIC, - .size = sizeof(NICState), - .can_receive = eth_can_receive, - .receive = eth_receive, - .cleanup = eth_cleanup, -}; - -static int mv88w8618_eth_init(SysBusDevice *dev) -{ - mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev); - - sysbus_init_irq(dev, &s->irq); - s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); - memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth", - MP_ETH_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_eth_vmsd = { - .name = "mv88w8618_eth", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(smir, mv88w8618_eth_state), - VMSTATE_UINT32(icr, mv88w8618_eth_state), - VMSTATE_UINT32(imr, mv88w8618_eth_state), - VMSTATE_UINT32(vlan_header, mv88w8618_eth_state), - VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2), - VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4), - VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4), - VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4), - VMSTATE_END_OF_LIST() - } -}; - -static Property mv88w8618_eth_properties[] = { - DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), - DEFINE_PROP_END_OF_LIST(), -}; - -static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_eth_init; - dc->vmsd = &mv88w8618_eth_vmsd; - dc->props = mv88w8618_eth_properties; -} - -static const TypeInfo mv88w8618_eth_info = { - .name = "mv88w8618_eth", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_eth_state), - .class_init = mv88w8618_eth_class_init, -}; - -/* LCD register offsets */ -#define MP_LCD_IRQCTRL 0x180 -#define MP_LCD_IRQSTAT 0x184 -#define MP_LCD_SPICTRL 0x1ac -#define MP_LCD_INST 0x1bc -#define MP_LCD_DATA 0x1c0 - -/* Mode magics */ -#define MP_LCD_SPI_DATA 0x00100011 -#define MP_LCD_SPI_CMD 0x00104011 -#define MP_LCD_SPI_INVALID 0x00000000 - -/* Commmands */ -#define MP_LCD_INST_SETPAGE0 0xB0 -/* ... */ -#define MP_LCD_INST_SETPAGE7 0xB7 - -#define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */ - -typedef struct musicpal_lcd_state { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t brightness; - uint32_t mode; - uint32_t irqctrl; - uint32_t page; - uint32_t page_off; - DisplayState *ds; - uint8_t video_ram[128*64/8]; -} musicpal_lcd_state; - -static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col) -{ - switch (s->brightness) { - case 7: - return col; - case 0: - return 0; - default: - return (col * s->brightness) / 7; - } -} - -#define SET_LCD_PIXEL(depth, type) \ -static inline void glue(set_lcd_pixel, depth) \ - (musicpal_lcd_state *s, int x, int y, type col) \ -{ \ - int dx, dy; \ - type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \ -\ - for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \ - for (dx = 0; dx < 3; dx++, pixel++) \ - *pixel = col; \ -} -SET_LCD_PIXEL(8, uint8_t) -SET_LCD_PIXEL(16, uint16_t) -SET_LCD_PIXEL(32, uint32_t) - -static void lcd_refresh(void *opaque) -{ - musicpal_lcd_state *s = opaque; - int x, y, col; - - switch (ds_get_bits_per_pixel(s->ds)) { - case 0: - return; -#define LCD_REFRESH(depth, func) \ - case depth: \ - col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \ - scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \ - scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \ - for (x = 0; x < 128; x++) { \ - for (y = 0; y < 64; y++) { \ - if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \ - glue(set_lcd_pixel, depth)(s, x, y, col); \ - } else { \ - glue(set_lcd_pixel, depth)(s, x, y, 0); \ - } \ - } \ - } \ - break; - LCD_REFRESH(8, rgb_to_pixel8) - LCD_REFRESH(16, rgb_to_pixel16) - LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ? - rgb_to_pixel32bgr : rgb_to_pixel32)) - default: - hw_error("unsupported colour depth %i\n", - ds_get_bits_per_pixel(s->ds)); - } - - dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3); -} - -static void lcd_invalidate(void *opaque) -{ -} - -static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level) -{ - musicpal_lcd_state *s = opaque; - s->brightness &= ~(1 << irq); - s->brightness |= level << irq; -} - -static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset, - unsigned size) -{ - musicpal_lcd_state *s = opaque; - - switch (offset) { - case MP_LCD_IRQCTRL: - return s->irqctrl; - - default: - return 0; - } -} - -static void musicpal_lcd_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - musicpal_lcd_state *s = opaque; - - switch (offset) { - case MP_LCD_IRQCTRL: - s->irqctrl = value; - break; - - case MP_LCD_SPICTRL: - if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) { - s->mode = value; - } else { - s->mode = MP_LCD_SPI_INVALID; - } - break; - - case MP_LCD_INST: - if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) { - s->page = value - MP_LCD_INST_SETPAGE0; - s->page_off = 0; - } - break; - - case MP_LCD_DATA: - if (s->mode == MP_LCD_SPI_CMD) { - if (value >= MP_LCD_INST_SETPAGE0 && - value <= MP_LCD_INST_SETPAGE7) { - s->page = value - MP_LCD_INST_SETPAGE0; - s->page_off = 0; - } - } else if (s->mode == MP_LCD_SPI_DATA) { - s->video_ram[s->page*128 + s->page_off] = value; - s->page_off = (s->page_off + 1) & 127; - } - break; - } -} - -static const MemoryRegionOps musicpal_lcd_ops = { - .read = musicpal_lcd_read, - .write = musicpal_lcd_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int musicpal_lcd_init(SysBusDevice *dev) -{ - musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev); - - s->brightness = 7; - - memory_region_init_io(&s->iomem, &musicpal_lcd_ops, s, - "musicpal-lcd", MP_LCD_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - s->ds = graphic_console_init(lcd_refresh, lcd_invalidate, - NULL, NULL, s); - qemu_console_resize(s->ds, 128*3, 64*3); - - qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3); - - return 0; -} - -static const VMStateDescription musicpal_lcd_vmsd = { - .name = "musicpal_lcd", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(brightness, musicpal_lcd_state), - VMSTATE_UINT32(mode, musicpal_lcd_state), - VMSTATE_UINT32(irqctrl, musicpal_lcd_state), - VMSTATE_UINT32(page, musicpal_lcd_state), - VMSTATE_UINT32(page_off, musicpal_lcd_state), - VMSTATE_BUFFER(video_ram, musicpal_lcd_state), - VMSTATE_END_OF_LIST() - } -}; - -static void musicpal_lcd_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = musicpal_lcd_init; - dc->vmsd = &musicpal_lcd_vmsd; -} - -static const TypeInfo musicpal_lcd_info = { - .name = "musicpal_lcd", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(musicpal_lcd_state), - .class_init = musicpal_lcd_class_init, -}; - -/* PIC register offsets */ -#define MP_PIC_STATUS 0x00 -#define MP_PIC_ENABLE_SET 0x08 -#define MP_PIC_ENABLE_CLR 0x0C - -typedef struct mv88w8618_pic_state -{ - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t level; - uint32_t enabled; - qemu_irq parent_irq; -} mv88w8618_pic_state; - -static void mv88w8618_pic_update(mv88w8618_pic_state *s) -{ - qemu_set_irq(s->parent_irq, (s->level & s->enabled)); -} - -static void mv88w8618_pic_set_irq(void *opaque, int irq, int level) -{ - mv88w8618_pic_state *s = opaque; - - if (level) { - s->level |= 1 << irq; - } else { - s->level &= ~(1 << irq); - } - mv88w8618_pic_update(s); -} - -static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset, - unsigned size) -{ - mv88w8618_pic_state *s = opaque; - - switch (offset) { - case MP_PIC_STATUS: - return s->level & s->enabled; - - default: - return 0; - } -} - -static void mv88w8618_pic_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_pic_state *s = opaque; - - switch (offset) { - case MP_PIC_ENABLE_SET: - s->enabled |= value; - break; - - case MP_PIC_ENABLE_CLR: - s->enabled &= ~value; - s->level &= ~value; - break; - } - mv88w8618_pic_update(s); -} - -static void mv88w8618_pic_reset(DeviceState *d) -{ - mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, - SYS_BUS_DEVICE(d)); - - s->level = 0; - s->enabled = 0; -} - -static const MemoryRegionOps mv88w8618_pic_ops = { - .read = mv88w8618_pic_read, - .write = mv88w8618_pic_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_pic_init(SysBusDevice *dev) -{ - mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev); - - qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32); - sysbus_init_irq(dev, &s->parent_irq); - memory_region_init_io(&s->iomem, &mv88w8618_pic_ops, s, - "musicpal-pic", MP_PIC_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_pic_vmsd = { - .name = "mv88w8618_pic", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(level, mv88w8618_pic_state), - VMSTATE_UINT32(enabled, mv88w8618_pic_state), - VMSTATE_END_OF_LIST() - } -}; - -static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_pic_init; - dc->reset = mv88w8618_pic_reset; - dc->vmsd = &mv88w8618_pic_vmsd; -} - -static const TypeInfo mv88w8618_pic_info = { - .name = "mv88w8618_pic", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_pic_state), - .class_init = mv88w8618_pic_class_init, -}; - -/* PIT register offsets */ -#define MP_PIT_TIMER1_LENGTH 0x00 -/* ... */ -#define MP_PIT_TIMER4_LENGTH 0x0C -#define MP_PIT_CONTROL 0x10 -#define MP_PIT_TIMER1_VALUE 0x14 -/* ... */ -#define MP_PIT_TIMER4_VALUE 0x20 -#define MP_BOARD_RESET 0x34 - -/* Magic board reset value (probably some watchdog behind it) */ -#define MP_BOARD_RESET_MAGIC 0x10000 - -typedef struct mv88w8618_timer_state { - ptimer_state *ptimer; - uint32_t limit; - int freq; - qemu_irq irq; -} mv88w8618_timer_state; - -typedef struct mv88w8618_pit_state { - SysBusDevice busdev; - MemoryRegion iomem; - mv88w8618_timer_state timer[4]; -} mv88w8618_pit_state; - -static void mv88w8618_timer_tick(void *opaque) -{ - mv88w8618_timer_state *s = opaque; - - qemu_irq_raise(s->irq); -} - -static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, - uint32_t freq) -{ - QEMUBH *bh; - - sysbus_init_irq(dev, &s->irq); - s->freq = freq; - - bh = qemu_bh_new(mv88w8618_timer_tick, s); - s->ptimer = ptimer_init(bh); -} - -static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, - unsigned size) -{ - mv88w8618_pit_state *s = opaque; - mv88w8618_timer_state *t; - - switch (offset) { - case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE: - t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2]; - return ptimer_get_count(t->ptimer); - - default: - return 0; - } -} - -static void mv88w8618_pit_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_pit_state *s = opaque; - mv88w8618_timer_state *t; - int i; - - switch (offset) { - case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH: - t = &s->timer[offset >> 2]; - t->limit = value; - if (t->limit > 0) { - ptimer_set_limit(t->ptimer, t->limit, 1); - } else { - ptimer_stop(t->ptimer); - } - break; - - case MP_PIT_CONTROL: - for (i = 0; i < 4; i++) { - t = &s->timer[i]; - if (value & 0xf && t->limit > 0) { - ptimer_set_limit(t->ptimer, t->limit, 0); - ptimer_set_freq(t->ptimer, t->freq); - ptimer_run(t->ptimer, 0); - } else { - ptimer_stop(t->ptimer); - } - value >>= 4; - } - break; - - case MP_BOARD_RESET: - if (value == MP_BOARD_RESET_MAGIC) { - qemu_system_reset_request(); - } - break; - } -} - -static void mv88w8618_pit_reset(DeviceState *d) -{ - mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, - SYS_BUS_DEVICE(d)); - int i; - - for (i = 0; i < 4; i++) { - ptimer_stop(s->timer[i].ptimer); - s->timer[i].limit = 0; - } -} - -static const MemoryRegionOps mv88w8618_pit_ops = { - .read = mv88w8618_pit_read, - .write = mv88w8618_pit_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_pit_init(SysBusDevice *dev) -{ - mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev); - int i; - - /* Letting them all run at 1 MHz is likely just a pragmatic - * simplification. */ - for (i = 0; i < 4; i++) { - mv88w8618_timer_init(dev, &s->timer[i], 1000000); - } - - memory_region_init_io(&s->iomem, &mv88w8618_pit_ops, s, - "musicpal-pit", MP_PIT_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_timer_vmsd = { - .name = "timer", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_PTIMER(ptimer, mv88w8618_timer_state), - VMSTATE_UINT32(limit, mv88w8618_timer_state), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription mv88w8618_pit_vmsd = { - .name = "mv88w8618_pit", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1, - mv88w8618_timer_vmsd, mv88w8618_timer_state), - VMSTATE_END_OF_LIST() - } -}; - -static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_pit_init; - dc->reset = mv88w8618_pit_reset; - dc->vmsd = &mv88w8618_pit_vmsd; -} - -static const TypeInfo mv88w8618_pit_info = { - .name = "mv88w8618_pit", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_pit_state), - .class_init = mv88w8618_pit_class_init, -}; - -/* Flash config register offsets */ -#define MP_FLASHCFG_CFGR0 0x04 - -typedef struct mv88w8618_flashcfg_state { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t cfgr0; -} mv88w8618_flashcfg_state; - -static uint64_t mv88w8618_flashcfg_read(void *opaque, - hwaddr offset, - unsigned size) -{ - mv88w8618_flashcfg_state *s = opaque; - - switch (offset) { - case MP_FLASHCFG_CFGR0: - return s->cfgr0; - - default: - return 0; - } -} - -static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_flashcfg_state *s = opaque; - - switch (offset) { - case MP_FLASHCFG_CFGR0: - s->cfgr0 = value; - break; - } -} - -static const MemoryRegionOps mv88w8618_flashcfg_ops = { - .read = mv88w8618_flashcfg_read, - .write = mv88w8618_flashcfg_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_flashcfg_init(SysBusDevice *dev) -{ - mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev); - - s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ - memory_region_init_io(&s->iomem, &mv88w8618_flashcfg_ops, s, - "musicpal-flashcfg", MP_FLASHCFG_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_flashcfg_vmsd = { - .name = "mv88w8618_flashcfg", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state), - VMSTATE_END_OF_LIST() - } -}; - -static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_flashcfg_init; - dc->vmsd = &mv88w8618_flashcfg_vmsd; -} - -static const TypeInfo mv88w8618_flashcfg_info = { - .name = "mv88w8618_flashcfg", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_flashcfg_state), - .class_init = mv88w8618_flashcfg_class_init, -}; - -/* Misc register offsets */ -#define MP_MISC_BOARD_REVISION 0x18 - -#define MP_BOARD_REVISION 0x31 - -static uint64_t musicpal_misc_read(void *opaque, hwaddr offset, - unsigned size) -{ - switch (offset) { - case MP_MISC_BOARD_REVISION: - return MP_BOARD_REVISION; - - default: - return 0; - } -} - -static void musicpal_misc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ -} - -static const MemoryRegionOps musicpal_misc_ops = { - .read = musicpal_misc_read, - .write = musicpal_misc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void musicpal_misc_init(SysBusDevice *dev) -{ - MemoryRegion *iomem = g_new(MemoryRegion, 1); - - memory_region_init_io(iomem, &musicpal_misc_ops, NULL, - "musicpal-misc", MP_MISC_SIZE); - sysbus_add_memory(dev, MP_MISC_BASE, iomem); -} - -/* WLAN register offsets */ -#define MP_WLAN_MAGIC1 0x11c -#define MP_WLAN_MAGIC2 0x124 - -static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset, - unsigned size) -{ - switch (offset) { - /* Workaround to allow loading the binary-only wlandrv.ko crap - * from the original Freecom firmware. */ - case MP_WLAN_MAGIC1: - return ~3; - case MP_WLAN_MAGIC2: - return -1; - - default: - return 0; - } -} - -static void mv88w8618_wlan_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ -} - -static const MemoryRegionOps mv88w8618_wlan_ops = { - .read = mv88w8618_wlan_read, - .write =mv88w8618_wlan_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_wlan_init(SysBusDevice *dev) -{ - MemoryRegion *iomem = g_new(MemoryRegion, 1); - - memory_region_init_io(iomem, &mv88w8618_wlan_ops, NULL, - "musicpal-wlan", MP_WLAN_SIZE); - sysbus_init_mmio(dev, iomem); - return 0; -} - -/* GPIO register offsets */ -#define MP_GPIO_OE_LO 0x008 -#define MP_GPIO_OUT_LO 0x00c -#define MP_GPIO_IN_LO 0x010 -#define MP_GPIO_IER_LO 0x014 -#define MP_GPIO_IMR_LO 0x018 -#define MP_GPIO_ISR_LO 0x020 -#define MP_GPIO_OE_HI 0x508 -#define MP_GPIO_OUT_HI 0x50c -#define MP_GPIO_IN_HI 0x510 -#define MP_GPIO_IER_HI 0x514 -#define MP_GPIO_IMR_HI 0x518 -#define MP_GPIO_ISR_HI 0x520 - -/* GPIO bits & masks */ -#define MP_GPIO_LCD_BRIGHTNESS 0x00070000 -#define MP_GPIO_I2C_DATA_BIT 29 -#define MP_GPIO_I2C_CLOCK_BIT 30 - -/* LCD brightness bits in GPIO_OE_HI */ -#define MP_OE_LCD_BRIGHTNESS 0x0007 - -typedef struct musicpal_gpio_state { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t lcd_brightness; - uint32_t out_state; - uint32_t in_state; - uint32_t ier; - uint32_t imr; - uint32_t isr; - qemu_irq irq; - qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */ -} musicpal_gpio_state; - -static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) { - int i; - uint32_t brightness; - - /* compute brightness ratio */ - switch (s->lcd_brightness) { - case 0x00000007: - brightness = 0; - break; - - case 0x00020000: - brightness = 1; - break; - - case 0x00020001: - brightness = 2; - break; - - case 0x00040000: - brightness = 3; - break; - - case 0x00010006: - brightness = 4; - break; - - case 0x00020005: - brightness = 5; - break; - - case 0x00040003: - brightness = 6; - break; - - case 0x00030004: - default: - brightness = 7; - } - - /* set lcd brightness GPIOs */ - for (i = 0; i <= 2; i++) { - qemu_set_irq(s->out[i], (brightness >> i) & 1); - } -} - -static void musicpal_gpio_pin_event(void *opaque, int pin, int level) -{ - musicpal_gpio_state *s = opaque; - uint32_t mask = 1 << pin; - uint32_t delta = level << pin; - uint32_t old = s->in_state & mask; - - s->in_state &= ~mask; - s->in_state |= delta; - - if ((old ^ delta) && - ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) { - s->isr = mask; - qemu_irq_raise(s->irq); - } -} - -static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset, - unsigned size) -{ - musicpal_gpio_state *s = opaque; - - switch (offset) { - case MP_GPIO_OE_HI: /* used for LCD brightness control */ - return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS; - - case MP_GPIO_OUT_LO: - return s->out_state & 0xFFFF; - case MP_GPIO_OUT_HI: - return s->out_state >> 16; - - case MP_GPIO_IN_LO: - return s->in_state & 0xFFFF; - case MP_GPIO_IN_HI: - return s->in_state >> 16; - - case MP_GPIO_IER_LO: - return s->ier & 0xFFFF; - case MP_GPIO_IER_HI: - return s->ier >> 16; - - case MP_GPIO_IMR_LO: - return s->imr & 0xFFFF; - case MP_GPIO_IMR_HI: - return s->imr >> 16; - - case MP_GPIO_ISR_LO: - return s->isr & 0xFFFF; - case MP_GPIO_ISR_HI: - return s->isr >> 16; - - default: - return 0; - } -} - -static void musicpal_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - musicpal_gpio_state *s = opaque; - switch (offset) { - case MP_GPIO_OE_HI: /* used for LCD brightness control */ - s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) | - (value & MP_OE_LCD_BRIGHTNESS); - musicpal_gpio_brightness_update(s); - break; - - case MP_GPIO_OUT_LO: - s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF); - break; - case MP_GPIO_OUT_HI: - s->out_state = (s->out_state & 0xFFFF) | (value << 16); - s->lcd_brightness = (s->lcd_brightness & 0xFFFF) | - (s->out_state & MP_GPIO_LCD_BRIGHTNESS); - musicpal_gpio_brightness_update(s); - qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1); - qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); - break; - - case MP_GPIO_IER_LO: - s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF); - break; - case MP_GPIO_IER_HI: - s->ier = (s->ier & 0xFFFF) | (value << 16); - break; - - case MP_GPIO_IMR_LO: - s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF); - break; - case MP_GPIO_IMR_HI: - s->imr = (s->imr & 0xFFFF) | (value << 16); - break; - } -} - -static const MemoryRegionOps musicpal_gpio_ops = { - .read = musicpal_gpio_read, - .write = musicpal_gpio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void musicpal_gpio_reset(DeviceState *d) -{ - musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, - SYS_BUS_DEVICE(d)); - - s->lcd_brightness = 0; - s->out_state = 0; - s->in_state = 0xffffffff; - s->ier = 0; - s->imr = 0; - s->isr = 0; -} - -static int musicpal_gpio_init(SysBusDevice *dev) -{ - musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->iomem, &musicpal_gpio_ops, s, - "musicpal-gpio", MP_GPIO_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); - - qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32); - - return 0; -} - -static const VMStateDescription musicpal_gpio_vmsd = { - .name = "musicpal_gpio", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state), - VMSTATE_UINT32(out_state, musicpal_gpio_state), - VMSTATE_UINT32(in_state, musicpal_gpio_state), - VMSTATE_UINT32(ier, musicpal_gpio_state), - VMSTATE_UINT32(imr, musicpal_gpio_state), - VMSTATE_UINT32(isr, musicpal_gpio_state), - VMSTATE_END_OF_LIST() - } -}; - -static void musicpal_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = musicpal_gpio_init; - dc->reset = musicpal_gpio_reset; - dc->vmsd = &musicpal_gpio_vmsd; -} - -static const TypeInfo musicpal_gpio_info = { - .name = "musicpal_gpio", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(musicpal_gpio_state), - .class_init = musicpal_gpio_class_init, -}; - -/* Keyboard codes & masks */ -#define KEY_RELEASED 0x80 -#define KEY_CODE 0x7f - -#define KEYCODE_TAB 0x0f -#define KEYCODE_ENTER 0x1c -#define KEYCODE_F 0x21 -#define KEYCODE_M 0x32 - -#define KEYCODE_EXTENDED 0xe0 -#define KEYCODE_UP 0x48 -#define KEYCODE_DOWN 0x50 -#define KEYCODE_LEFT 0x4b -#define KEYCODE_RIGHT 0x4d - -#define MP_KEY_WHEEL_VOL (1 << 0) -#define MP_KEY_WHEEL_VOL_INV (1 << 1) -#define MP_KEY_WHEEL_NAV (1 << 2) -#define MP_KEY_WHEEL_NAV_INV (1 << 3) -#define MP_KEY_BTN_FAVORITS (1 << 4) -#define MP_KEY_BTN_MENU (1 << 5) -#define MP_KEY_BTN_VOLUME (1 << 6) -#define MP_KEY_BTN_NAVIGATION (1 << 7) - -typedef struct musicpal_key_state { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t kbd_extended; - uint32_t pressed_keys; - qemu_irq out[8]; -} musicpal_key_state; - -static void musicpal_key_event(void *opaque, int keycode) -{ - musicpal_key_state *s = opaque; - uint32_t event = 0; - int i; - - if (keycode == KEYCODE_EXTENDED) { - s->kbd_extended = 1; - return; - } - - if (s->kbd_extended) { - switch (keycode & KEY_CODE) { - case KEYCODE_UP: - event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV; - break; - - case KEYCODE_DOWN: - event = MP_KEY_WHEEL_NAV; - break; - - case KEYCODE_LEFT: - event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV; - break; - - case KEYCODE_RIGHT: - event = MP_KEY_WHEEL_VOL; - break; - } - } else { - switch (keycode & KEY_CODE) { - case KEYCODE_F: - event = MP_KEY_BTN_FAVORITS; - break; - - case KEYCODE_TAB: - event = MP_KEY_BTN_VOLUME; - break; - - case KEYCODE_ENTER: - event = MP_KEY_BTN_NAVIGATION; - break; - - case KEYCODE_M: - event = MP_KEY_BTN_MENU; - break; - } - /* Do not repeat already pressed buttons */ - if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { - event = 0; - } - } - - if (event) { - /* Raise GPIO pin first if repeating a key */ - if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { - for (i = 0; i <= 7; i++) { - if (event & (1 << i)) { - qemu_set_irq(s->out[i], 1); - } - } - } - for (i = 0; i <= 7; i++) { - if (event & (1 << i)) { - qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED)); - } - } - if (keycode & KEY_RELEASED) { - s->pressed_keys &= ~event; - } else { - s->pressed_keys |= event; - } - } - - s->kbd_extended = 0; -} - -static int musicpal_key_init(SysBusDevice *dev) -{ - musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev); - - memory_region_init(&s->iomem, "dummy", 0); - sysbus_init_mmio(dev, &s->iomem); - - s->kbd_extended = 0; - s->pressed_keys = 0; - - qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); - - qemu_add_kbd_event_handler(musicpal_key_event, s); - - return 0; -} - -static const VMStateDescription musicpal_key_vmsd = { - .name = "musicpal_key", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(kbd_extended, musicpal_key_state), - VMSTATE_UINT32(pressed_keys, musicpal_key_state), - VMSTATE_END_OF_LIST() - } -}; - -static void musicpal_key_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = musicpal_key_init; - dc->vmsd = &musicpal_key_vmsd; -} - -static const TypeInfo musicpal_key_info = { - .name = "musicpal_key", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(musicpal_key_state), - .class_init = musicpal_key_class_init, -}; - -static struct arm_boot_info musicpal_binfo = { - .loader_start = 0x0, - .board_id = 0x20e, -}; - -static void musicpal_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - ARMCPU *cpu; - qemu_irq *cpu_pic; - qemu_irq pic[32]; - DeviceState *dev; - DeviceState *i2c_dev; - DeviceState *lcd_dev; - DeviceState *key_dev; - DeviceState *wm8750_dev; - SysBusDevice *s; - i2c_bus *i2c; - int i; - unsigned long flash_size; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - - if (!cpu_model) { - cpu_model = "arm926"; - } - cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - cpu_pic = arm_pic_init_cpu(cpu); - - /* For now we use a fixed - the original - RAM size */ - memory_region_init_ram(ram, "musicpal.ram", MP_RAM_DEFAULT_SIZE); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space_mem, 0, ram); - - memory_region_init_ram(sram, "musicpal.sram", MP_SRAM_SIZE); - vmstate_register_ram_global(sram); - memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram); - - dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE, - cpu_pic[ARM_PIC_CPU_IRQ]); - for (i = 0; i < 32; i++) { - pic[i] = qdev_get_gpio_in(dev, i); - } - sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ], - pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ], - pic[MP_TIMER4_IRQ], NULL); - - if (serial_hds[0]) { - serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ], - 1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN); - } - if (serial_hds[1]) { - serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ], - 1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN); - } - - /* Register flash */ - dinfo = drive_get(IF_PFLASH, 0, 0); - if (dinfo) { - flash_size = bdrv_getlength(dinfo->bdrv); - if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 && - flash_size != 32*1024*1024) { - fprintf(stderr, "Invalid flash image size\n"); - exit(1); - } - - /* - * The original U-Boot accesses the flash at 0xFE000000 instead of - * 0xFF800000 (if there is 8 MB flash). So remap flash access if the - * image is smaller than 32 MB. - */ -#ifdef TARGET_WORDS_BIGENDIAN - pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, - "musicpal.flash", flash_size, - dinfo->bdrv, 0x10000, - (flash_size + 0xffff) >> 16, - MP_FLASH_SIZE_MAX / flash_size, - 2, 0x00BF, 0x236D, 0x0000, 0x0000, - 0x5555, 0x2AAA, 1); -#else - pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, - "musicpal.flash", flash_size, - dinfo->bdrv, 0x10000, - (flash_size + 0xffff) >> 16, - MP_FLASH_SIZE_MAX / flash_size, - 2, 0x00BF, 0x236D, 0x0000, 0x0000, - 0x5555, 0x2AAA, 0); -#endif - - } - sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL); - - qemu_check_nic_model(&nd_table[0], "mv88w8618"); - dev = qdev_create(NULL, "mv88w8618_eth"); - qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]); - - sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); - - musicpal_misc_init(SYS_BUS_DEVICE(dev)); - - dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); - i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); - i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"); - - lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); - key_dev = sysbus_create_simple("musicpal_key", -1, NULL); - - /* I2C read data */ - qdev_connect_gpio_out(i2c_dev, 0, - qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT)); - /* I2C data */ - qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0)); - /* I2C clock */ - qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1)); - - for (i = 0; i < 3; i++) { - qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i)); - } - for (i = 0; i < 4; i++) { - qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8)); - } - for (i = 4; i < 8; i++) { - qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); - } - - wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR); - dev = qdev_create(NULL, "mv88w8618_audio"); - s = SYS_BUS_DEVICE(dev); - qdev_prop_set_ptr(dev, "wm8750", wm8750_dev); - qdev_init_nofail(dev); - sysbus_mmio_map(s, 0, MP_AUDIO_BASE); - sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); - - musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; - musicpal_binfo.kernel_filename = kernel_filename; - musicpal_binfo.kernel_cmdline = kernel_cmdline; - musicpal_binfo.initrd_filename = initrd_filename; - arm_load_kernel(cpu, &musicpal_binfo); -} - -static QEMUMachine musicpal_machine = { - .name = "musicpal", - .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)", - .init = musicpal_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void musicpal_machine_init(void) -{ - qemu_register_machine(&musicpal_machine); -} - -machine_init(musicpal_machine_init); - -static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = mv88w8618_wlan_init; -} - -static const TypeInfo mv88w8618_wlan_info = { - .name = "mv88w8618_wlan", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SysBusDevice), - .class_init = mv88w8618_wlan_class_init, -}; - -static void musicpal_register_types(void) -{ - type_register_static(&mv88w8618_pic_info); - type_register_static(&mv88w8618_pit_info); - type_register_static(&mv88w8618_flashcfg_info); - type_register_static(&mv88w8618_eth_info); - type_register_static(&mv88w8618_wlan_info); - type_register_static(&musicpal_lcd_info); - type_register_static(&musicpal_gpio_info); - type_register_static(&musicpal_key_info); -} - -type_init(musicpal_register_types) diff --git a/hw/nseries.c b/hw/nseries.c deleted file mode 100644 index c5bf9f95b3..0000000000 --- a/hw/nseries.c +++ /dev/null @@ -1,1430 +0,0 @@ -/* - * Nokia N-series internet tablets. - * - * Copyright (C) 2007 Nokia Corporation - * Written by Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "qemu-common.h" -#include "sysemu/sysemu.h" -#include "hw/omap.h" -#include "hw/arm-misc.h" -#include "hw/irq.h" -#include "ui/console.h" -#include "hw/boards.h" -#include "hw/i2c.h" -#include "hw/devices.h" -#include "hw/flash.h" -#include "hw/hw.h" -#include "hw/bt.h" -#include "hw/loader.h" -#include "sysemu/blockdev.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -/* Nokia N8x0 support */ -struct n800_s { - struct omap_mpu_state_s *mpu; - - struct rfbi_chip_s blizzard; - struct { - void *opaque; - uint32_t (*txrx)(void *opaque, uint32_t value, int len); - uWireSlave *chip; - } ts; - - int keymap[0x80]; - DeviceState *kbd; - - DeviceState *usb; - void *retu; - void *tahvo; - DeviceState *nand; -}; - -/* GPIO pins */ -#define N8X0_TUSB_ENABLE_GPIO 0 -#define N800_MMC2_WP_GPIO 8 -#define N800_UNKNOWN_GPIO0 9 /* out */ -#define N810_MMC2_VIOSD_GPIO 9 -#define N810_HEADSET_AMP_GPIO 10 -#define N800_CAM_TURN_GPIO 12 -#define N810_GPS_RESET_GPIO 12 -#define N800_BLIZZARD_POWERDOWN_GPIO 15 -#define N800_MMC1_WP_GPIO 23 -#define N810_MMC2_VSD_GPIO 23 -#define N8X0_ONENAND_GPIO 26 -#define N810_BLIZZARD_RESET_GPIO 30 -#define N800_UNKNOWN_GPIO2 53 /* out */ -#define N8X0_TUSB_INT_GPIO 58 -#define N8X0_BT_WKUP_GPIO 61 -#define N8X0_STI_GPIO 62 -#define N8X0_CBUS_SEL_GPIO 64 -#define N8X0_CBUS_DAT_GPIO 65 -#define N8X0_CBUS_CLK_GPIO 66 -#define N8X0_WLAN_IRQ_GPIO 87 -#define N8X0_BT_RESET_GPIO 92 -#define N8X0_TEA5761_CS_GPIO 93 -#define N800_UNKNOWN_GPIO 94 -#define N810_TSC_RESET_GPIO 94 -#define N800_CAM_ACT_GPIO 95 -#define N810_GPS_WAKEUP_GPIO 95 -#define N8X0_MMC_CS_GPIO 96 -#define N8X0_WLAN_PWR_GPIO 97 -#define N8X0_BT_HOST_WKUP_GPIO 98 -#define N810_SPEAKER_AMP_GPIO 101 -#define N810_KB_LOCK_GPIO 102 -#define N800_TSC_TS_GPIO 103 -#define N810_TSC_TS_GPIO 106 -#define N8X0_HEADPHONE_GPIO 107 -#define N8X0_RETU_GPIO 108 -#define N800_TSC_KP_IRQ_GPIO 109 -#define N810_KEYBOARD_GPIO 109 -#define N800_BAT_COVER_GPIO 110 -#define N810_SLIDE_GPIO 110 -#define N8X0_TAHVO_GPIO 111 -#define N800_UNKNOWN_GPIO4 112 /* out */ -#define N810_SLEEPX_LED_GPIO 112 -#define N800_TSC_RESET_GPIO 118 /* ? */ -#define N810_AIC33_RESET_GPIO 118 -#define N800_TSC_UNKNOWN_GPIO 119 /* out */ -#define N8X0_TMP105_GPIO 125 - -/* Config */ -#define BT_UART 0 -#define XLDR_LL_UART 1 - -/* Addresses on the I2C bus 0 */ -#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */ -#define N8X0_TCM825x_ADDR 0x29 /* Camera */ -#define N810_LP5521_ADDR 0x32 /* LEDs */ -#define N810_TSL2563_ADDR 0x3d /* Light sensor */ -#define N810_LM8323_ADDR 0x45 /* Keyboard */ -/* Addresses on the I2C bus 1 */ -#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */ -#define N8X0_MENELAUS_ADDR 0x72 /* Power management */ - -/* Chipselects on GPMC NOR interface */ -#define N8X0_ONENAND_CS 0 -#define N8X0_USB_ASYNC_CS 1 -#define N8X0_USB_SYNC_CS 4 - -#define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81 - -static void n800_mmc_cs_cb(void *opaque, int line, int level) -{ - /* TODO: this seems to actually be connected to the menelaus, to - * which also both MMC slots connect. */ - omap_mmc_enable((struct omap_mmc_s *) opaque, !level); - - printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1); -} - -static void n8x0_gpio_setup(struct n800_s *s) -{ - qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]); - - qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO)); -} - -#define MAEMO_CAL_HEADER(...) \ - 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \ - __VA_ARGS__, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - -static const uint8_t n8x0_cal_wlan_mac[] = { - MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c') - 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3, - 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, -}; - -static const uint8_t n8x0_cal_bt_id[] = { - MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0) - 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96, - 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00, - N8X0_BD_ADDR, -}; - -static void n8x0_nand_setup(struct n800_s *s) -{ - char *otp_region; - DriveInfo *dinfo; - - s->nand = qdev_create(NULL, "onenand"); - qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG); - /* Either 0x40 or 0x48 are OK for the device ID */ - qdev_prop_set_uint16(s->nand, "device_id", 0x48); - qdev_prop_set_uint16(s->nand, "version_id", 0); - qdev_prop_set_int32(s->nand, "shift", 1); - dinfo = drive_get(IF_MTD, 0, 0); - if (dinfo && dinfo->bdrv) { - qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv); - } - qdev_init_nofail(s->nand); - sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, - qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); - omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, - sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0)); - otp_region = onenand_raw_otp(s->nand); - - memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac)); - memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id)); - /* XXX: in theory should also update the OOB for both pages */ -} - -static qemu_irq n8x0_system_powerdown; - -static void n8x0_powerdown_req(Notifier *n, void *opaque) -{ - qemu_irq_raise(n8x0_system_powerdown); -} - -static Notifier n8x0_system_powerdown_notifier = { - .notify = n8x0_powerdown_req -}; - -static void n8x0_i2c_setup(struct n800_s *s) -{ - DeviceState *dev; - qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO); - i2c_bus *i2c = omap_i2c_bus(s->mpu->i2c[0]); - - /* Attach a menelaus PM chip */ - dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR); - qdev_connect_gpio_out(dev, 3, - qdev_get_gpio_in(s->mpu->ih[0], - OMAP_INT_24XX_SYS_NIRQ)); - - n8x0_system_powerdown = qdev_get_gpio_in(dev, 3); - qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier); - - /* Attach a TMP105 PM chip (A0 wired to ground) */ - dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR); - qdev_connect_gpio_out(dev, 0, tmp_irq); -} - -/* Touchscreen and keypad controller */ -static MouseTransformInfo n800_pointercal = { - .x = 800, - .y = 480, - .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, -}; - -static MouseTransformInfo n810_pointercal = { - .x = 800, - .y = 480, - .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 }, -}; - -#define RETU_KEYCODE 61 /* F3 */ - -static void n800_key_event(void *opaque, int keycode) -{ - struct n800_s *s = (struct n800_s *) opaque; - int code = s->keymap[keycode & 0x7f]; - - if (code == -1) { - if ((keycode & 0x7f) == RETU_KEYCODE) - retu_key_event(s->retu, !(keycode & 0x80)); - return; - } - - tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80)); -} - -static const int n800_keys[16] = { - -1, - 72, /* Up */ - 63, /* Home (F5) */ - -1, - 75, /* Left */ - 28, /* Enter */ - 77, /* Right */ - -1, - 1, /* Cycle (ESC) */ - 80, /* Down */ - 62, /* Menu (F4) */ - -1, - 66, /* Zoom- (F8) */ - 64, /* FullScreen (F6) */ - 65, /* Zoom+ (F7) */ - -1, -}; - -static void n800_tsc_kbd_setup(struct n800_s *s) -{ - int i; - - /* XXX: are the three pins inverted inside the chip between the - * tsc and the cpu (N4111)? */ - qemu_irq penirq = NULL; /* NC */ - qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO); - qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO); - - s->ts.chip = tsc2301_init(penirq, kbirq, dav); - s->ts.opaque = s->ts.chip->opaque; - s->ts.txrx = tsc210x_txrx; - - for (i = 0; i < 0x80; i ++) - s->keymap[i] = -1; - for (i = 0; i < 0x10; i ++) - if (n800_keys[i] >= 0) - s->keymap[n800_keys[i]] = i; - - qemu_add_kbd_event_handler(n800_key_event, s); - - tsc210x_set_transform(s->ts.chip, &n800_pointercal); -} - -static void n810_tsc_setup(struct n800_s *s) -{ - qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO); - - s->ts.opaque = tsc2005_init(pintdav); - s->ts.txrx = tsc2005_txrx; - - tsc2005_set_transform(s->ts.opaque, &n810_pointercal); -} - -/* N810 Keyboard controller */ -static void n810_key_event(void *opaque, int keycode) -{ - struct n800_s *s = (struct n800_s *) opaque; - int code = s->keymap[keycode & 0x7f]; - - if (code == -1) { - if ((keycode & 0x7f) == RETU_KEYCODE) - retu_key_event(s->retu, !(keycode & 0x80)); - return; - } - - lm832x_key_event(s->kbd, code, !(keycode & 0x80)); -} - -#define M 0 - -static int n810_keys[0x80] = { - [0x01] = 16, /* Q */ - [0x02] = 37, /* K */ - [0x03] = 24, /* O */ - [0x04] = 25, /* P */ - [0x05] = 14, /* Backspace */ - [0x06] = 30, /* A */ - [0x07] = 31, /* S */ - [0x08] = 32, /* D */ - [0x09] = 33, /* F */ - [0x0a] = 34, /* G */ - [0x0b] = 35, /* H */ - [0x0c] = 36, /* J */ - - [0x11] = 17, /* W */ - [0x12] = 62, /* Menu (F4) */ - [0x13] = 38, /* L */ - [0x14] = 40, /* ' (Apostrophe) */ - [0x16] = 44, /* Z */ - [0x17] = 45, /* X */ - [0x18] = 46, /* C */ - [0x19] = 47, /* V */ - [0x1a] = 48, /* B */ - [0x1b] = 49, /* N */ - [0x1c] = 42, /* Shift (Left shift) */ - [0x1f] = 65, /* Zoom+ (F7) */ - - [0x21] = 18, /* E */ - [0x22] = 39, /* ; (Semicolon) */ - [0x23] = 12, /* - (Minus) */ - [0x24] = 13, /* = (Equal) */ - [0x2b] = 56, /* Fn (Left Alt) */ - [0x2c] = 50, /* M */ - [0x2f] = 66, /* Zoom- (F8) */ - - [0x31] = 19, /* R */ - [0x32] = 29 | M, /* Right Ctrl */ - [0x34] = 57, /* Space */ - [0x35] = 51, /* , (Comma) */ - [0x37] = 72 | M, /* Up */ - [0x3c] = 82 | M, /* Compose (Insert) */ - [0x3f] = 64, /* FullScreen (F6) */ - - [0x41] = 20, /* T */ - [0x44] = 52, /* . (Dot) */ - [0x46] = 77 | M, /* Right */ - [0x4f] = 63, /* Home (F5) */ - [0x51] = 21, /* Y */ - [0x53] = 80 | M, /* Down */ - [0x55] = 28, /* Enter */ - [0x5f] = 1, /* Cycle (ESC) */ - - [0x61] = 22, /* U */ - [0x64] = 75 | M, /* Left */ - - [0x71] = 23, /* I */ -#if 0 - [0x75] = 28 | M, /* KP Enter (KP Enter) */ -#else - [0x75] = 15, /* KP Enter (Tab) */ -#endif -}; - -#undef M - -static void n810_kbd_setup(struct n800_s *s) -{ - qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO); - int i; - - for (i = 0; i < 0x80; i ++) - s->keymap[i] = -1; - for (i = 0; i < 0x80; i ++) - if (n810_keys[i] > 0) - s->keymap[n810_keys[i]] = i; - - qemu_add_kbd_event_handler(n810_key_event, s); - - /* Attach the LM8322 keyboard to the I2C bus, - * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ - s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]), - "lm8323", N810_LM8323_ADDR); - qdev_connect_gpio_out(s->kbd, 0, kbd_irq); -} - -/* LCD MIPI DBI-C controller (URAL) */ -struct mipid_s { - int resp[4]; - int param[4]; - int p; - int pm; - int cmd; - - int sleep; - int booster; - int te; - int selfcheck; - int partial; - int normal; - int vscr; - int invert; - int onoff; - int gamma; - uint32_t id; -}; - -static void mipid_reset(struct mipid_s *s) -{ - if (!s->sleep) - fprintf(stderr, "%s: Display off\n", __FUNCTION__); - - s->pm = 0; - s->cmd = 0; - - s->sleep = 1; - s->booster = 0; - s->selfcheck = - (1 << 7) | /* Register loading OK. */ - (1 << 5) | /* The chip is attached. */ - (1 << 4); /* Display glass still in one piece. */ - s->te = 0; - s->partial = 0; - s->normal = 1; - s->vscr = 0; - s->invert = 0; - s->onoff = 1; - s->gamma = 0; -} - -static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) -{ - struct mipid_s *s = (struct mipid_s *) opaque; - uint8_t ret; - - if (len > 9) - hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len); - - if (s->p >= ARRAY_SIZE(s->resp)) - ret = 0; - else - ret = s->resp[s->p ++]; - if (s->pm --> 0) - s->param[s->pm] = cmd; - else - s->cmd = cmd; - - switch (s->cmd) { - case 0x00: /* NOP */ - break; - - case 0x01: /* SWRESET */ - mipid_reset(s); - break; - - case 0x02: /* BSTROFF */ - s->booster = 0; - break; - case 0x03: /* BSTRON */ - s->booster = 1; - break; - - case 0x04: /* RDDID */ - s->p = 0; - s->resp[0] = (s->id >> 16) & 0xff; - s->resp[1] = (s->id >> 8) & 0xff; - s->resp[2] = (s->id >> 0) & 0xff; - break; - - case 0x06: /* RD_RED */ - case 0x07: /* RD_GREEN */ - /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so - * for the bootloader one needs to change this. */ - case 0x08: /* RD_BLUE */ - s->p = 0; - /* TODO: return first pixel components */ - s->resp[0] = 0x01; - break; - - case 0x09: /* RDDST */ - s->p = 0; - s->resp[0] = s->booster << 7; - s->resp[1] = (5 << 4) | (s->partial << 2) | - (s->sleep << 1) | s->normal; - s->resp[2] = (s->vscr << 7) | (s->invert << 5) | - (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2); - s->resp[3] = s->gamma << 6; - break; - - case 0x0a: /* RDDPM */ - s->p = 0; - s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) | - (s->partial << 5) | (s->sleep << 6) | (s->booster << 7); - break; - case 0x0b: /* RDDMADCTR */ - s->p = 0; - s->resp[0] = 0; - break; - case 0x0c: /* RDDCOLMOD */ - s->p = 0; - s->resp[0] = 5; /* 65K colours */ - break; - case 0x0d: /* RDDIM */ - s->p = 0; - s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma; - break; - case 0x0e: /* RDDSM */ - s->p = 0; - s->resp[0] = s->te << 7; - break; - case 0x0f: /* RDDSDR */ - s->p = 0; - s->resp[0] = s->selfcheck; - break; - - case 0x10: /* SLPIN */ - s->sleep = 1; - break; - case 0x11: /* SLPOUT */ - s->sleep = 0; - s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */ - break; - - case 0x12: /* PTLON */ - s->partial = 1; - s->normal = 0; - s->vscr = 0; - break; - case 0x13: /* NORON */ - s->partial = 0; - s->normal = 1; - s->vscr = 0; - break; - - case 0x20: /* INVOFF */ - s->invert = 0; - break; - case 0x21: /* INVON */ - s->invert = 1; - break; - - case 0x22: /* APOFF */ - case 0x23: /* APON */ - goto bad_cmd; - - case 0x25: /* WRCNTR */ - if (s->pm < 0) - s->pm = 1; - goto bad_cmd; - - case 0x26: /* GAMSET */ - if (!s->pm) - s->gamma = ffs(s->param[0] & 0xf) - 1; - else if (s->pm < 0) - s->pm = 1; - break; - - case 0x28: /* DISPOFF */ - s->onoff = 0; - fprintf(stderr, "%s: Display off\n", __FUNCTION__); - break; - case 0x29: /* DISPON */ - s->onoff = 1; - fprintf(stderr, "%s: Display on\n", __FUNCTION__); - break; - - case 0x2a: /* CASET */ - case 0x2b: /* RASET */ - case 0x2c: /* RAMWR */ - case 0x2d: /* RGBSET */ - case 0x2e: /* RAMRD */ - case 0x30: /* PTLAR */ - case 0x33: /* SCRLAR */ - goto bad_cmd; - - case 0x34: /* TEOFF */ - s->te = 0; - break; - case 0x35: /* TEON */ - if (!s->pm) - s->te = 1; - else if (s->pm < 0) - s->pm = 1; - break; - - case 0x36: /* MADCTR */ - goto bad_cmd; - - case 0x37: /* VSCSAD */ - s->partial = 0; - s->normal = 0; - s->vscr = 1; - break; - - case 0x38: /* IDMOFF */ - case 0x39: /* IDMON */ - case 0x3a: /* COLMOD */ - goto bad_cmd; - - case 0xb0: /* CLKINT / DISCTL */ - case 0xb1: /* CLKEXT */ - if (s->pm < 0) - s->pm = 2; - break; - - case 0xb4: /* FRMSEL */ - break; - - case 0xb5: /* FRM8SEL */ - case 0xb6: /* TMPRNG / INIESC */ - case 0xb7: /* TMPHIS / NOP2 */ - case 0xb8: /* TMPREAD / MADCTL */ - case 0xba: /* DISTCTR */ - case 0xbb: /* EPVOL */ - goto bad_cmd; - - case 0xbd: /* Unknown */ - s->p = 0; - s->resp[0] = 0; - s->resp[1] = 1; - break; - - case 0xc2: /* IFMOD */ - if (s->pm < 0) - s->pm = 2; - break; - - case 0xc6: /* PWRCTL */ - case 0xc7: /* PPWRCTL */ - case 0xd0: /* EPWROUT */ - case 0xd1: /* EPWRIN */ - case 0xd4: /* RDEV */ - case 0xd5: /* RDRR */ - goto bad_cmd; - - case 0xda: /* RDID1 */ - s->p = 0; - s->resp[0] = (s->id >> 16) & 0xff; - break; - case 0xdb: /* RDID2 */ - s->p = 0; - s->resp[0] = (s->id >> 8) & 0xff; - break; - case 0xdc: /* RDID3 */ - s->p = 0; - s->resp[0] = (s->id >> 0) & 0xff; - break; - - default: - bad_cmd: - fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd); - break; - } - - return ret; -} - -static void *mipid_init(void) -{ - struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s)); - - s->id = 0x838f03; - mipid_reset(s); - - return s; -} - -static void n8x0_spi_setup(struct n800_s *s) -{ - void *tsc = s->ts.opaque; - void *mipid = mipid_init(); - - omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0); - omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1); -} - -/* This task is normally performed by the bootloader. If we're loading - * a kernel directly, we need to enable the Blizzard ourselves. */ -static void n800_dss_init(struct rfbi_chip_s *chip) -{ - uint8_t *fb_blank; - - chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */ - chip->write(chip->opaque, 1, 0x64); - chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */ - chip->write(chip->opaque, 1, 0x1e); - chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */ - chip->write(chip->opaque, 1, 0xe0); - chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */ - chip->write(chip->opaque, 1, 0x01); - chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */ - chip->write(chip->opaque, 1, 0x06); - chip->write(chip->opaque, 0, 0x68); /* Display Mode register */ - chip->write(chip->opaque, 1, 1); /* Enable bit */ - - chip->write(chip->opaque, 0, 0x6c); - chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ - chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */ - chip->write(chip->opaque, 1, 0x03); /* Input X End Position */ - chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */ - chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */ - chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ - chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */ - chip->write(chip->opaque, 1, 0x03); /* Output X End Position */ - chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */ - chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */ - chip->write(chip->opaque, 1, 0x01); /* Input Data Format */ - chip->write(chip->opaque, 1, 0x01); /* Data Source Select */ - - fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2); - /* Display Memory Data Port */ - chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800); - g_free(fb_blank); -} - -static void n8x0_dss_setup(struct n800_s *s) -{ - s->blizzard.opaque = s1d13745_init(NULL); - s->blizzard.block = s1d13745_write_block; - s->blizzard.write = s1d13745_write; - s->blizzard.read = s1d13745_read; - - omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard); -} - -static void n8x0_cbus_setup(struct n800_s *s) -{ - qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO); - qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO); - qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO); - - CBus *cbus = cbus_init(dat_out); - - qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel); - - cbus_attach(cbus, s->retu = retu_init(retu_irq, 1)); - cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1)); -} - -static void n8x0_uart_setup(struct n800_s *s) -{ - CharDriverState *radio = uart_hci_init( - qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); - - qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO, - csrhci_pins_get(radio)[csrhci_pin_reset]); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO, - csrhci_pins_get(radio)[csrhci_pin_wakeup]); - - omap_uart_attach(s->mpu->uart[BT_UART], radio); -} - -static void n8x0_usb_setup(struct n800_s *s) -{ - SysBusDevice *dev; - s->usb = qdev_create(NULL, "tusb6010"); - dev = SYS_BUS_DEVICE(s->usb); - qdev_init_nofail(s->usb); - sysbus_connect_irq(dev, 0, - qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); - /* Using the NOR interface */ - omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS, - sysbus_mmio_get_region(dev, 0)); - omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS, - sysbus_mmio_get_region(dev, 1)); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO, - qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */ -} - -/* Setup done before the main bootloader starts by some early setup code - * - used when we want to run the main bootloader in emulation. This - * isn't documented. */ -static uint32_t n800_pinout[104] = { - 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, - 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, - 0x08080808, 0x180800c4, 0x00b80000, 0x08080808, - 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128, - 0x01241800, 0x18181818, 0x000000f0, 0x01300000, - 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b, - 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080, - 0x007c0000, 0x00000000, 0x00000088, 0x00840000, - 0x00000000, 0x00000094, 0x00980300, 0x0f180003, - 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c, - 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008, - 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f, - 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc, - 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008, - 0x00000000, 0x00000038, 0x00340000, 0x00000000, - 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060, - 0x005c0808, 0x08080808, 0x08080058, 0x00540808, - 0x08080808, 0x0808006c, 0x00680808, 0x08080808, - 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0, - 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808, - 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff, - 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100, - 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a, - 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00, - 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118, - 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b, -}; - -static void n800_setup_nolo_tags(void *sram_base) -{ - int i; - uint32_t *p = sram_base + 0x8000; - uint32_t *v = sram_base + 0xa000; - - memset(p, 0, 0x3000); - - strcpy((void *) (p + 0), "QEMU N800"); - - strcpy((void *) (p + 8), "F5"); - - stl_raw(p + 10, 0x04f70000); - strcpy((void *) (p + 9), "RX-34"); - - /* RAM size in MB? */ - stl_raw(p + 12, 0x80); - - /* Pointer to the list of tags */ - stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000); - - /* The NOLO tags start here */ - p = sram_base + 0x9000; -#define ADD_TAG(tag, len) \ - stw_raw((uint16_t *) p + 0, tag); \ - stw_raw((uint16_t *) p + 1, len); p ++; \ - stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff)); - - /* OMAP STI console? Pin out settings? */ - ADD_TAG(0x6e01, 414); - for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++) - stl_raw(v ++, n800_pinout[i]); - - /* Kernel memsize? */ - ADD_TAG(0x6e05, 1); - stl_raw(v ++, 2); - - /* NOLO serial console */ - ADD_TAG(0x6e02, 4); - stl_raw(v ++, XLDR_LL_UART); /* UART number (1 - 3) */ - -#if 0 - /* CBUS settings (Retu/AVilma) */ - ADD_TAG(0x6e03, 6); - stw_raw((uint16_t *) v + 0, 65); /* CBUS GPIO0 */ - stw_raw((uint16_t *) v + 1, 66); /* CBUS GPIO1 */ - stw_raw((uint16_t *) v + 2, 64); /* CBUS GPIO2 */ - v += 2; -#endif - - /* Nokia ASIC BB5 (Retu/Tahvo) */ - ADD_TAG(0x6e0a, 4); - stw_raw((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */ - stw_raw((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */ - v ++; - - /* LCD console? */ - ADD_TAG(0x6e04, 4); - stw_raw((uint16_t *) v + 0, 30); /* ??? */ - stw_raw((uint16_t *) v + 1, 24); /* ??? */ - v ++; - -#if 0 - /* LCD settings */ - ADD_TAG(0x6e06, 2); - stw_raw((uint16_t *) (v ++), 15); /* ??? */ -#endif - - /* I^2C (Menelaus) */ - ADD_TAG(0x6e07, 4); - stl_raw(v ++, 0x00720000); /* ??? */ - - /* Unknown */ - ADD_TAG(0x6e0b, 6); - stw_raw((uint16_t *) v + 0, 94); /* ??? */ - stw_raw((uint16_t *) v + 1, 23); /* ??? */ - stw_raw((uint16_t *) v + 2, 0); /* ??? */ - v += 2; - - /* OMAP gpio switch info */ - ADD_TAG(0x6e0c, 80); - strcpy((void *) v, "bat_cover"); v += 3; - stw_raw((uint16_t *) v + 0, 110); /* GPIO num ??? */ - stw_raw((uint16_t *) v + 1, 1); /* GPIO num ??? */ - v += 2; - strcpy((void *) v, "cam_act"); v += 3; - stw_raw((uint16_t *) v + 0, 95); /* GPIO num ??? */ - stw_raw((uint16_t *) v + 1, 32); /* GPIO num ??? */ - v += 2; - strcpy((void *) v, "cam_turn"); v += 3; - stw_raw((uint16_t *) v + 0, 12); /* GPIO num ??? */ - stw_raw((uint16_t *) v + 1, 33); /* GPIO num ??? */ - v += 2; - strcpy((void *) v, "headphone"); v += 3; - stw_raw((uint16_t *) v + 0, 107); /* GPIO num ??? */ - stw_raw((uint16_t *) v + 1, 17); /* GPIO num ??? */ - v += 2; - - /* Bluetooth */ - ADD_TAG(0x6e0e, 12); - stl_raw(v ++, 0x5c623d01); /* ??? */ - stl_raw(v ++, 0x00000201); /* ??? */ - stl_raw(v ++, 0x00000000); /* ??? */ - - /* CX3110x WLAN settings */ - ADD_TAG(0x6e0f, 8); - stl_raw(v ++, 0x00610025); /* ??? */ - stl_raw(v ++, 0xffff0057); /* ??? */ - - /* MMC host settings */ - ADD_TAG(0x6e10, 12); - stl_raw(v ++, 0xffff000f); /* ??? */ - stl_raw(v ++, 0xffffffff); /* ??? */ - stl_raw(v ++, 0x00000060); /* ??? */ - - /* OneNAND chip select */ - ADD_TAG(0x6e11, 10); - stl_raw(v ++, 0x00000401); /* ??? */ - stl_raw(v ++, 0x0002003a); /* ??? */ - stl_raw(v ++, 0x00000002); /* ??? */ - - /* TEA5761 sensor settings */ - ADD_TAG(0x6e12, 2); - stl_raw(v ++, 93); /* GPIO num ??? */ - -#if 0 - /* Unknown tag */ - ADD_TAG(6e09, 0); - - /* Kernel UART / console */ - ADD_TAG(6e12, 0); -#endif - - /* End of the list */ - stl_raw(p ++, 0x00000000); - stl_raw(p ++, 0x00000000); -} - -/* This task is normally performed by the bootloader. If we're loading - * a kernel directly, we need to set up GPMC mappings ourselves. */ -static void n800_gpmc_init(struct n800_s *s) -{ - uint32_t config7 = - (0xf << 8) | /* MASKADDRESS */ - (1 << 6) | /* CSVALID */ - (4 << 0); /* BASEADDRESS */ - - cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */ - (void *) &config7, sizeof(config7)); -} - -/* Setup sequence done by the bootloader */ -static void n8x0_boot_init(void *opaque) -{ - struct n800_s *s = (struct n800_s *) opaque; - uint32_t buf; - - /* PRCM setup */ -#define omap_writel(addr, val) \ - buf = (val); \ - cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf)) - - omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */ - omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */ - omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */ - omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */ - omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */ - omap_writel(0x48008098, 0); /* PRCM_POLCTRL */ - omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */ - omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */ - omap_writel(0x48008158, 1); /* RM_RSTST_MPU */ - omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */ - omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */ - omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */ - omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */ - omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */ - omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */ - omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */ - omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */ - omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */ - omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */ - omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */ - omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */ - omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */ - omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */ - omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */ - omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */ - omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */ - omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */ - omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */ - omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */ - omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */ - omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */ - omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */ - omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */ - omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */ - omap_writel(0x48008540, /* CM_CLKSEL1_PLL */ - (0x78 << 12) | (6 << 8)); - omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */ - - /* GPMC setup */ - n800_gpmc_init(s); - - /* Video setup */ - n800_dss_init(&s->blizzard); - - /* CPU setup */ - s->mpu->cpu->env.GE = 0x5; - - /* If the machine has a slided keyboard, open it */ - if (s->kbd) - qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO)); -} - -#define OMAP_TAG_NOKIA_BT 0x4e01 -#define OMAP_TAG_WLAN_CX3110X 0x4e02 -#define OMAP_TAG_CBUS 0x4e03 -#define OMAP_TAG_EM_ASIC_BB5 0x4e04 - -static struct omap_gpiosw_info_s { - const char *name; - int line; - int type; -} n800_gpiosw_info[] = { - { - "bat_cover", N800_BAT_COVER_GPIO, - OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, - }, { - "cam_act", N800_CAM_ACT_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY, - }, { - "cam_turn", N800_CAM_TURN_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED, - }, { - "headphone", N8X0_HEADPHONE_GPIO, - OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, - }, - { NULL } -}, n810_gpiosw_info[] = { - { - "gps_reset", N810_GPS_RESET_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, - }, { - "gps_wakeup", N810_GPS_WAKEUP_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, - }, { - "headphone", N8X0_HEADPHONE_GPIO, - OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, - }, { - "kb_lock", N810_KB_LOCK_GPIO, - OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, - }, { - "sleepx_led", N810_SLEEPX_LED_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT, - }, { - "slide", N810_SLIDE_GPIO, - OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, - }, - { NULL } -}; - -static struct omap_partition_info_s { - uint32_t offset; - uint32_t size; - int mask; - const char *name; -} n800_part_info[] = { - { 0x00000000, 0x00020000, 0x3, "bootloader" }, - { 0x00020000, 0x00060000, 0x0, "config" }, - { 0x00080000, 0x00200000, 0x0, "kernel" }, - { 0x00280000, 0x00200000, 0x3, "initfs" }, - { 0x00480000, 0x0fb80000, 0x3, "rootfs" }, - - { 0, 0, 0, NULL } -}, n810_part_info[] = { - { 0x00000000, 0x00020000, 0x3, "bootloader" }, - { 0x00020000, 0x00060000, 0x0, "config" }, - { 0x00080000, 0x00220000, 0x0, "kernel" }, - { 0x002a0000, 0x00400000, 0x0, "initfs" }, - { 0x006a0000, 0x0f960000, 0x0, "rootfs" }, - - { 0, 0, 0, NULL } -}; - -static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }}; - -static int n8x0_atag_setup(void *p, int model) -{ - uint8_t *b; - uint16_t *w; - uint32_t *l; - struct omap_gpiosw_info_s *gpiosw; - struct omap_partition_info_s *partition; - const char *tag; - - w = p; - - stw_raw(w ++, OMAP_TAG_UART); /* u16 tag */ - stw_raw(w ++, 4); /* u16 len */ - stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ - w ++; - -#if 0 - stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */ - stw_raw(w ++, 4); /* u16 len */ - stw_raw(w ++, XLDR_LL_UART + 1); /* u8 console_uart */ - stw_raw(w ++, 115200); /* u32 console_speed */ -#endif - - stw_raw(w ++, OMAP_TAG_LCD); /* u16 tag */ - stw_raw(w ++, 36); /* u16 len */ - strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */ - w += 8; - strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */ - w += 8; - stw_raw(w ++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */ - stw_raw(w ++, 24); /* u8 data_lines */ - - stw_raw(w ++, OMAP_TAG_CBUS); /* u16 tag */ - stw_raw(w ++, 8); /* u16 len */ - stw_raw(w ++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */ - stw_raw(w ++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */ - stw_raw(w ++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */ - w ++; - - stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */ - stw_raw(w ++, 4); /* u16 len */ - stw_raw(w ++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */ - stw_raw(w ++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */ - - gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info; - for (; gpiosw->name; gpiosw ++) { - stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ - stw_raw(w ++, 20); /* u16 len */ - strcpy((void *) w, gpiosw->name); /* char name[12] */ - w += 6; - stw_raw(w ++, gpiosw->line); /* u16 gpio */ - stw_raw(w ++, gpiosw->type); - stw_raw(w ++, 0); - stw_raw(w ++, 0); - } - - stw_raw(w ++, OMAP_TAG_NOKIA_BT); /* u16 tag */ - stw_raw(w ++, 12); /* u16 len */ - b = (void *) w; - stb_raw(b ++, 0x01); /* u8 chip_type (CSR) */ - stb_raw(b ++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */ - stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */ - stb_raw(b ++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */ - stb_raw(b ++, BT_UART + 1); /* u8 bt_uart */ - memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */ - b += 6; - stb_raw(b ++, 0x02); /* u8 bt_sysclk (38.4) */ - w = (void *) b; - - stw_raw(w ++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */ - stw_raw(w ++, 8); /* u16 len */ - stw_raw(w ++, 0x25); /* u8 chip_type */ - stw_raw(w ++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */ - stw_raw(w ++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */ - stw_raw(w ++, -1); /* s16 spi_cs_gpio */ - - stw_raw(w ++, OMAP_TAG_MMC); /* u16 tag */ - stw_raw(w ++, 16); /* u16 len */ - if (model == 810) { - stw_raw(w ++, 0x23f); /* unsigned flags */ - stw_raw(w ++, -1); /* s16 power_pin */ - stw_raw(w ++, -1); /* s16 switch_pin */ - stw_raw(w ++, -1); /* s16 wp_pin */ - stw_raw(w ++, 0x240); /* unsigned flags */ - stw_raw(w ++, 0xc000); /* s16 power_pin */ - stw_raw(w ++, 0x0248); /* s16 switch_pin */ - stw_raw(w ++, 0xc000); /* s16 wp_pin */ - } else { - stw_raw(w ++, 0xf); /* unsigned flags */ - stw_raw(w ++, -1); /* s16 power_pin */ - stw_raw(w ++, -1); /* s16 switch_pin */ - stw_raw(w ++, -1); /* s16 wp_pin */ - stw_raw(w ++, 0); /* unsigned flags */ - stw_raw(w ++, 0); /* s16 power_pin */ - stw_raw(w ++, 0); /* s16 switch_pin */ - stw_raw(w ++, 0); /* s16 wp_pin */ - } - - stw_raw(w ++, OMAP_TAG_TEA5761); /* u16 tag */ - stw_raw(w ++, 4); /* u16 len */ - stw_raw(w ++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */ - w ++; - - partition = (model == 810) ? n810_part_info : n800_part_info; - for (; partition->name; partition ++) { - stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ - stw_raw(w ++, 28); /* u16 len */ - strcpy((void *) w, partition->name); /* char name[16] */ - l = (void *) (w + 8); - stl_raw(l ++, partition->size); /* unsigned int size */ - stl_raw(l ++, partition->offset); /* unsigned int offset */ - stl_raw(l ++, partition->mask); /* unsigned int mask_flags */ - w = (void *) l; - } - - stw_raw(w ++, OMAP_TAG_BOOT_REASON); /* u16 tag */ - stw_raw(w ++, 12); /* u16 len */ -#if 0 - strcpy((void *) w, "por"); /* char reason_str[12] */ - strcpy((void *) w, "charger"); /* char reason_str[12] */ - strcpy((void *) w, "32wd_to"); /* char reason_str[12] */ - strcpy((void *) w, "sw_rst"); /* char reason_str[12] */ - strcpy((void *) w, "mbus"); /* char reason_str[12] */ - strcpy((void *) w, "unknown"); /* char reason_str[12] */ - strcpy((void *) w, "swdg_to"); /* char reason_str[12] */ - strcpy((void *) w, "sec_vio"); /* char reason_str[12] */ - strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ - strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */ -#else - strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ -#endif - w += 6; - - tag = (model == 810) ? "RX-44" : "RX-34"; - stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ - stw_raw(w ++, 24); /* u16 len */ - strcpy((void *) w, "product"); /* char component[12] */ - w += 6; - strcpy((void *) w, tag); /* char version[12] */ - w += 6; - - stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ - stw_raw(w ++, 24); /* u16 len */ - strcpy((void *) w, "hw-build"); /* char component[12] */ - w += 6; - strcpy((void *) w, "QEMU "); - pstrcat((void *) w, 12, qemu_get_version()); /* char version[12] */ - w += 6; - - tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu"; - stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ - stw_raw(w ++, 24); /* u16 len */ - strcpy((void *) w, "nolo"); /* char component[12] */ - w += 6; - strcpy((void *) w, tag); /* char version[12] */ - w += 6; - - return (void *) w - p; -} - -static int n800_atag_setup(const struct arm_boot_info *info, void *p) -{ - return n8x0_atag_setup(p, 800); -} - -static int n810_atag_setup(const struct arm_boot_info *info, void *p) -{ - return n8x0_atag_setup(p, 810); -} - -static void n8x0_init(QEMUMachineInitArgs *args, - struct arm_boot_info *binfo, int model) -{ - MemoryRegion *sysmem = get_system_memory(); - struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); - int sdram_size = binfo->ram_size; - DisplayState *ds; - - s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model); - - /* Setup peripherals - * - * Believed external peripherals layout in the N810: - * (spi bus 1) - * tsc2005 - * lcd_mipid - * (spi bus 2) - * Conexant cx3110x (WLAN) - * optional: pc2400m (WiMAX) - * (i2c bus 0) - * TLV320AIC33 (audio codec) - * TCM825x (camera by Toshiba) - * lp5521 (clever LEDs) - * tsl2563 (light sensor, hwmon, model 7, rev. 0) - * lm8323 (keypad, manf 00, rev 04) - * (i2c bus 1) - * tmp105 (temperature sensor, hwmon) - * menelaus (pm) - * (somewhere on i2c - maybe N800-only) - * tea5761 (FM tuner) - * (serial 0) - * GPS - * (some serial port) - * csr41814 (Bluetooth) - */ - n8x0_gpio_setup(s); - n8x0_nand_setup(s); - n8x0_i2c_setup(s); - if (model == 800) - n800_tsc_kbd_setup(s); - else if (model == 810) { - n810_tsc_setup(s); - n810_kbd_setup(s); - } - n8x0_spi_setup(s); - n8x0_dss_setup(s); - n8x0_cbus_setup(s); - n8x0_uart_setup(s); - if (usb_enabled(false)) { - n8x0_usb_setup(s); - } - - if (args->kernel_filename) { - /* Or at the linux loader. */ - binfo->kernel_filename = args->kernel_filename; - binfo->kernel_cmdline = args->kernel_cmdline; - binfo->initrd_filename = args->initrd_filename; - arm_load_kernel(s->mpu->cpu, binfo); - - qemu_register_reset(n8x0_boot_init, s); - } - - if (option_rom[0].name && - (args->boot_device[0] == 'n' || !args->kernel_filename)) { - int rom_size; - uint8_t nolo_tags[0x10000]; - /* No, wait, better start at the ROM. */ - s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; - - /* This is intended for loading the `secondary.bin' program from - * Nokia images (the NOLO bootloader). The entry point seems - * to be at OMAP2_Q2_BASE + 0x400000. - * - * The `2nd.bin' files contain some kind of earlier boot code and - * for them the entry point needs to be set to OMAP2_SRAM_BASE. - * - * The code above is for loading the `zImage' file from Nokia - * images. */ - rom_size = load_image_targphys(option_rom[0].name, - OMAP2_Q2_BASE + 0x400000, - sdram_size - 0x400000); - printf("%i bytes of image loaded\n", rom_size); - - n800_setup_nolo_tags(nolo_tags); - cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000); - } - /* FIXME: We shouldn't really be doing this here. The LCD controller - will set the size once configured, so this just sets an initial - size until the guest activates the display. */ - ds = get_displaystate(); - ds->surface = qemu_resize_displaysurface(ds, 800, 480); - dpy_gfx_resize(ds); -} - -static struct arm_boot_info n800_binfo = { - .loader_start = OMAP2_Q2_BASE, - /* Actually two chips of 0x4000000 bytes each */ - .ram_size = 0x08000000, - .board_id = 0x4f7, - .atag_board = n800_atag_setup, -}; - -static struct arm_boot_info n810_binfo = { - .loader_start = OMAP2_Q2_BASE, - /* Actually two chips of 0x4000000 bytes each */ - .ram_size = 0x08000000, - /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not - * used by some older versions of the bootloader and 5555 is used - * instead (including versions that shipped with many devices). */ - .board_id = 0x60c, - .atag_board = n810_atag_setup, -}; - -static void n800_init(QEMUMachineInitArgs *args) -{ - return n8x0_init(args, &n800_binfo, 800); -} - -static void n810_init(QEMUMachineInitArgs *args) -{ - return n8x0_init(args, &n810_binfo, 810); -} - -static QEMUMachine n800_machine = { - .name = "n800", - .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)", - .init = n800_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine n810_machine = { - .name = "n810", - .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)", - .init = n810_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void nseries_machine_init(void) -{ - qemu_register_machine(&n800_machine); - qemu_register_machine(&n810_machine); -} - -machine_init(nseries_machine_init); diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c deleted file mode 100644 index 85982334bd..0000000000 --- a/hw/omap_sx1.c +++ /dev/null @@ -1,238 +0,0 @@ -/* omap_sx1.c Support for the Siemens SX1 smartphone emulation. - * - * Copyright (C) 2008 - * Jean-Christophe PLAGNIOL-VILLARD - * Copyright (C) 2007 Vladimir Ananiev - * - * based on PalmOne's (TM) PDAs support (palm.c) - */ - -/* - * PalmOne's (TM) PDAs. - * - * Copyright (C) 2006-2007 Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "hw/hw.h" -#include "ui/console.h" -#include "hw/omap.h" -#include "hw/boards.h" -#include "hw/arm-misc.h" -#include "hw/flash.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -/*****************************************************************************/ -/* Siemens SX1 Cellphone V1 */ -/* - ARM OMAP310 processor - * - SRAM 192 kB - * - SDRAM 32 MB at 0x10000000 - * - Boot flash 16 MB at 0x00000000 - * - Application flash 8 MB at 0x04000000 - * - 3 serial ports - * - 1 SecureDigital - * - 1 LCD display - * - 1 RTC - */ - -/*****************************************************************************/ -/* Siemens SX1 Cellphone V2 */ -/* - ARM OMAP310 processor - * - SRAM 192 kB - * - SDRAM 32 MB at 0x10000000 - * - Boot flash 32 MB at 0x00000000 - * - 3 serial ports - * - 1 SecureDigital - * - 1 LCD display - * - 1 RTC - */ - -static uint64_t static_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint32_t *val = (uint32_t *) opaque; - uint32_t mask = (4 / size) - 1; - - return *val >> ((offset & mask) << 3); -} - -static void static_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ -#ifdef SPY - printf("%s: value %" PRIx64 " %u bytes written at 0x%x\n", - __func__, value, size, (int)offset); -#endif -} - -static const MemoryRegionOps static_ops = { - .read = static_read, - .write = static_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -#define sdram_size 0x02000000 -#define sector_size (128 * 1024) -#define flash0_size (16 * 1024 * 1024) -#define flash1_size ( 8 * 1024 * 1024) -#define flash2_size (32 * 1024 * 1024) -#define total_ram_v1 (sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE) -#define total_ram_v2 (sdram_size + flash2_size + OMAP15XX_SRAM_SIZE) - -static struct arm_boot_info sx1_binfo = { - .loader_start = OMAP_EMIFF_BASE, - .ram_size = sdram_size, - .board_id = 0x265, -}; - -static void sx1_init(QEMUMachineInitArgs *args, const int version) -{ - struct omap_mpu_state_s *mpu; - MemoryRegion *address_space = get_system_memory(); - MemoryRegion *flash = g_new(MemoryRegion, 1); - MemoryRegion *flash_1 = g_new(MemoryRegion, 1); - MemoryRegion *cs = g_new(MemoryRegion, 4); - static uint32_t cs0val = 0x00213090; - static uint32_t cs1val = 0x00215070; - static uint32_t cs2val = 0x00001139; - static uint32_t cs3val = 0x00001139; - DriveInfo *dinfo; - int fl_idx; - uint32_t flash_size = flash0_size; - int be; - - if (version == 2) { - flash_size = flash2_size; - } - - mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model); - - /* External Flash (EMIFS) */ - memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size); - vmstate_register_ram_global(flash); - memory_region_set_readonly(flash, true); - memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash); - - memory_region_init_io(&cs[0], &static_ops, &cs0val, - "sx1.cs0", OMAP_CS0_SIZE - flash_size); - memory_region_add_subregion(address_space, - OMAP_CS0_BASE + flash_size, &cs[0]); - - - memory_region_init_io(&cs[2], &static_ops, &cs2val, - "sx1.cs2", OMAP_CS2_SIZE); - memory_region_add_subregion(address_space, - OMAP_CS2_BASE, &cs[2]); - - memory_region_init_io(&cs[3], &static_ops, &cs3val, - "sx1.cs3", OMAP_CS3_SIZE); - memory_region_add_subregion(address_space, - OMAP_CS2_BASE, &cs[3]); - - fl_idx = 0; -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - - if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { - if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL, - "omap_sx1.flash0-1", flash_size, - dinfo->bdrv, sector_size, - flash_size / sector_size, - 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory %d.\n", - fl_idx); - } - fl_idx++; - } - - if ((version == 1) && - (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { - memory_region_init_ram(flash_1, "omap_sx1.flash1-0", flash1_size); - vmstate_register_ram_global(flash_1); - memory_region_set_readonly(flash_1, true); - memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1); - - memory_region_init_io(&cs[1], &static_ops, &cs1val, - "sx1.cs1", OMAP_CS1_SIZE - flash1_size); - memory_region_add_subregion(address_space, - OMAP_CS1_BASE + flash1_size, &cs[1]); - - if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL, - "omap_sx1.flash1-1", flash1_size, - dinfo->bdrv, sector_size, - flash1_size / sector_size, - 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory %d.\n", - fl_idx); - } - fl_idx++; - } else { - memory_region_init_io(&cs[1], &static_ops, &cs1val, - "sx1.cs1", OMAP_CS1_SIZE); - memory_region_add_subregion(address_space, - OMAP_CS1_BASE, &cs[1]); - } - - if (!args->kernel_filename && !fl_idx) { - fprintf(stderr, "Kernel or Flash image must be specified\n"); - exit(1); - } - - /* Load the kernel. */ - if (args->kernel_filename) { - sx1_binfo.kernel_filename = args->kernel_filename; - sx1_binfo.kernel_cmdline = args->kernel_cmdline; - sx1_binfo.initrd_filename = args->initrd_filename; - arm_load_kernel(mpu->cpu, &sx1_binfo); - } - - /* TODO: fix next line */ - //~ qemu_console_resize(ds, 640, 480); -} - -static void sx1_init_v1(QEMUMachineInitArgs *args) -{ - sx1_init(args, 1); -} - -static void sx1_init_v2(QEMUMachineInitArgs *args) -{ - sx1_init(args, 2); -} - -static QEMUMachine sx1_machine_v2 = { - .name = "sx1", - .desc = "Siemens SX1 (OMAP310) V2", - .init = sx1_init_v2, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine sx1_machine_v1 = { - .name = "sx1-v1", - .desc = "Siemens SX1 (OMAP310) V1", - .init = sx1_init_v1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void sx1_machine_init(void) -{ - qemu_register_machine(&sx1_machine_v2); - qemu_register_machine(&sx1_machine_v1); -} - -machine_init(sx1_machine_init); diff --git a/hw/openrisc/Makefile.objs b/hw/openrisc/Makefile.objs index 38ff8f5d6d..61246b149b 100644 --- a/hw/openrisc/Makefile.objs +++ b/hw/openrisc/Makefile.objs @@ -1,3 +1,2 @@ -obj-y = openrisc_pic.o openrisc_sim.o openrisc_timer.o - -obj-y := $(addprefix ../,$(obj-y)) +obj-y = pic_cpu.o cputimer.o +obj-y += openrisc_sim.o diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c new file mode 100644 index 0000000000..f6c877f425 --- /dev/null +++ b/hw/openrisc/cputimer.c @@ -0,0 +1,101 @@ +/* + * QEMU OpenRISC timer support + * + * Copyright (c) 2011-2012 Jia Liu + * Zhizhou Zhang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "cpu.h" +#include "hw/hw.h" +#include "qemu/timer.h" + +#define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */ + +/* The time when TTCR changes */ +static uint64_t last_clk; +static int is_counting; + +void cpu_openrisc_count_update(OpenRISCCPU *cpu) +{ + uint64_t now, next; + uint32_t wait; + + now = qemu_get_clock_ns(vm_clock); + if (!is_counting) { + qemu_del_timer(cpu->env.timer); + last_clk = now; + return; + } + + cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ, + get_ticks_per_sec()); + last_clk = now; + + if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) { + wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1; + wait += cpu->env.ttmr & TTMR_TP; + } else { + wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP); + } + + next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); + qemu_mod_timer(cpu->env.timer, next); +} + +void cpu_openrisc_count_start(OpenRISCCPU *cpu) +{ + is_counting = 1; + cpu_openrisc_count_update(cpu); +} + +void cpu_openrisc_count_stop(OpenRISCCPU *cpu) +{ + is_counting = 0; + cpu_openrisc_count_update(cpu); +} + +static void openrisc_timer_cb(void *opaque) +{ + OpenRISCCPU *cpu = opaque; + + if ((cpu->env.ttmr & TTMR_IE) && + qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) { + cpu->env.ttmr |= TTMR_IP; + cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER; + } + + switch (cpu->env.ttmr & TTMR_M) { + case TIMER_NONE: + break; + case TIMER_INTR: + cpu->env.ttcr = 0; + cpu_openrisc_count_start(cpu); + break; + case TIMER_SHOT: + cpu_openrisc_count_stop(cpu); + break; + case TIMER_CONT: + cpu_openrisc_count_start(cpu); + break; + } +} + +void cpu_openrisc_clock_init(OpenRISCCPU *cpu) +{ + cpu->env.timer = qemu_new_timer_ns(vm_clock, &openrisc_timer_cb, cpu); + cpu->env.ttmr = 0x00000000; + cpu->env.ttcr = 0x00000000; +} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c new file mode 100644 index 0000000000..db2aac8cf8 --- /dev/null +++ b/hw/openrisc/openrisc_sim.c @@ -0,0 +1,150 @@ +/* + * OpenRISC simulator for use as an IIS. + * + * Copyright (c) 2011-2012 Jia Liu + * Feng Gao + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "hw/hw.h" +#include "hw/boards.h" +#include "elf.h" +#include "hw/serial.h" +#include "net/net.h" +#include "hw/loader.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "sysemu/qtest.h" + +#define KERNEL_LOAD_ADDR 0x100 + +static void main_cpu_reset(void *opaque) +{ + OpenRISCCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static void openrisc_sim_net_init(MemoryRegion *address_space, + hwaddr base, + hwaddr descriptors, + qemu_irq irq, NICInfo *nd) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "open_eth"); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, irq); + memory_region_add_subregion(address_space, base, + sysbus_mmio_get_region(s, 0)); + memory_region_add_subregion(address_space, descriptors, + sysbus_mmio_get_region(s, 1)); +} + +static void cpu_openrisc_load_kernel(ram_addr_t ram_size, + const char *kernel_filename, + OpenRISCCPU *cpu) +{ + long kernel_size; + uint64_t elf_entry; + hwaddr entry; + + if (kernel_filename && !qtest_enabled()) { + kernel_size = load_elf(kernel_filename, NULL, NULL, + &elf_entry, NULL, NULL, 1, ELF_MACHINE, 1); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(kernel_filename, + &entry, NULL, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); + entry = KERNEL_LOAD_ADDR; + } + + if (kernel_size < 0) { + qemu_log("QEMU: couldn't load the kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + cpu->env.pc = entry; +} + +static void openrisc_sim_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + OpenRISCCPU *cpu = NULL; + MemoryRegion *ram; + int n; + + if (!cpu_model) { + cpu_model = "or1200"; + } + + for (n = 0; n < smp_cpus; n++) { + cpu = cpu_openrisc_init(cpu_model); + if (cpu == NULL) { + qemu_log("Unable to find CPU definition!\n"); + exit(1); + } + qemu_register_reset(main_cpu_reset, cpu); + main_cpu_reset(cpu); + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, "openrisc.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(get_system_memory(), 0, ram); + + cpu_openrisc_pic_init(cpu); + cpu_openrisc_clock_init(cpu); + + serial_mm_init(get_system_memory(), 0x90000000, 0, cpu->env.irq[2], + 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); + + if (nd_table[0].used) { + openrisc_sim_net_init(get_system_memory(), 0x92000000, + 0x92000400, cpu->env.irq[4], nd_table); + } + + cpu_openrisc_load_kernel(ram_size, kernel_filename, cpu); +} + +static QEMUMachine openrisc_sim_machine = { + .name = "or32-sim", + .desc = "or32 simulation", + .init = openrisc_sim_init, + .max_cpus = 1, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void openrisc_sim_machine_init(void) +{ + qemu_register_machine(&openrisc_sim_machine); +} + +machine_init(openrisc_sim_machine_init); diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c new file mode 100644 index 0000000000..931511ec0f --- /dev/null +++ b/hw/openrisc/pic_cpu.c @@ -0,0 +1,60 @@ +/* + * OpenRISC Programmable Interrupt Controller support. + * + * Copyright (c) 2011-2012 Jia Liu + * Feng Gao + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "hw/hw.h" +#include "cpu.h" + +/* OpenRISC pic handler */ +static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) +{ + OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; + int i; + uint32_t irq_bit = 1 << irq; + + if (irq > 31 || irq < 0) { + return; + } + + if (level) { + cpu->env.picsr |= irq_bit; + } else { + cpu->env.picsr &= ~irq_bit; + } + + for (i = 0; i < 32; i++) { + if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) { + cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(&cpu->env, CPU_INTERRUPT_HARD); + cpu->env.picsr &= ~(1 << i); + } + } +} + +void cpu_openrisc_pic_init(OpenRISCCPU *cpu) +{ + int i; + qemu_irq *qi; + qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS); + + for (i = 0; i < NR_IRQS; i++) { + cpu->env.irq[i] = qi[i]; + } +} diff --git a/hw/openrisc_pic.c b/hw/openrisc_pic.c deleted file mode 100644 index 931511ec0f..0000000000 --- a/hw/openrisc_pic.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * OpenRISC Programmable Interrupt Controller support. - * - * Copyright (c) 2011-2012 Jia Liu - * Feng Gao - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/hw.h" -#include "cpu.h" - -/* OpenRISC pic handler */ -static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) -{ - OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; - int i; - uint32_t irq_bit = 1 << irq; - - if (irq > 31 || irq < 0) { - return; - } - - if (level) { - cpu->env.picsr |= irq_bit; - } else { - cpu->env.picsr &= ~irq_bit; - } - - for (i = 0; i < 32; i++) { - if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) { - cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(&cpu->env, CPU_INTERRUPT_HARD); - cpu->env.picsr &= ~(1 << i); - } - } -} - -void cpu_openrisc_pic_init(OpenRISCCPU *cpu) -{ - int i; - qemu_irq *qi; - qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS); - - for (i = 0; i < NR_IRQS; i++) { - cpu->env.irq[i] = qi[i]; - } -} diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c deleted file mode 100644 index db2aac8cf8..0000000000 --- a/hw/openrisc_sim.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * OpenRISC simulator for use as an IIS. - * - * Copyright (c) 2011-2012 Jia Liu - * Feng Gao - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/hw.h" -#include "hw/boards.h" -#include "elf.h" -#include "hw/serial.h" -#include "net/net.h" -#include "hw/loader.h" -#include "exec/address-spaces.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "sysemu/qtest.h" - -#define KERNEL_LOAD_ADDR 0x100 - -static void main_cpu_reset(void *opaque) -{ - OpenRISCCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -static void openrisc_sim_net_init(MemoryRegion *address_space, - hwaddr base, - hwaddr descriptors, - qemu_irq irq, NICInfo *nd) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "open_eth"); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, irq); - memory_region_add_subregion(address_space, base, - sysbus_mmio_get_region(s, 0)); - memory_region_add_subregion(address_space, descriptors, - sysbus_mmio_get_region(s, 1)); -} - -static void cpu_openrisc_load_kernel(ram_addr_t ram_size, - const char *kernel_filename, - OpenRISCCPU *cpu) -{ - long kernel_size; - uint64_t elf_entry; - hwaddr entry; - - if (kernel_filename && !qtest_enabled()) { - kernel_size = load_elf(kernel_filename, NULL, NULL, - &elf_entry, NULL, NULL, 1, ELF_MACHINE, 1); - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(kernel_filename, - &entry, NULL, NULL); - } - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - ram_size - KERNEL_LOAD_ADDR); - entry = KERNEL_LOAD_ADDR; - } - - if (kernel_size < 0) { - qemu_log("QEMU: couldn't load the kernel '%s'\n", - kernel_filename); - exit(1); - } - } - - cpu->env.pc = entry; -} - -static void openrisc_sim_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - OpenRISCCPU *cpu = NULL; - MemoryRegion *ram; - int n; - - if (!cpu_model) { - cpu_model = "or1200"; - } - - for (n = 0; n < smp_cpus; n++) { - cpu = cpu_openrisc_init(cpu_model); - if (cpu == NULL) { - qemu_log("Unable to find CPU definition!\n"); - exit(1); - } - qemu_register_reset(main_cpu_reset, cpu); - main_cpu_reset(cpu); - } - - ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, "openrisc.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(get_system_memory(), 0, ram); - - cpu_openrisc_pic_init(cpu); - cpu_openrisc_clock_init(cpu); - - serial_mm_init(get_system_memory(), 0x90000000, 0, cpu->env.irq[2], - 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); - - if (nd_table[0].used) { - openrisc_sim_net_init(get_system_memory(), 0x92000000, - 0x92000400, cpu->env.irq[4], nd_table); - } - - cpu_openrisc_load_kernel(ram_size, kernel_filename, cpu); -} - -static QEMUMachine openrisc_sim_machine = { - .name = "or32-sim", - .desc = "or32 simulation", - .init = openrisc_sim_init, - .max_cpus = 1, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void openrisc_sim_machine_init(void) -{ - qemu_register_machine(&openrisc_sim_machine); -} - -machine_init(openrisc_sim_machine_init); diff --git a/hw/openrisc_timer.c b/hw/openrisc_timer.c deleted file mode 100644 index f6c877f425..0000000000 --- a/hw/openrisc_timer.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * QEMU OpenRISC timer support - * - * Copyright (c) 2011-2012 Jia Liu - * Zhizhou Zhang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "cpu.h" -#include "hw/hw.h" -#include "qemu/timer.h" - -#define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */ - -/* The time when TTCR changes */ -static uint64_t last_clk; -static int is_counting; - -void cpu_openrisc_count_update(OpenRISCCPU *cpu) -{ - uint64_t now, next; - uint32_t wait; - - now = qemu_get_clock_ns(vm_clock); - if (!is_counting) { - qemu_del_timer(cpu->env.timer); - last_clk = now; - return; - } - - cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ, - get_ticks_per_sec()); - last_clk = now; - - if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) { - wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1; - wait += cpu->env.ttmr & TTMR_TP; - } else { - wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP); - } - - next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); - qemu_mod_timer(cpu->env.timer, next); -} - -void cpu_openrisc_count_start(OpenRISCCPU *cpu) -{ - is_counting = 1; - cpu_openrisc_count_update(cpu); -} - -void cpu_openrisc_count_stop(OpenRISCCPU *cpu) -{ - is_counting = 0; - cpu_openrisc_count_update(cpu); -} - -static void openrisc_timer_cb(void *opaque) -{ - OpenRISCCPU *cpu = opaque; - - if ((cpu->env.ttmr & TTMR_IE) && - qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) { - cpu->env.ttmr |= TTMR_IP; - cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER; - } - - switch (cpu->env.ttmr & TTMR_M) { - case TIMER_NONE: - break; - case TIMER_INTR: - cpu->env.ttcr = 0; - cpu_openrisc_count_start(cpu); - break; - case TIMER_SHOT: - cpu_openrisc_count_stop(cpu); - break; - case TIMER_CONT: - cpu_openrisc_count_start(cpu); - break; - } -} - -void cpu_openrisc_clock_init(OpenRISCCPU *cpu) -{ - cpu->env.timer = qemu_new_timer_ns(vm_clock, &openrisc_timer_cb, cpu); - cpu->env.ttmr = 0x00000000; - cpu->env.ttcr = 0x00000000; -} diff --git a/hw/palm.c b/hw/palm.c deleted file mode 100644 index 91bc74af24..0000000000 --- a/hw/palm.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * PalmOne's (TM) PDAs. - * - * Copyright (C) 2006-2007 Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "hw/hw.h" -#include "audio/audio.h" -#include "sysemu/sysemu.h" -#include "ui/console.h" -#include "hw/omap.h" -#include "hw/boards.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "hw/loader.h" -#include "exec/address-spaces.h" - -static uint32_t static_readb(void *opaque, hwaddr offset) -{ - uint32_t *val = (uint32_t *) opaque; - return *val >> ((offset & 3) << 3); -} - -static uint32_t static_readh(void *opaque, hwaddr offset) -{ - uint32_t *val = (uint32_t *) opaque; - return *val >> ((offset & 1) << 3); -} - -static uint32_t static_readw(void *opaque, hwaddr offset) -{ - uint32_t *val = (uint32_t *) opaque; - return *val >> ((offset & 0) << 3); -} - -static void static_write(void *opaque, hwaddr offset, - uint32_t value) -{ -#ifdef SPY - printf("%s: value %08lx written at " PA_FMT "\n", - __FUNCTION__, value, offset); -#endif -} - -static const MemoryRegionOps static_ops = { - .old_mmio = { - .read = { static_readb, static_readh, static_readw, }, - .write = { static_write, static_write, static_write, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* Palm Tunsgten|E support */ - -/* Shared GPIOs */ -#define PALMTE_USBDETECT_GPIO 0 -#define PALMTE_USB_OR_DC_GPIO 1 -#define PALMTE_TSC_GPIO 4 -#define PALMTE_PINTDAV_GPIO 6 -#define PALMTE_MMC_WP_GPIO 8 -#define PALMTE_MMC_POWER_GPIO 9 -#define PALMTE_HDQ_GPIO 11 -#define PALMTE_HEADPHONES_GPIO 14 -#define PALMTE_SPEAKER_GPIO 15 -/* MPU private GPIOs */ -#define PALMTE_DC_GPIO 2 -#define PALMTE_MMC_SWITCH_GPIO 4 -#define PALMTE_MMC1_GPIO 6 -#define PALMTE_MMC2_GPIO 7 -#define PALMTE_MMC3_GPIO 11 - -static MouseTransformInfo palmte_pointercal = { - .x = 320, - .y = 320, - .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 }, -}; - -static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) -{ - uWireSlave *tsc; - - tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO)); - - omap_uwire_attach(cpu->microwire, tsc, 0); - omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc)); - - tsc210x_set_transform(tsc, &palmte_pointercal); -} - -static struct { - int row; - int column; -} palmte_keymap[0x80] = { - [0 ... 0x7f] = { -1, -1 }, - [0x3b] = { 0, 0 }, /* F1 -> Calendar */ - [0x3c] = { 1, 0 }, /* F2 -> Contacts */ - [0x3d] = { 2, 0 }, /* F3 -> Tasks List */ - [0x3e] = { 3, 0 }, /* F4 -> Note Pad */ - [0x01] = { 4, 0 }, /* Esc -> Power */ - [0x4b] = { 0, 1 }, /* Left */ - [0x50] = { 1, 1 }, /* Down */ - [0x48] = { 2, 1 }, /* Up */ - [0x4d] = { 3, 1 }, /* Right */ - [0x4c] = { 4, 1 }, /* Centre */ - [0x39] = { 4, 1 }, /* Spc -> Centre */ -}; - -static void palmte_button_event(void *opaque, int keycode) -{ - struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; - - if (palmte_keymap[keycode & 0x7f].row != -1) - omap_mpuio_key(cpu->mpuio, - palmte_keymap[keycode & 0x7f].row, - palmte_keymap[keycode & 0x7f].column, - !(keycode & 0x80)); -} - -static void palmte_onoff_gpios(void *opaque, int line, int level) -{ - switch (line) { - case 0: - printf("%s: current to MMC/SD card %sabled.\n", - __FUNCTION__, level ? "dis" : "en"); - break; - case 1: - printf("%s: internal speaker amplifier %s.\n", - __FUNCTION__, level ? "down" : "on"); - break; - - /* These LCD & Audio output signals have not been identified yet. */ - case 2: - case 3: - case 4: - printf("%s: LCD GPIO%i %s.\n", - __FUNCTION__, line - 1, level ? "high" : "low"); - break; - case 5: - case 6: - printf("%s: Audio GPIO%i %s.\n", - __FUNCTION__, line - 4, level ? "high" : "low"); - break; - } -} - -static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) -{ - qemu_irq *misc_gpio; - - omap_mmc_handlers(cpu->mmc, - qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO), - qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio) - [PALMTE_MMC_SWITCH_GPIO])); - - misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7); - qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]); - qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]); - qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]); - qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]); - qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]); - omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]); - omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]); - - /* Reset some inputs to initial state. */ - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO)); - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO)); - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4)); - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO)); - qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]); - qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]); - qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]); - qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]); -} - -static struct arm_boot_info palmte_binfo = { - .loader_start = OMAP_EMIFF_BASE, - .ram_size = 0x02000000, - .board_id = 0x331, -}; - -static void palmte_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - MemoryRegion *address_space_mem = get_system_memory(); - struct omap_mpu_state_s *mpu; - int flash_size = 0x00800000; - int sdram_size = palmte_binfo.ram_size; - static uint32_t cs0val = 0xffffffff; - static uint32_t cs1val = 0x0000e1a0; - static uint32_t cs2val = 0x0000e1a0; - static uint32_t cs3val = 0xe1a0e1a0; - int rom_size, rom_loaded = 0; - DisplayState *ds = get_displaystate(); - MemoryRegion *flash = g_new(MemoryRegion, 1); - MemoryRegion *cs = g_new(MemoryRegion, 4); - - mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); - - /* External Flash (EMIFS) */ - memory_region_init_ram(flash, "palmte.flash", flash_size); - vmstate_register_ram_global(flash); - memory_region_set_readonly(flash, true); - memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash); - - memory_region_init_io(&cs[0], &static_ops, &cs0val, "palmte-cs0", - OMAP_CS0_SIZE - flash_size); - memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size, - &cs[0]); - memory_region_init_io(&cs[1], &static_ops, &cs1val, "palmte-cs1", - OMAP_CS1_SIZE); - memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]); - memory_region_init_io(&cs[2], &static_ops, &cs2val, "palmte-cs2", - OMAP_CS2_SIZE); - memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]); - memory_region_init_io(&cs[3], &static_ops, &cs3val, "palmte-cs3", - OMAP_CS3_SIZE); - memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]); - - palmte_microwire_setup(mpu); - - qemu_add_kbd_event_handler(palmte_button_event, mpu); - - palmte_gpio_setup(mpu); - - /* Setup initial (reset) machine state */ - if (nb_option_roms) { - rom_size = get_image_size(option_rom[0].name); - if (rom_size > flash_size) { - fprintf(stderr, "%s: ROM image too big (%x > %x)\n", - __FUNCTION__, rom_size, flash_size); - rom_size = 0; - } - if (rom_size > 0) { - rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE, - flash_size); - rom_loaded = 1; - } - if (rom_size < 0) { - fprintf(stderr, "%s: error loading '%s'\n", - __FUNCTION__, option_rom[0].name); - } - } - - if (!rom_loaded && !kernel_filename) { - fprintf(stderr, "Kernel or ROM image must be specified\n"); - exit(1); - } - - /* Load the kernel. */ - if (kernel_filename) { - palmte_binfo.kernel_filename = kernel_filename; - palmte_binfo.kernel_cmdline = kernel_cmdline; - palmte_binfo.initrd_filename = initrd_filename; - arm_load_kernel(mpu->cpu, &palmte_binfo); - } - - /* FIXME: We shouldn't really be doing this here. The LCD controller - will set the size once configured, so this just sets an initial - size until the guest activates the display. */ - ds->surface = qemu_resize_displaysurface(ds, 320, 320); - dpy_gfx_resize(ds); -} - -static QEMUMachine palmte_machine = { - .name = "cheetah", - .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)", - .init = palmte_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void palmte_machine_init(void) -{ - qemu_register_machine(&palmte_machine); -} - -machine_init(palmte_machine_init); diff --git a/hw/pc.c b/hw/pc.c deleted file mode 100644 index 309bb83cab..0000000000 --- a/hw/pc.c +++ /dev/null @@ -1,1161 +0,0 @@ -/* - * QEMU PC System Emulator - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/pc.h" -#include "hw/serial.h" -#include "hw/apic.h" -#include "hw/fdc.h" -#include "hw/ide.h" -#include "hw/pci/pci.h" -#include "monitor/monitor.h" -#include "hw/fw_cfg.h" -#include "hw/hpet_emul.h" -#include "hw/smbios.h" -#include "hw/loader.h" -#include "elf.h" -#include "hw/multiboot.h" -#include "hw/mc146818rtc.h" -#include "hw/i8254.h" -#include "hw/pcspk.h" -#include "hw/pci/msi.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "sysemu/kvm.h" -#include "kvm_i386.h" -#include "hw/xen.h" -#include "sysemu/blockdev.h" -#include "hw/block-common.h" -#include "ui/qemu-spice.h" -#include "exec/memory.h" -#include "exec/address-spaces.h" -#include "sysemu/arch_init.h" -#include "qemu/bitmap.h" - -/* debug PC/ISA interrupts */ -//#define DEBUG_IRQ - -#ifdef DEBUG_IRQ -#define DPRINTF(fmt, ...) \ - do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif - -/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ -#define ACPI_DATA_SIZE 0x10000 -#define BIOS_CFG_IOPORT 0x510 -#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) -#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) -#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) -#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) -#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4) - -#define E820_NR_ENTRIES 16 - -struct e820_entry { - uint64_t address; - uint64_t length; - uint32_t type; -} QEMU_PACKED __attribute((__aligned__(4))); - -struct e820_table { - uint32_t count; - struct e820_entry entry[E820_NR_ENTRIES]; -} QEMU_PACKED __attribute((__aligned__(4))); - -static struct e820_table e820_table; -struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; - -void gsi_handler(void *opaque, int n, int level) -{ - GSIState *s = opaque; - - DPRINTF("pc: %s GSI %d\n", level ? "raising" : "lowering", n); - if (n < ISA_NUM_IRQS) { - qemu_set_irq(s->i8259_irq[n], level); - } - qemu_set_irq(s->ioapic_irq[n], level); -} - -static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, - unsigned size) -{ -} - -static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size) -{ - return 0xffffffffffffffffULL; -} - -/* MSDOS compatibility mode FPU exception support */ -static qemu_irq ferr_irq; - -void pc_register_ferr_irq(qemu_irq irq) -{ - ferr_irq = irq; -} - -/* XXX: add IGNNE support */ -void cpu_set_ferr(CPUX86State *s) -{ - qemu_irq_raise(ferr_irq); -} - -static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, - unsigned size) -{ - qemu_irq_lower(ferr_irq); -} - -static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size) -{ - return 0xffffffffffffffffULL; -} - -/* TSC handling */ -uint64_t cpu_get_tsc(CPUX86State *env) -{ - return cpu_get_ticks(); -} - -/* SMM support */ - -static cpu_set_smm_t smm_set; -static void *smm_arg; - -void cpu_smm_register(cpu_set_smm_t callback, void *arg) -{ - assert(smm_set == NULL); - assert(smm_arg == NULL); - smm_set = callback; - smm_arg = arg; -} - -void cpu_smm_update(CPUX86State *env) -{ - if (smm_set && smm_arg && env == first_cpu) - smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg); -} - - -/* IRQ handling */ -int cpu_get_pic_interrupt(CPUX86State *env) -{ - int intno; - - intno = apic_get_interrupt(env->apic_state); - if (intno >= 0) { - return intno; - } - /* read the irq from the PIC */ - if (!apic_accept_pic_intr(env->apic_state)) { - return -1; - } - - intno = pic_read_irq(isa_pic); - return intno; -} - -static void pic_irq_request(void *opaque, int irq, int level) -{ - CPUX86State *env = first_cpu; - - DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq); - if (env->apic_state) { - while (env) { - if (apic_accept_pic_intr(env->apic_state)) { - apic_deliver_pic_intr(env->apic_state, level); - } - env = env->next_cpu; - } - } else { - if (level) - cpu_interrupt(env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -/* PC cmos mappings */ - -#define REG_EQUIPMENT_BYTE 0x14 - -static int cmos_get_fd_drive_type(FDriveType fd0) -{ - int val; - - switch (fd0) { - case FDRIVE_DRV_144: - /* 1.44 Mb 3"5 drive */ - val = 4; - break; - case FDRIVE_DRV_288: - /* 2.88 Mb 3"5 drive */ - val = 5; - break; - case FDRIVE_DRV_120: - /* 1.2 Mb 5"5 drive */ - val = 2; - break; - case FDRIVE_DRV_NONE: - default: - val = 0; - break; - } - return val; -} - -static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs, - int16_t cylinders, int8_t heads, int8_t sectors) -{ - rtc_set_memory(s, type_ofs, 47); - rtc_set_memory(s, info_ofs, cylinders); - rtc_set_memory(s, info_ofs + 1, cylinders >> 8); - rtc_set_memory(s, info_ofs + 2, heads); - rtc_set_memory(s, info_ofs + 3, 0xff); - rtc_set_memory(s, info_ofs + 4, 0xff); - rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); - rtc_set_memory(s, info_ofs + 6, cylinders); - rtc_set_memory(s, info_ofs + 7, cylinders >> 8); - rtc_set_memory(s, info_ofs + 8, sectors); -} - -/* convert boot_device letter to something recognizable by the bios */ -static int boot_device2nibble(char boot_device) -{ - switch(boot_device) { - case 'a': - case 'b': - return 0x01; /* floppy boot */ - case 'c': - return 0x02; /* hard drive boot */ - case 'd': - return 0x03; /* CD-ROM boot */ - case 'n': - return 0x04; /* Network boot */ - } - return 0; -} - -static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk) -{ -#define PC_MAX_BOOT_DEVICES 3 - int nbds, bds[3] = { 0, }; - int i; - - nbds = strlen(boot_device); - if (nbds > PC_MAX_BOOT_DEVICES) { - error_report("Too many boot devices for PC"); - return(1); - } - for (i = 0; i < nbds; i++) { - bds[i] = boot_device2nibble(boot_device[i]); - if (bds[i] == 0) { - error_report("Invalid boot device for PC: '%c'", - boot_device[i]); - return(1); - } - } - rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); - rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1)); - return(0); -} - -static int pc_boot_set(void *opaque, const char *boot_device) -{ - return set_boot_dev(opaque, boot_device, 0); -} - -typedef struct pc_cmos_init_late_arg { - ISADevice *rtc_state; - BusState *idebus[2]; -} pc_cmos_init_late_arg; - -static void pc_cmos_init_late(void *opaque) -{ - pc_cmos_init_late_arg *arg = opaque; - ISADevice *s = arg->rtc_state; - int16_t cylinders; - int8_t heads, sectors; - int val; - int i, trans; - - val = 0; - if (ide_get_geometry(arg->idebus[0], 0, - &cylinders, &heads, §ors) >= 0) { - cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors); - val |= 0xf0; - } - if (ide_get_geometry(arg->idebus[0], 1, - &cylinders, &heads, §ors) >= 0) { - cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors); - val |= 0x0f; - } - rtc_set_memory(s, 0x12, val); - - val = 0; - for (i = 0; i < 4; i++) { - /* NOTE: ide_get_geometry() returns the physical - geometry. It is always such that: 1 <= sects <= 63, 1 - <= heads <= 16, 1 <= cylinders <= 16383. The BIOS - geometry can be different if a translation is done. */ - if (ide_get_geometry(arg->idebus[i / 2], i % 2, - &cylinders, &heads, §ors) >= 0) { - trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1; - assert((trans & ~3) == 0); - val |= trans << (i * 2); - } - } - rtc_set_memory(s, 0x39, val); - - qemu_unregister_reset(pc_cmos_init_late, opaque); -} - -void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, - ISADevice *floppy, BusState *idebus0, BusState *idebus1, - ISADevice *s) -{ - int val, nb, i; - FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE }; - static pc_cmos_init_late_arg arg; - - /* various important CMOS locations needed by PC/Bochs bios */ - - /* memory size */ - /* base memory (first MiB) */ - val = MIN(ram_size / 1024, 640); - rtc_set_memory(s, 0x15, val); - rtc_set_memory(s, 0x16, val >> 8); - /* extended memory (next 64MiB) */ - if (ram_size > 1024 * 1024) { - val = (ram_size - 1024 * 1024) / 1024; - } else { - val = 0; - } - if (val > 65535) - val = 65535; - rtc_set_memory(s, 0x17, val); - rtc_set_memory(s, 0x18, val >> 8); - rtc_set_memory(s, 0x30, val); - rtc_set_memory(s, 0x31, val >> 8); - /* memory between 16MiB and 4GiB */ - if (ram_size > 16 * 1024 * 1024) { - val = (ram_size - 16 * 1024 * 1024) / 65536; - } else { - val = 0; - } - if (val > 65535) - val = 65535; - rtc_set_memory(s, 0x34, val); - rtc_set_memory(s, 0x35, val >> 8); - /* memory above 4GiB */ - val = above_4g_mem_size / 65536; - rtc_set_memory(s, 0x5b, val); - rtc_set_memory(s, 0x5c, val >> 8); - rtc_set_memory(s, 0x5d, val >> 16); - - /* set the number of CPU */ - rtc_set_memory(s, 0x5f, smp_cpus - 1); - - /* set boot devices, and disable floppy signature check if requested */ - if (set_boot_dev(s, boot_device, fd_bootchk)) { - exit(1); - } - - /* floppy type */ - if (floppy) { - for (i = 0; i < 2; i++) { - fd_type[i] = isa_fdc_get_drive_type(floppy, i); - } - } - val = (cmos_get_fd_drive_type(fd_type[0]) << 4) | - cmos_get_fd_drive_type(fd_type[1]); - rtc_set_memory(s, 0x10, val); - - val = 0; - nb = 0; - if (fd_type[0] < FDRIVE_DRV_NONE) { - nb++; - } - if (fd_type[1] < FDRIVE_DRV_NONE) { - nb++; - } - switch (nb) { - case 0: - break; - case 1: - val |= 0x01; /* 1 drive, ready for boot */ - break; - case 2: - val |= 0x41; /* 2 drives, ready for boot */ - break; - } - val |= 0x02; /* FPU is there */ - val |= 0x04; /* PS/2 mouse installed */ - rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); - - /* hard drives */ - arg.rtc_state = s; - arg.idebus[0] = idebus0; - arg.idebus[1] = idebus1; - qemu_register_reset(pc_cmos_init_late, &arg); -} - -/* port 92 stuff: could be split off */ -typedef struct Port92State { - ISADevice dev; - MemoryRegion io; - uint8_t outport; - qemu_irq *a20_out; -} Port92State; - -static void port92_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - Port92State *s = opaque; - - DPRINTF("port92: write 0x%02x\n", val); - s->outport = val; - qemu_set_irq(*s->a20_out, (val >> 1) & 1); - if (val & 1) { - qemu_system_reset_request(); - } -} - -static uint64_t port92_read(void *opaque, hwaddr addr, - unsigned size) -{ - Port92State *s = opaque; - uint32_t ret; - - ret = s->outport; - DPRINTF("port92: read 0x%02x\n", ret); - return ret; -} - -static void port92_init(ISADevice *dev, qemu_irq *a20_out) -{ - Port92State *s = DO_UPCAST(Port92State, dev, dev); - - s->a20_out = a20_out; -} - -static const VMStateDescription vmstate_port92_isa = { - .name = "port92", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_UINT8(outport, Port92State), - VMSTATE_END_OF_LIST() - } -}; - -static void port92_reset(DeviceState *d) -{ - Port92State *s = container_of(d, Port92State, dev.qdev); - - s->outport &= ~1; -} - -static const MemoryRegionOps port92_ops = { - .read = port92_read, - .write = port92_write, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static int port92_initfn(ISADevice *dev) -{ - Port92State *s = DO_UPCAST(Port92State, dev, dev); - - memory_region_init_io(&s->io, &port92_ops, s, "port92", 1); - isa_register_ioport(dev, &s->io, 0x92); - - s->outport = 0; - return 0; -} - -static void port92_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); - ic->init = port92_initfn; - dc->no_user = 1; - dc->reset = port92_reset; - dc->vmsd = &vmstate_port92_isa; -} - -static const TypeInfo port92_info = { - .name = "port92", - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(Port92State), - .class_init = port92_class_initfn, -}; - -static void port92_register_types(void) -{ - type_register_static(&port92_info); -} - -type_init(port92_register_types) - -static void handle_a20_line_change(void *opaque, int irq, int level) -{ - X86CPU *cpu = opaque; - - /* XXX: send to all CPUs ? */ - /* XXX: add logic to handle multiple A20 line sources */ - x86_cpu_set_a20(cpu, level); -} - -int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) -{ - int index = le32_to_cpu(e820_table.count); - struct e820_entry *entry; - - if (index >= E820_NR_ENTRIES) - return -EBUSY; - entry = &e820_table.entry[index++]; - - entry->address = cpu_to_le64(address); - entry->length = cpu_to_le64(length); - entry->type = cpu_to_le32(type); - - e820_table.count = cpu_to_le32(index); - return index; -} - -/* Calculates the limit to CPU APIC ID values - * - * This function returns the limit for the APIC ID value, so that all - * CPU APIC IDs are < pc_apic_id_limit(). - * - * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). - */ -static unsigned int pc_apic_id_limit(unsigned int max_cpus) -{ - return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; -} - -static void *bochs_bios_init(void) -{ - void *fw_cfg; - uint8_t *smbios_table; - size_t smbios_len; - uint64_t *numa_fw_cfg; - int i, j; - unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); - - fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); - /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: - * - * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug - * QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC - * ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the - * "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS - * may see". - * - * So, this means we must not use max_cpus, here, but the maximum possible - * APIC ID value, plus one. - * - * [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is - * the APIC ID, not the "CPU index" - */ - fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit); - fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); - fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, - acpi_tables, acpi_tables_len); - fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); - - smbios_table = smbios_get_table(&smbios_len); - if (smbios_table) - fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, - smbios_table, smbios_len); - fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, - &e820_table, sizeof(e820_table)); - - fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg)); - /* allocate memory for the NUMA channel: one (64bit) word for the number - * of nodes, one word for each VCPU->node and one word for each node to - * hold the amount of memory. - */ - numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes); - numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); - for (i = 0; i < max_cpus; i++) { - unsigned int apic_id = x86_cpu_apic_id_from_index(i); - assert(apic_id < apic_id_limit); - for (j = 0; j < nb_numa_nodes; j++) { - if (test_bit(i, node_cpumask[j])) { - numa_fw_cfg[apic_id + 1] = cpu_to_le64(j); - break; - } - } - } - for (i = 0; i < nb_numa_nodes; i++) { - numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]); - } - fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, - (1 + apic_id_limit + nb_numa_nodes) * - sizeof(*numa_fw_cfg)); - - return fw_cfg; -} - -static long get_file_size(FILE *f) -{ - long where, size; - - /* XXX: on Unix systems, using fstat() probably makes more sense */ - - where = ftell(f); - fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, where, SEEK_SET); - - return size; -} - -static void load_linux(void *fw_cfg, - const char *kernel_filename, - const char *initrd_filename, - const char *kernel_cmdline, - hwaddr max_ram_size) -{ - uint16_t protocol; - int setup_size, kernel_size, initrd_size = 0, cmdline_size; - uint32_t initrd_max; - uint8_t header[8192], *setup, *kernel, *initrd_data; - hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; - FILE *f; - char *vmode; - - /* Align to 16 bytes as a paranoia measure */ - cmdline_size = (strlen(kernel_cmdline)+16) & ~15; - - /* load the kernel header */ - f = fopen(kernel_filename, "rb"); - if (!f || !(kernel_size = get_file_size(f)) || - fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) != - MIN(ARRAY_SIZE(header), kernel_size)) { - fprintf(stderr, "qemu: could not load kernel '%s': %s\n", - kernel_filename, strerror(errno)); - exit(1); - } - - /* kernel protocol version */ -#if 0 - fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202)); -#endif - if (ldl_p(header+0x202) == 0x53726448) - protocol = lduw_p(header+0x206); - else { - /* This looks like a multiboot kernel. If it is, let's stop - treating it like a Linux kernel. */ - if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename, - kernel_cmdline, kernel_size, header)) - return; - protocol = 0; - } - - if (protocol < 0x200 || !(header[0x211] & 0x01)) { - /* Low kernel */ - real_addr = 0x90000; - cmdline_addr = 0x9a000 - cmdline_size; - prot_addr = 0x10000; - } else if (protocol < 0x202) { - /* High but ancient kernel */ - real_addr = 0x90000; - cmdline_addr = 0x9a000 - cmdline_size; - prot_addr = 0x100000; - } else { - /* High and recent kernel */ - real_addr = 0x10000; - cmdline_addr = 0x20000; - prot_addr = 0x100000; - } - -#if 0 - fprintf(stderr, - "qemu: real_addr = 0x" TARGET_FMT_plx "\n" - "qemu: cmdline_addr = 0x" TARGET_FMT_plx "\n" - "qemu: prot_addr = 0x" TARGET_FMT_plx "\n", - real_addr, - cmdline_addr, - prot_addr); -#endif - - /* highest address for loading the initrd */ - if (protocol >= 0x203) - initrd_max = ldl_p(header+0x22c); - else - initrd_max = 0x37ffffff; - - if (initrd_max >= max_ram_size-ACPI_DATA_SIZE) - initrd_max = max_ram_size-ACPI_DATA_SIZE-1; - - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - - if (protocol >= 0x202) { - stl_p(header+0x228, cmdline_addr); - } else { - stw_p(header+0x20, 0xA33F); - stw_p(header+0x22, cmdline_addr-real_addr); - } - - /* handle vga= parameter */ - vmode = strstr(kernel_cmdline, "vga="); - if (vmode) { - unsigned int video_mode; - /* skip "vga=" */ - vmode += 4; - if (!strncmp(vmode, "normal", 6)) { - video_mode = 0xffff; - } else if (!strncmp(vmode, "ext", 3)) { - video_mode = 0xfffe; - } else if (!strncmp(vmode, "ask", 3)) { - video_mode = 0xfffd; - } else { - video_mode = strtol(vmode, NULL, 0); - } - stw_p(header+0x1fa, video_mode); - } - - /* loader type */ - /* High nybble = B reserved for QEMU; low nybble is revision number. - If this code is substantially changed, you may want to consider - incrementing the revision. */ - if (protocol >= 0x200) - header[0x210] = 0xB0; - - /* heap */ - if (protocol >= 0x201) { - header[0x211] |= 0x80; /* CAN_USE_HEAP */ - stw_p(header+0x224, cmdline_addr-real_addr-0x200); - } - - /* load initrd */ - if (initrd_filename) { - if (protocol < 0x200) { - fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n"); - exit(1); - } - - initrd_size = get_image_size(initrd_filename); - if (initrd_size < 0) { - fprintf(stderr, "qemu: error reading initrd %s\n", - initrd_filename); - exit(1); - } - - initrd_addr = (initrd_max-initrd_size) & ~4095; - - initrd_data = g_malloc(initrd_size); - load_image(initrd_filename, initrd_data); - - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size); - - stl_p(header+0x218, initrd_addr); - stl_p(header+0x21c, initrd_size); - } - - /* load kernel and setup */ - setup_size = header[0x1f1]; - if (setup_size == 0) - setup_size = 4; - setup_size = (setup_size+1)*512; - kernel_size -= setup_size; - - setup = g_malloc(setup_size); - kernel = g_malloc(kernel_size); - fseek(f, 0, SEEK_SET); - if (fread(setup, 1, setup_size, f) != setup_size) { - fprintf(stderr, "fread() failed\n"); - exit(1); - } - if (fread(kernel, 1, kernel_size, f) != kernel_size) { - fprintf(stderr, "fread() failed\n"); - exit(1); - } - fclose(f); - memcpy(setup, header, MIN(sizeof(header), setup_size)); - - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); - - fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size); - - option_rom[nb_option_roms].name = "linuxboot.bin"; - option_rom[nb_option_roms].bootindex = 0; - nb_option_roms++; -} - -#define NE2000_NB_MAX 6 - -static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, - 0x280, 0x380 }; -static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; - -static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; -static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; - -void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd) -{ - static int nb_ne2k = 0; - - if (nb_ne2k == NE2000_NB_MAX) - return; - isa_ne2000_init(bus, ne2000_io[nb_ne2k], - ne2000_irq[nb_ne2k], nd); - nb_ne2k++; -} - -DeviceState *cpu_get_current_apic(void) -{ - if (cpu_single_env) { - return cpu_single_env->apic_state; - } else { - return NULL; - } -} - -void pc_acpi_smi_interrupt(void *opaque, int irq, int level) -{ - CPUX86State *s = opaque; - - if (level) { - cpu_interrupt(s, CPU_INTERRUPT_SMI); - } -} - -void pc_cpus_init(const char *cpu_model) -{ - int i; - - /* init CPUs */ - if (cpu_model == NULL) { -#ifdef TARGET_X86_64 - cpu_model = "qemu64"; -#else - cpu_model = "qemu32"; -#endif - } - - for (i = 0; i < smp_cpus; i++) { - if (!cpu_x86_init(cpu_model)) { - exit(1); - } - } -} - -void pc_acpi_init(const char *default_dsdt) -{ - char *filename = NULL, *arg = NULL; - - if (acpi_tables != NULL) { - /* manually set via -acpitable, leave it alone */ - return; - } - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt); - if (filename == NULL) { - fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt); - return; - } - - arg = g_strdup_printf("file=%s", filename); - if (acpi_table_add(arg) != 0) { - fprintf(stderr, "WARNING: failed to load %s\n", filename); - } - g_free(arg); - g_free(filename); -} - -void *pc_memory_init(MemoryRegion *system_memory, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, - MemoryRegion *rom_memory, - MemoryRegion **ram_memory) -{ - int linux_boot, i; - MemoryRegion *ram, *option_rom_mr; - MemoryRegion *ram_below_4g, *ram_above_4g; - void *fw_cfg; - - linux_boot = (kernel_filename != NULL); - - /* Allocate RAM. We allocate it as a single memory region and use - * aliases to address portions of it, mostly for backwards compatibility - * with older qemus that used qemu_ram_alloc(). - */ - ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, "pc.ram", - below_4g_mem_size + above_4g_mem_size); - vmstate_register_ram_global(ram); - *ram_memory = ram; - ram_below_4g = g_malloc(sizeof(*ram_below_4g)); - memory_region_init_alias(ram_below_4g, "ram-below-4g", ram, - 0, below_4g_mem_size); - memory_region_add_subregion(system_memory, 0, ram_below_4g); - if (above_4g_mem_size > 0) { - ram_above_4g = g_malloc(sizeof(*ram_above_4g)); - memory_region_init_alias(ram_above_4g, "ram-above-4g", ram, - below_4g_mem_size, above_4g_mem_size); - memory_region_add_subregion(system_memory, 0x100000000ULL, - ram_above_4g); - } - - - /* Initialize PC system firmware */ - pc_system_firmware_init(rom_memory); - - option_rom_mr = g_malloc(sizeof(*option_rom_mr)); - memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE); - vmstate_register_ram_global(option_rom_mr); - memory_region_add_subregion_overlap(rom_memory, - PC_ROM_MIN_VGA, - option_rom_mr, - 1); - - fw_cfg = bochs_bios_init(); - rom_set_fw(fw_cfg); - - if (linux_boot) { - load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size); - } - - for (i = 0; i < nb_option_roms; i++) { - rom_add_option(option_rom[i].name, option_rom[i].bootindex); - } - return fw_cfg; -} - -qemu_irq *pc_allocate_cpu_irq(void) -{ - return qemu_allocate_irqs(pic_irq_request, NULL, 1); -} - -DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) -{ - DeviceState *dev = NULL; - - if (pci_bus) { - PCIDevice *pcidev = pci_vga_init(pci_bus); - dev = pcidev ? &pcidev->qdev : NULL; - } else if (isa_bus) { - ISADevice *isadev = isa_vga_init(isa_bus); - dev = isadev ? &isadev->qdev : NULL; - } - return dev; -} - -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUX86State *env = cpu_single_env; - - if (env && level) { - cpu_exit(env); - } -} - -static const MemoryRegionOps ioport80_io_ops = { - .write = ioport80_write, - .read = ioport80_read, - .endianness = DEVICE_NATIVE_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static const MemoryRegionOps ioportF0_io_ops = { - .write = ioportF0_write, - .read = ioportF0_read, - .endianness = DEVICE_NATIVE_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, - ISADevice **rtc_state, - ISADevice **floppy, - bool no_vmport) -{ - int i; - DriveInfo *fd[MAX_FD]; - DeviceState *hpet = NULL; - int pit_isa_irq = 0; - qemu_irq pit_alt_irq = NULL; - qemu_irq rtc_irq = NULL; - qemu_irq *a20_line; - ISADevice *i8042, *port92, *vmmouse, *pit = NULL; - qemu_irq *cpu_exit_irq; - MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); - MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); - - memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1); - memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io); - - memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1); - memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io); - - /* - * Check if an HPET shall be created. - * - * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT - * when the HPET wants to take over. Thus we have to disable the latter. - */ - if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) { - hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL); - - if (hpet) { - for (i = 0; i < GSI_NUM_PINS; i++) { - sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]); - } - pit_isa_irq = -1; - pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT); - rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT); - } - } - *rtc_state = rtc_init(isa_bus, 2000, rtc_irq); - - qemu_register_boot_set(pc_boot_set, *rtc_state); - - if (!xen_enabled()) { - if (kvm_irqchip_in_kernel()) { - pit = kvm_pit_init(isa_bus, 0x40); - } else { - pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq); - } - if (hpet) { - /* connect PIT to output control line of the HPET */ - qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0)); - } - pcspk_init(isa_bus, pit); - } - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_hds[i]) { - parallel_init(isa_bus, i, parallel_hds[i]); - } - } - - a20_line = qemu_allocate_irqs(handle_a20_line_change, - x86_env_get_cpu(first_cpu), 2); - i8042 = isa_create_simple(isa_bus, "i8042"); - i8042_setup_a20_line(i8042, &a20_line[0]); - if (!no_vmport) { - vmport_init(isa_bus); - vmmouse = isa_try_create(isa_bus, "vmmouse"); - } else { - vmmouse = NULL; - } - if (vmmouse) { - qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042); - qdev_init_nofail(&vmmouse->qdev); - } - port92 = isa_create_simple(isa_bus, "port92"); - port92_init(port92, &a20_line[1]); - - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); - - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - } - *floppy = fdctrl_init_isa(isa_bus, fd); -} - -void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) -{ - int i; - - for (i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - - if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) { - pc_init_ne2k_isa(isa_bus, nd); - } else { - pci_nic_init_nofail(nd, "e1000", NULL); - } - } -} - -void pc_pci_device_init(PCIBus *pci_bus) -{ - int max_bus; - int bus; - - max_bus = drive_get_max_bus(IF_SCSI); - for (bus = 0; bus <= max_bus; bus++) { - pci_create_simple(pci_bus, -1, "lsi53c895a"); - } -} - -void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) -{ - DeviceState *dev; - SysBusDevice *d; - unsigned int i; - - if (kvm_irqchip_in_kernel()) { - dev = qdev_create(NULL, "kvm-ioapic"); - } else { - dev = qdev_create(NULL, "ioapic"); - } - if (parent_name) { - object_property_add_child(object_resolve_path(parent_name, NULL), - "ioapic", OBJECT(dev), NULL); - } - qdev_init_nofail(dev); - d = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(d, 0, 0xfec00000); - - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); - } -} diff --git a/hw/pc_piix.c b/hw/pc_piix.c deleted file mode 100644 index 73a8656df8..0000000000 --- a/hw/pc_piix.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * QEMU PC System Emulator - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include - -#include "hw/hw.h" -#include "hw/pc.h" -#include "hw/apic.h" -#include "hw/pci/pci.h" -#include "hw/pci/pci_ids.h" -#include "hw/usb.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/ide.h" -#include "sysemu/kvm.h" -#include "hw/kvm/clock.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "sysemu/arch_init.h" -#include "sysemu/blockdev.h" -#include "hw/smbus.h" -#include "hw/xen.h" -#include "exec/memory.h" -#include "exec/address-spaces.h" -#include "cpu.h" -#ifdef CONFIG_XEN -# include -#endif - -#define MAX_IDE_BUS 2 - -static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; -static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; -static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; - -/* PC hardware initialisation */ -static void pc_init1(MemoryRegion *system_memory, - MemoryRegion *system_io, - ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model, - int pci_enabled, - int kvmclock_enabled) -{ - int i; - ram_addr_t below_4g_mem_size, above_4g_mem_size; - PCIBus *pci_bus; - ISABus *isa_bus; - PCII440FXState *i440fx_state; - int piix3_devfn = -1; - qemu_irq *cpu_irq; - qemu_irq *gsi; - qemu_irq *i8259; - qemu_irq *smi_irq; - GSIState *gsi_state; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - BusState *idebus[MAX_IDE_BUS]; - ISADevice *rtc_state; - ISADevice *floppy; - MemoryRegion *ram_memory; - MemoryRegion *pci_memory; - MemoryRegion *rom_memory; - void *fw_cfg = NULL; - - pc_cpus_init(cpu_model); - pc_acpi_init("acpi-dsdt.aml"); - - if (kvmclock_enabled) { - kvmclock_create(); - } - - if (ram_size >= 0xe0000000 ) { - above_4g_mem_size = ram_size - 0xe0000000; - below_4g_mem_size = 0xe0000000; - } else { - above_4g_mem_size = 0; - below_4g_mem_size = ram_size; - } - - if (pci_enabled) { - pci_memory = g_new(MemoryRegion, 1); - memory_region_init(pci_memory, "pci", INT64_MAX); - rom_memory = pci_memory; - } else { - pci_memory = NULL; - rom_memory = system_memory; - } - - /* allocate ram and load rom/bios */ - if (!xen_enabled()) { - fw_cfg = pc_memory_init(system_memory, - kernel_filename, kernel_cmdline, initrd_filename, - below_4g_mem_size, above_4g_mem_size, - rom_memory, &ram_memory); - } - - gsi_state = g_malloc0(sizeof(*gsi_state)); - if (kvm_irqchip_in_kernel()) { - kvm_pc_setup_irq_routing(pci_enabled); - gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, - GSI_NUM_PINS); - } else { - gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); - } - - if (pci_enabled) { - pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, - system_memory, system_io, ram_size, - below_4g_mem_size, - 0x100000000ULL - below_4g_mem_size, - 0x100000000ULL + above_4g_mem_size, - (sizeof(hwaddr) == 4 - ? 0 - : ((uint64_t)1 << 62)), - pci_memory, ram_memory); - } else { - pci_bus = NULL; - i440fx_state = NULL; - isa_bus = isa_bus_new(NULL, system_io); - no_hpet = 1; - } - isa_bus_irqs(isa_bus, gsi); - - if (kvm_irqchip_in_kernel()) { - i8259 = kvm_i8259_init(isa_bus); - } else if (xen_enabled()) { - i8259 = xen_interrupt_controller_init(); - } else { - cpu_irq = pc_allocate_cpu_irq(); - i8259 = i8259_init(isa_bus, cpu_irq[0]); - } - - for (i = 0; i < ISA_NUM_IRQS; i++) { - gsi_state->i8259_irq[i] = i8259[i]; - } - if (pci_enabled) { - ioapic_init_gsi(gsi_state, "i440fx"); - } - - pc_register_ferr_irq(gsi[13]); - - pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); - if (xen_enabled()) { - pci_create_simple(pci_bus, -1, "xen-platform"); - } - - /* init basic PC hardware */ - pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled()); - - pc_nic_init(isa_bus, pci_bus); - - ide_drive_get(hd, MAX_IDE_BUS); - if (pci_enabled) { - PCIDevice *dev; - if (xen_enabled()) { - dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1); - } else { - dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1); - } - idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); - idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); - } else { - for(i = 0; i < MAX_IDE_BUS; i++) { - ISADevice *dev; - dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], - ide_irq[i], - hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); - idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0"); - } - } - - audio_init(isa_bus, pci_enabled ? pci_bus : NULL); - - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, - floppy, idebus[0], idebus[1], rtc_state); - - if (pci_enabled && usb_enabled(false)) { - pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); - } - - if (pci_enabled && acpi_enabled) { - i2c_bus *smbus; - - smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1); - /* TODO: Populate SPD eeprom data. */ - smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, - gsi[9], *smi_irq, - kvm_enabled(), fw_cfg); - smbus_eeprom_init(smbus, 8, NULL, 0); - } - - if (pci_enabled) { - pc_pci_device_init(pci_bus); - } -} - -static void pc_init_pci(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - pc_init1(get_system_memory(), - get_system_io(), - ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 1, 1); -} - -static void pc_init_pci_1_3(QEMUMachineInitArgs *args) -{ - enable_compat_apic_id_mode(); - pc_init_pci(args); -} - -/* PC machine init function for pc-0.14 to pc-1.2 */ -static void pc_init_pci_1_2(QEMUMachineInitArgs *args) -{ - disable_kvm_pv_eoi(); - pc_init_pci_1_3(args); -} - -/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ -static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - disable_kvm_pv_eoi(); - enable_compat_apic_id_mode(); - pc_init1(get_system_memory(), - get_system_io(), - ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 1, 0); -} - -static void pc_init_isa(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - if (cpu_model == NULL) - cpu_model = "486"; - disable_kvm_pv_eoi(); - enable_compat_apic_id_mode(); - pc_init1(get_system_memory(), - get_system_io(), - ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 0, 1); -} - -#ifdef CONFIG_XEN -static void pc_xen_hvm_init(QEMUMachineInitArgs *args) -{ - if (xen_hvm_init() != 0) { - hw_error("xen hardware virtual machine initialisation failed"); - } - pc_init_pci_no_kvmclock(args); - xen_vcpu_init(); -} -#endif - -static QEMUMachine pc_i440fx_machine_v1_5 = { - .name = "pc-i440fx-1.5", - .alias = "pc", - .desc = "Standard PC (i440FX + PIIX, 1996)", - .init = pc_init_pci, - .max_cpus = 255, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine pc_i440fx_machine_v1_4 = { - .name = "pc-i440fx-1.4", - .desc = "Standard PC (i440FX + PIIX, 1996)", - .init = pc_init_pci, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_1_4, - { /* end of list */ } - }, - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_1_3 \ - PC_COMPAT_1_4, \ - {\ - .driver = "usb-tablet",\ - .property = "usb_version",\ - .value = stringify(1),\ - },{\ - .driver = "virtio-net-pci",\ - .property = "ctrl_mac_addr",\ - .value = "off", \ - },{ \ - .driver = "virtio-net-pci", \ - .property = "mq", \ - .value = "off", \ - } - -static QEMUMachine pc_machine_v1_3 = { - .name = "pc-1.3", - .desc = "Standard PC", - .init = pc_init_pci_1_3, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_1_3, - { /* end of list */ } - }, - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_1_2 \ - PC_COMPAT_1_3,\ - {\ - .driver = "nec-usb-xhci",\ - .property = "msi",\ - .value = "off",\ - },{\ - .driver = "nec-usb-xhci",\ - .property = "msix",\ - .value = "off",\ - },{\ - .driver = "ivshmem",\ - .property = "use64",\ - .value = "0",\ - },{\ - .driver = "qxl",\ - .property = "revision",\ - .value = stringify(3),\ - },{\ - .driver = "qxl-vga",\ - .property = "revision",\ - .value = stringify(3),\ - },{\ - .driver = "VGA",\ - .property = "mmio",\ - .value = "off",\ - } - -static QEMUMachine pc_machine_v1_2 = { - .name = "pc-1.2", - .desc = "Standard PC", - .init = pc_init_pci_1_2, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_1_2, - { /* end of list */ } - }, - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_1_1 \ - PC_COMPAT_1_2,\ - {\ - .driver = "virtio-scsi-pci",\ - .property = "hotplug",\ - .value = "off",\ - },{\ - .driver = "virtio-scsi-pci",\ - .property = "param_change",\ - .value = "off",\ - },{\ - .driver = "VGA",\ - .property = "vgamem_mb",\ - .value = stringify(8),\ - },{\ - .driver = "vmware-svga",\ - .property = "vgamem_mb",\ - .value = stringify(8),\ - },{\ - .driver = "qxl-vga",\ - .property = "vgamem_mb",\ - .value = stringify(8),\ - },{\ - .driver = "qxl",\ - .property = "vgamem_mb",\ - .value = stringify(8),\ - },{\ - .driver = "virtio-blk-pci",\ - .property = "config-wce",\ - .value = "off",\ - } - -static QEMUMachine pc_machine_v1_1 = { - .name = "pc-1.1", - .desc = "Standard PC", - .init = pc_init_pci_1_2, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_1_1, - { /* end of list */ } - }, - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_1_0 \ - PC_COMPAT_1_1,\ - {\ - .driver = "pc-sysfw",\ - .property = "rom_only",\ - .value = stringify(1),\ - }, {\ - .driver = "isa-fdc",\ - .property = "check_media_rate",\ - .value = "off",\ - }, {\ - .driver = "virtio-balloon-pci",\ - .property = "class",\ - .value = stringify(PCI_CLASS_MEMORY_RAM),\ - },{\ - .driver = "apic",\ - .property = "vapic",\ - .value = "off",\ - },{\ - .driver = TYPE_USB_DEVICE,\ - .property = "full-path",\ - .value = "no",\ - } - -static QEMUMachine pc_machine_v1_0 = { - .name = "pc-1.0", - .desc = "Standard PC", - .init = pc_init_pci_1_2, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_1_0, - { /* end of list */ } - }, - .hw_version = "1.0", - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_0_15 \ - PC_COMPAT_1_0 - -static QEMUMachine pc_machine_v0_15 = { - .name = "pc-0.15", - .desc = "Standard PC", - .init = pc_init_pci_1_2, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_0_15, - { /* end of list */ } - }, - .hw_version = "0.15", - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_0_14 \ - PC_COMPAT_0_15,\ - {\ - .driver = "virtio-blk-pci",\ - .property = "event_idx",\ - .value = "off",\ - },{\ - .driver = "virtio-serial-pci",\ - .property = "event_idx",\ - .value = "off",\ - },{\ - .driver = "virtio-net-pci",\ - .property = "event_idx",\ - .value = "off",\ - },{\ - .driver = "virtio-balloon-pci",\ - .property = "event_idx",\ - .value = "off",\ - } - -static QEMUMachine pc_machine_v0_14 = { - .name = "pc-0.14", - .desc = "Standard PC", - .init = pc_init_pci_1_2, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_0_14, - { - .driver = "qxl", - .property = "revision", - .value = stringify(2), - },{ - .driver = "qxl-vga", - .property = "revision", - .value = stringify(2), - }, - { /* end of list */ } - }, - .hw_version = "0.14", - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_0_13 \ - PC_COMPAT_0_14,\ - {\ - .driver = TYPE_PCI_DEVICE,\ - .property = "command_serr_enable",\ - .value = "off",\ - },{\ - .driver = "AC97",\ - .property = "use_broken_id",\ - .value = stringify(1),\ - } - -static QEMUMachine pc_machine_v0_13 = { - .name = "pc-0.13", - .desc = "Standard PC", - .init = pc_init_pci_no_kvmclock, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_0_13, - { - .driver = "virtio-9p-pci", - .property = "vectors", - .value = stringify(0), - },{ - .driver = "VGA", - .property = "rombar", - .value = stringify(0), - },{ - .driver = "vmware-svga", - .property = "rombar", - .value = stringify(0), - }, - { /* end of list */ } - }, - .hw_version = "0.13", - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_0_12 \ - PC_COMPAT_0_13,\ - {\ - .driver = "virtio-serial-pci",\ - .property = "max_ports",\ - .value = stringify(1),\ - },{\ - .driver = "virtio-serial-pci",\ - .property = "vectors",\ - .value = stringify(0),\ - } - -static QEMUMachine pc_machine_v0_12 = { - .name = "pc-0.12", - .desc = "Standard PC", - .init = pc_init_pci_no_kvmclock, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_0_12, - { - .driver = "VGA", - .property = "rombar", - .value = stringify(0), - },{ - .driver = "vmware-svga", - .property = "rombar", - .value = stringify(0), - }, - { /* end of list */ } - }, - .hw_version = "0.12", - DEFAULT_MACHINE_OPTIONS, -}; - -#define PC_COMPAT_0_11 \ - PC_COMPAT_0_12,\ - {\ - .driver = "virtio-blk-pci",\ - .property = "vectors",\ - .value = stringify(0),\ - },{\ - .driver = TYPE_PCI_DEVICE,\ - .property = "rombar",\ - .value = stringify(0),\ - } - -static QEMUMachine pc_machine_v0_11 = { - .name = "pc-0.11", - .desc = "Standard PC, qemu 0.11", - .init = pc_init_pci_no_kvmclock, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_0_11, - { - .driver = "ide-drive", - .property = "ver", - .value = "0.11", - },{ - .driver = "scsi-disk", - .property = "ver", - .value = "0.11", - }, - { /* end of list */ } - }, - .hw_version = "0.11", - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine pc_machine_v0_10 = { - .name = "pc-0.10", - .desc = "Standard PC, qemu 0.10", - .init = pc_init_pci_no_kvmclock, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_0_11, - { - .driver = "virtio-blk-pci", - .property = "class", - .value = stringify(PCI_CLASS_STORAGE_OTHER), - },{ - .driver = "virtio-serial-pci", - .property = "class", - .value = stringify(PCI_CLASS_DISPLAY_OTHER), - },{ - .driver = "virtio-net-pci", - .property = "vectors", - .value = stringify(0), - },{ - .driver = "ide-drive", - .property = "ver", - .value = "0.10", - },{ - .driver = "scsi-disk", - .property = "ver", - .value = "0.10", - }, - { /* end of list */ } - }, - .hw_version = "0.10", - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine isapc_machine = { - .name = "isapc", - .desc = "ISA-only PC", - .init = pc_init_isa, - .max_cpus = 1, - .compat_props = (GlobalProperty[]) { - { - .driver = "pc-sysfw", - .property = "rom_only", - .value = stringify(1), - }, - { /* end of list */ } - }, - DEFAULT_MACHINE_OPTIONS, -}; - -#ifdef CONFIG_XEN -static QEMUMachine xenfv_machine = { - .name = "xenfv", - .desc = "Xen Fully-virtualized PC", - .init = pc_xen_hvm_init, - .max_cpus = HVM_MAX_VCPUS, - .default_machine_opts = "accel=xen", - DEFAULT_MACHINE_OPTIONS, -}; -#endif - -static void pc_machine_init(void) -{ - qemu_register_machine(&pc_i440fx_machine_v1_5); - qemu_register_machine(&pc_i440fx_machine_v1_4); - qemu_register_machine(&pc_machine_v1_3); - qemu_register_machine(&pc_machine_v1_2); - qemu_register_machine(&pc_machine_v1_1); - qemu_register_machine(&pc_machine_v1_0); - qemu_register_machine(&pc_machine_v0_15); - qemu_register_machine(&pc_machine_v0_14); - qemu_register_machine(&pc_machine_v0_13); - qemu_register_machine(&pc_machine_v0_12); - qemu_register_machine(&pc_machine_v0_11); - qemu_register_machine(&pc_machine_v0_10); - qemu_register_machine(&isapc_machine); -#ifdef CONFIG_XEN - qemu_register_machine(&xenfv_machine); -#endif -} - -machine_init(pc_machine_init); diff --git a/hw/pc_q35.c b/hw/pc_q35.c deleted file mode 100644 index 4f5f347309..0000000000 --- a/hw/pc_q35.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Q35 chipset based pc system emulator - * - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2009, 2010 - * Isaku Yamahata - * VA Linux Systems Japan K.K. - * Copyright (C) 2012 Jason Baron - * - * This is based on pc.c, but heavily modified. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "sysemu/arch_init.h" -#include "hw/smbus.h" -#include "hw/boards.h" -#include "hw/mc146818rtc.h" -#include "hw/xen.h" -#include "sysemu/kvm.h" -#include "hw/kvm/clock.h" -#include "hw/q35.h" -#include "exec/address-spaces.h" -#include "hw/ich9.h" -#include "hw/ide/pci.h" -#include "hw/ide/ahci.h" -#include "hw/usb.h" - -/* ICH9 AHCI has 6 ports */ -#define MAX_SATA_PORTS 6 - -/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) - * BIOS will read it and start S3 resume at POST Entry */ -static void pc_cmos_set_s3_resume(void *opaque, int irq, int level) -{ - ISADevice *s = opaque; - - if (level) { - rtc_set_memory(s, 0xF, 0xFE); - } -} - -/* PC hardware initialisation */ -static void pc_q35_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - ram_addr_t below_4g_mem_size, above_4g_mem_size; - Q35PCIHost *q35_host; - PCIBus *host_bus; - PCIDevice *lpc; - BusState *idebus[MAX_SATA_PORTS]; - ISADevice *rtc_state; - ISADevice *floppy; - MemoryRegion *pci_memory; - MemoryRegion *rom_memory; - MemoryRegion *ram_memory; - GSIState *gsi_state; - ISABus *isa_bus; - int pci_enabled = 1; - qemu_irq *cpu_irq; - qemu_irq *gsi; - qemu_irq *i8259; - int i; - ICH9LPCState *ich9_lpc; - PCIDevice *ahci; - qemu_irq *cmos_s3; - - pc_cpus_init(cpu_model); - pc_acpi_init("q35-acpi-dsdt.aml"); - - kvmclock_create(); - - if (ram_size >= 0xb0000000) { - above_4g_mem_size = ram_size - 0xb0000000; - below_4g_mem_size = 0xb0000000; - } else { - above_4g_mem_size = 0; - below_4g_mem_size = ram_size; - } - - /* pci enabled */ - if (pci_enabled) { - pci_memory = g_new(MemoryRegion, 1); - memory_region_init(pci_memory, "pci", INT64_MAX); - rom_memory = pci_memory; - } else { - pci_memory = NULL; - rom_memory = get_system_memory(); - } - - /* allocate ram and load rom/bios */ - if (!xen_enabled()) { - pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline, - initrd_filename, below_4g_mem_size, above_4g_mem_size, - rom_memory, &ram_memory); - } - - /* irq lines */ - gsi_state = g_malloc0(sizeof(*gsi_state)); - if (kvm_irqchip_in_kernel()) { - kvm_pc_setup_irq_routing(pci_enabled); - gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, - GSI_NUM_PINS); - } else { - gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); - } - - /* create pci host bus */ - q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); - - q35_host->mch.ram_memory = ram_memory; - q35_host->mch.pci_address_space = pci_memory; - q35_host->mch.system_memory = get_system_memory(); - q35_host->mch.address_space_io = get_system_io();; - q35_host->mch.below_4g_mem_size = below_4g_mem_size; - q35_host->mch.above_4g_mem_size = above_4g_mem_size; - /* pci */ - qdev_init_nofail(DEVICE(q35_host)); - host_bus = q35_host->host.pci.bus; - /* create ISA bus */ - lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV, - ICH9_LPC_FUNC), true, - TYPE_ICH9_LPC_DEVICE); - ich9_lpc = ICH9_LPC_DEVICE(lpc); - ich9_lpc->pic = gsi; - ich9_lpc->ioapic = gsi_state->ioapic_irq; - pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc, - ICH9_LPC_NB_PIRQS); - pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq); - isa_bus = ich9_lpc->isa_bus; - - /*end early*/ - isa_bus_irqs(isa_bus, gsi); - - if (kvm_irqchip_in_kernel()) { - i8259 = kvm_i8259_init(isa_bus); - } else if (xen_enabled()) { - i8259 = xen_interrupt_controller_init(); - } else { - cpu_irq = pc_allocate_cpu_irq(); - i8259 = i8259_init(isa_bus, cpu_irq[0]); - } - - for (i = 0; i < ISA_NUM_IRQS; i++) { - gsi_state->i8259_irq[i] = i8259[i]; - } - if (pci_enabled) { - ioapic_init_gsi(gsi_state, NULL); - } - - pc_register_ferr_irq(gsi[13]); - - /* init basic PC hardware */ - pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false); - - /* connect pm stuff to lpc */ - cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); - ich9_lpc_pm_init(lpc, *cmos_s3); - - /* ahci and SATA device, for q35 1 ahci controller is built-in */ - ahci = pci_create_simple_multifunction(host_bus, - PCI_DEVFN(ICH9_SATA1_DEV, - ICH9_SATA1_FUNC), - true, "ich9-ahci"); - idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); - idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); - - if (usb_enabled(false)) { - /* Should we create 6 UHCI according to ich9 spec? */ - ehci_create_ich9_with_companions(host_bus, 0x1d); - } - - /* TODO: Populate SPD eeprom data. */ - smbus_eeprom_init(ich9_smb_init(host_bus, - PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), - 0xb100), - 8, NULL, 0); - - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, - floppy, idebus[0], idebus[1], rtc_state); - - /* the rest devices to which pci devfn is automatically assigned */ - pc_vga_init(isa_bus, host_bus); - audio_init(isa_bus, host_bus); - pc_nic_init(isa_bus, host_bus); - if (pci_enabled) { - pc_pci_device_init(host_bus); - } -} - -static QEMUMachine pc_q35_machine_v1_5 = { - .name = "pc-q35-1.5", - .alias = "q35", - .desc = "Standard PC (Q35 + ICH9, 2009)", - .init = pc_q35_init, - .max_cpus = 255, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine pc_q35_machine_v1_4 = { - .name = "pc-q35-1.4", - .desc = "Standard PC (Q35 + ICH9, 2009)", - .init = pc_q35_init, - .max_cpus = 255, - .compat_props = (GlobalProperty[]) { - PC_COMPAT_1_4, - { /* end of list */ } - }, - DEFAULT_MACHINE_OPTIONS, -}; - -static void pc_q35_machine_init(void) -{ - qemu_register_machine(&pc_q35_machine_v1_5); - qemu_register_machine(&pc_q35_machine_v1_4); -} - -machine_init(pc_q35_machine_init); diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c deleted file mode 100644 index cfc02207ab..0000000000 --- a/hw/petalogix_ml605_mmu.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Model of Petalogix linux reference design targeting Xilinx Spartan ml605 - * board. - * - * Copyright (c) 2011 Michal Simek - * Copyright (c) 2011 PetaLogix - * Copyright (c) 2009 Edgar E. Iglesias. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "net/net.h" -#include "hw/flash.h" -#include "sysemu/sysemu.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/xilinx.h" -#include "sysemu/blockdev.h" -#include "hw/serial.h" -#include "exec/address-spaces.h" -#include "hw/ssi.h" - -#include "hw/microblaze_boot.h" -#include "hw/microblaze_pic_cpu.h" - -#include "hw/stream.h" - -#define LMB_BRAM_SIZE (128 * 1024) -#define FLASH_SIZE (32 * 1024 * 1024) - -#define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb" - -#define NUM_SPI_FLASHES 4 - -#define MEMORY_BASEADDR 0x50000000 -#define FLASH_BASEADDR 0x86000000 -#define INTC_BASEADDR 0x81800000 -#define TIMER_BASEADDR 0x83c00000 -#define UART16550_BASEADDR 0x83e00000 -#define AXIENET_BASEADDR 0x82780000 -#define AXIDMA_BASEADDR 0x84600000 - -static void machine_cpu_reset(MicroBlazeCPU *cpu) -{ - CPUMBState *env = &cpu->env; - - env->pvr.regs[10] = 0x0e000000; /* virtex 6 */ - /* setup pvr to match kernel setting */ - env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK; - env->pvr.regs[0] |= PVR0_USE_FPU_MASK | PVR0_ENDI; - env->pvr.regs[0] = (env->pvr.regs[0] & ~PVR0_VERSION_MASK) | (0x14 << 8); - env->pvr.regs[2] ^= PVR2_USE_FPU2_MASK; - env->pvr.regs[4] = 0xc56b8000; - env->pvr.regs[5] = 0xc56be000; -} - -static void -petalogix_ml605_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - MemoryRegion *address_space_mem = get_system_memory(); - DeviceState *dev, *dma, *eth0; - MicroBlazeCPU *cpu; - SysBusDevice *busdev; - CPUMBState *env; - DriveInfo *dinfo; - int i; - hwaddr ddr_base = MEMORY_BASEADDR; - MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); - MemoryRegion *phys_ram = g_new(MemoryRegion, 1); - qemu_irq irq[32], *cpu_irq; - - /* init CPUs */ - if (cpu_model == NULL) { - cpu_model = "microblaze"; - } - cpu = cpu_mb_init(cpu_model); - env = &cpu->env; - - /* Attach emulated BRAM through the LMB. */ - memory_region_init_ram(phys_lmb_bram, "petalogix_ml605.lmb_bram", - LMB_BRAM_SIZE); - vmstate_register_ram_global(phys_lmb_bram); - memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram); - - memory_region_init_ram(phys_ram, "petalogix_ml605.ram", ram_size); - vmstate_register_ram_global(phys_ram); - memory_region_add_subregion(address_space_mem, ddr_base, phys_ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* 5th parameter 2 means bank-width - * 10th paremeter 0 means little-endian */ - pflash_cfi01_register(FLASH_BASEADDR, - NULL, "petalogix_ml605.flash", FLASH_SIZE, - dinfo ? dinfo->bdrv : NULL, (64 * 1024), - FLASH_SIZE >> 16, - 2, 0x89, 0x18, 0x0000, 0x0, 0); - - - cpu_irq = microblaze_pic_init_cpu(env); - dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 4); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(dev, i); - } - - serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2, - irq[5], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN); - - /* 2 timers at irq 2 @ 100 Mhz. */ - xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000); - - /* axi ethernet and dma initialization. */ - qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet"); - eth0 = qdev_create(NULL, "xlnx.axi-ethernet"); - dma = qdev_create(NULL, "xlnx.axi-dma"); - - /* FIXME: attach to the sysbus instead */ - object_property_add_child(container_get(qdev_get_machine(), "/unattached"), - "xilinx-dma", OBJECT(dma), NULL); - - xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(dma), - 0x82780000, irq[3], 0x1000, 0x1000); - - xilinx_axidma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0], - 100 * 1000000); - - { - SSIBus *spi; - - dev = qdev_create(NULL, "xlnx.xps-spi"); - qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0x40a00000); - sysbus_connect_irq(busdev, 0, irq[4]); - - spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); - - for (i = 0; i < NUM_SPI_FLASHES; i++) { - qemu_irq cs_line; - - dev = ssi_create_slave_no_init(spi, "n25q128"); - qdev_init_nofail(dev); - cs_line = qdev_get_gpio_in(dev, 0); - sysbus_connect_irq(busdev, i+1, cs_line); - } - } - - microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, - machine_cpu_reset); - -} - -static QEMUMachine petalogix_ml605_machine = { - .name = "petalogix-ml605", - .desc = "PetaLogix linux refdesign for xilinx ml605 little endian", - .init = petalogix_ml605_init, - .is_default = 0, - DEFAULT_MACHINE_OPTIONS, -}; - -static void petalogix_ml605_machine_init(void) -{ - qemu_register_machine(&petalogix_ml605_machine); -} - -machine_init(petalogix_ml605_machine_init); diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c deleted file mode 100644 index 24983621e5..0000000000 --- a/hw/petalogix_s3adsp1800_mmu.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800 - * boards. - * - * Copyright (c) 2009 Edgar E. Iglesias. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "net/net.h" -#include "hw/flash.h" -#include "sysemu/sysemu.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/xilinx.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#include "hw/microblaze_boot.h" -#include "hw/microblaze_pic_cpu.h" - -#define LMB_BRAM_SIZE (128 * 1024) -#define FLASH_SIZE (16 * 1024 * 1024) - -#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb" - -#define MEMORY_BASEADDR 0x90000000 -#define FLASH_BASEADDR 0xa0000000 -#define INTC_BASEADDR 0x81800000 -#define TIMER_BASEADDR 0x83c00000 -#define UARTLITE_BASEADDR 0x84000000 -#define ETHLITE_BASEADDR 0x81000000 - -static void machine_cpu_reset(MicroBlazeCPU *cpu) -{ - CPUMBState *env = &cpu->env; - - env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */ -} - -static void -petalogix_s3adsp1800_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - DeviceState *dev; - MicroBlazeCPU *cpu; - CPUMBState *env; - DriveInfo *dinfo; - int i; - hwaddr ddr_base = MEMORY_BASEADDR; - MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); - MemoryRegion *phys_ram = g_new(MemoryRegion, 1); - qemu_irq irq[32], *cpu_irq; - MemoryRegion *sysmem = get_system_memory(); - - /* init CPUs */ - if (cpu_model == NULL) { - cpu_model = "microblaze"; - } - cpu = cpu_mb_init(cpu_model); - env = &cpu->env; - - /* Attach emulated BRAM through the LMB. */ - memory_region_init_ram(phys_lmb_bram, - "petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE); - vmstate_register_ram_global(phys_lmb_bram); - memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram); - - memory_region_init_ram(phys_ram, "petalogix_s3adsp1800.ram", ram_size); - vmstate_register_ram_global(phys_ram); - memory_region_add_subregion(sysmem, ddr_base, phys_ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - pflash_cfi01_register(FLASH_BASEADDR, - NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE, - dinfo ? dinfo->bdrv : NULL, (64 * 1024), - FLASH_SIZE >> 16, - 1, 0x89, 0x18, 0x0000, 0x0, 1); - - cpu_irq = microblaze_pic_init_cpu(env); - dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 2); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(dev, i); - } - - sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, irq[3]); - /* 2 timers at irq 2 @ 62 Mhz. */ - xilinx_timer_create(TIMER_BASEADDR, irq[0], 0, 62 * 1000000); - xilinx_ethlite_create(&nd_table[0], ETHLITE_BASEADDR, irq[1], 0, 0); - - microblaze_load_kernel(cpu, ddr_base, ram_size, - BINARY_DEVICE_TREE_FILE, machine_cpu_reset); -} - -static QEMUMachine petalogix_s3adsp1800_machine = { - .name = "petalogix-s3adsp1800", - .desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800", - .init = petalogix_s3adsp1800_init, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void petalogix_s3adsp1800_machine_init(void) -{ - qemu_register_machine(&petalogix_s3adsp1800_machine); -} - -machine_init(petalogix_s3adsp1800_machine_init); diff --git a/hw/ppc.c b/hw/ppc.c deleted file mode 100644 index c9437fc6a7..0000000000 --- a/hw/ppc.c +++ /dev/null @@ -1,1356 +0,0 @@ -/* - * QEMU generic PowerPC hardware System Emulator - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/ppc.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "hw/nvram.h" -#include "qemu/log.h" -#include "hw/loader.h" -#include "sysemu/kvm.h" -#include "kvm_ppc.h" - -//#define PPC_DEBUG_IRQ -//#define PPC_DEBUG_TB - -#ifdef PPC_DEBUG_IRQ -# define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) -#else -# define LOG_IRQ(...) do { } while (0) -#endif - - -#ifdef PPC_DEBUG_TB -# define LOG_TB(...) qemu_log(__VA_ARGS__) -#else -# define LOG_TB(...) do { } while (0) -#endif - -static void cpu_ppc_tb_stop (CPUPPCState *env); -static void cpu_ppc_tb_start (CPUPPCState *env); - -void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) -{ - CPUPPCState *env = &cpu->env; - unsigned int old_pending = env->pending_interrupts; - - if (level) { - env->pending_interrupts |= 1 << n_IRQ; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - env->pending_interrupts &= ~(1 << n_IRQ); - if (env->pending_interrupts == 0) - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } - - if (old_pending != env->pending_interrupts) { -#ifdef CONFIG_KVM - kvmppc_set_interrupt(cpu, n_IRQ, level); -#endif - } - - LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32 - "req %08x\n", __func__, env, n_IRQ, level, - env->pending_interrupts, env->interrupt_request); -} - -/* PowerPC 6xx / 7xx internal IRQ controller */ -static void ppc6xx_set_irq(void *opaque, int pin, int level) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - int cur_level; - - LOG_IRQ("%s: env %p pin %d level %d\n", __func__, - env, pin, level); - cur_level = (env->irq_input_state >> pin) & 1; - /* Don't generate spurious events */ - if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { - switch (pin) { - case PPC6xx_INPUT_TBEN: - /* Level sensitive - active high */ - LOG_IRQ("%s: %s the time base\n", - __func__, level ? "start" : "stop"); - if (level) { - cpu_ppc_tb_start(env); - } else { - cpu_ppc_tb_stop(env); - } - case PPC6xx_INPUT_INT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the external IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); - break; - case PPC6xx_INPUT_SMI: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the SMI IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); - break; - case PPC6xx_INPUT_MCP: - /* Negative edge sensitive */ - /* XXX: TODO: actual reaction may depends on HID0 status - * 603/604/740/750: check HID0[EMCP] - */ - if (cur_level == 1 && level == 0) { - LOG_IRQ("%s: raise machine check state\n", - __func__); - ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); - } - break; - case PPC6xx_INPUT_CKSTP_IN: - /* Level sensitive - active low */ - /* XXX: TODO: relay the signal to CKSTP_OUT pin */ - /* XXX: Note that the only way to restart the CPU is to reset it */ - if (level) { - LOG_IRQ("%s: stop the CPU\n", __func__); - env->halted = 1; - } - break; - case PPC6xx_INPUT_HRESET: - /* Level sensitive - active low */ - if (level) { - LOG_IRQ("%s: reset the CPU\n", __func__); - cpu_interrupt(env, CPU_INTERRUPT_RESET); - } - break; - case PPC6xx_INPUT_SRESET: - LOG_IRQ("%s: set the RESET IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); - break; - default: - /* Unknown pin - do nothing */ - LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); - return; - } - if (level) - env->irq_input_state |= 1 << pin; - else - env->irq_input_state &= ~(1 << pin); - } -} - -void ppc6xx_irq_init(CPUPPCState *env) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, - PPC6xx_INPUT_NB); -} - -#if defined(TARGET_PPC64) -/* PowerPC 970 internal IRQ controller */ -static void ppc970_set_irq(void *opaque, int pin, int level) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - int cur_level; - - LOG_IRQ("%s: env %p pin %d level %d\n", __func__, - env, pin, level); - cur_level = (env->irq_input_state >> pin) & 1; - /* Don't generate spurious events */ - if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { - switch (pin) { - case PPC970_INPUT_INT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the external IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); - break; - case PPC970_INPUT_THINT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, - level); - ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); - break; - case PPC970_INPUT_MCP: - /* Negative edge sensitive */ - /* XXX: TODO: actual reaction may depends on HID0 status - * 603/604/740/750: check HID0[EMCP] - */ - if (cur_level == 1 && level == 0) { - LOG_IRQ("%s: raise machine check state\n", - __func__); - ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); - } - break; - case PPC970_INPUT_CKSTP: - /* Level sensitive - active low */ - /* XXX: TODO: relay the signal to CKSTP_OUT pin */ - if (level) { - LOG_IRQ("%s: stop the CPU\n", __func__); - env->halted = 1; - } else { - LOG_IRQ("%s: restart the CPU\n", __func__); - env->halted = 0; - qemu_cpu_kick(CPU(cpu)); - } - break; - case PPC970_INPUT_HRESET: - /* Level sensitive - active low */ - if (level) { - cpu_interrupt(env, CPU_INTERRUPT_RESET); - } - break; - case PPC970_INPUT_SRESET: - LOG_IRQ("%s: set the RESET IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); - break; - case PPC970_INPUT_TBEN: - LOG_IRQ("%s: set the TBEN state to %d\n", __func__, - level); - /* XXX: TODO */ - break; - default: - /* Unknown pin - do nothing */ - LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); - return; - } - if (level) - env->irq_input_state |= 1 << pin; - else - env->irq_input_state &= ~(1 << pin); - } -} - -void ppc970_irq_init(CPUPPCState *env) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, - PPC970_INPUT_NB); -} - -/* POWER7 internal IRQ controller */ -static void power7_set_irq(void *opaque, int pin, int level) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - - LOG_IRQ("%s: env %p pin %d level %d\n", __func__, - env, pin, level); - - switch (pin) { - case POWER7_INPUT_INT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the external IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); - break; - default: - /* Unknown pin - do nothing */ - LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); - return; - } - if (level) { - env->irq_input_state |= 1 << pin; - } else { - env->irq_input_state &= ~(1 << pin); - } -} - -void ppcPOWER7_irq_init(CPUPPCState *env) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, - POWER7_INPUT_NB); -} -#endif /* defined(TARGET_PPC64) */ - -/* PowerPC 40x internal IRQ controller */ -static void ppc40x_set_irq(void *opaque, int pin, int level) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - int cur_level; - - LOG_IRQ("%s: env %p pin %d level %d\n", __func__, - env, pin, level); - cur_level = (env->irq_input_state >> pin) & 1; - /* Don't generate spurious events */ - if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { - switch (pin) { - case PPC40x_INPUT_RESET_SYS: - if (level) { - LOG_IRQ("%s: reset the PowerPC system\n", - __func__); - ppc40x_system_reset(cpu); - } - break; - case PPC40x_INPUT_RESET_CHIP: - if (level) { - LOG_IRQ("%s: reset the PowerPC chip\n", __func__); - ppc40x_chip_reset(cpu); - } - break; - case PPC40x_INPUT_RESET_CORE: - /* XXX: TODO: update DBSR[MRR] */ - if (level) { - LOG_IRQ("%s: reset the PowerPC core\n", __func__); - ppc40x_core_reset(cpu); - } - break; - case PPC40x_INPUT_CINT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the critical IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); - break; - case PPC40x_INPUT_INT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the external IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); - break; - case PPC40x_INPUT_HALT: - /* Level sensitive - active low */ - if (level) { - LOG_IRQ("%s: stop the CPU\n", __func__); - env->halted = 1; - } else { - LOG_IRQ("%s: restart the CPU\n", __func__); - env->halted = 0; - qemu_cpu_kick(CPU(cpu)); - } - break; - case PPC40x_INPUT_DEBUG: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the debug pin state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); - break; - default: - /* Unknown pin - do nothing */ - LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); - return; - } - if (level) - env->irq_input_state |= 1 << pin; - else - env->irq_input_state &= ~(1 << pin); - } -} - -void ppc40x_irq_init(CPUPPCState *env) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, - cpu, PPC40x_INPUT_NB); -} - -/* PowerPC E500 internal IRQ controller */ -static void ppce500_set_irq(void *opaque, int pin, int level) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - int cur_level; - - LOG_IRQ("%s: env %p pin %d level %d\n", __func__, - env, pin, level); - cur_level = (env->irq_input_state >> pin) & 1; - /* Don't generate spurious events */ - if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { - switch (pin) { - case PPCE500_INPUT_MCK: - if (level) { - LOG_IRQ("%s: reset the PowerPC system\n", - __func__); - qemu_system_reset_request(); - } - break; - case PPCE500_INPUT_RESET_CORE: - if (level) { - LOG_IRQ("%s: reset the PowerPC core\n", __func__); - ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); - } - break; - case PPCE500_INPUT_CINT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the critical IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); - break; - case PPCE500_INPUT_INT: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the core IRQ state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); - break; - case PPCE500_INPUT_DEBUG: - /* Level sensitive - active high */ - LOG_IRQ("%s: set the debug pin state to %d\n", - __func__, level); - ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); - break; - default: - /* Unknown pin - do nothing */ - LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); - return; - } - if (level) - env->irq_input_state |= 1 << pin; - else - env->irq_input_state &= ~(1 << pin); - } -} - -void ppce500_irq_init(CPUPPCState *env) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, - cpu, PPCE500_INPUT_NB); -} - -/* Enable or Disable the E500 EPR capability */ -void ppce500_set_mpic_proxy(bool enabled) -{ - CPUPPCState *env; - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); - CPUState *cs = CPU(cpu); - - env->mpic_proxy = enabled; - if (kvm_enabled()) { - kvmppc_set_mpic_proxy(POWERPC_CPU(cs), enabled); - } - } -} - -/*****************************************************************************/ -/* PowerPC time base and decrementer emulation */ - -uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) -{ - /* TB time in tb periods */ - return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset; -} - -uint64_t cpu_ppc_load_tbl (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - if (kvm_enabled()) { - return env->spr[SPR_TBL]; - } - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); - LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); - - return tb; -} - -static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); - LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); - - return tb >> 32; -} - -uint32_t cpu_ppc_load_tbu (CPUPPCState *env) -{ - if (kvm_enabled()) { - return env->spr[SPR_TBU]; - } - - return _cpu_ppc_load_tbu(env); -} - -static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, - int64_t *tb_offsetp, uint64_t value) -{ - *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()); - LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n", - __func__, value, *tb_offsetp); -} - -void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); - tb &= 0xFFFFFFFF00000000ULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), - &tb_env->tb_offset, tb | (uint64_t)value); -} - -static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); - tb &= 0x00000000FFFFFFFFULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), - &tb_env->tb_offset, ((uint64_t)value << 32) | tb); -} - -void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) -{ - _cpu_ppc_store_tbu(env, value); -} - -uint64_t cpu_ppc_load_atbl (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); - LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); - - return tb; -} - -uint32_t cpu_ppc_load_atbu (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); - LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); - - return tb >> 32; -} - -void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); - tb &= 0xFFFFFFFF00000000ULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), - &tb_env->atb_offset, tb | (uint64_t)value); -} - -void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); - tb &= 0x00000000FFFFFFFFULL; - cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), - &tb_env->atb_offset, ((uint64_t)value << 32) | tb); -} - -static void cpu_ppc_tb_stop (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb, atb, vmclk; - - /* If the time base is already frozen, do nothing */ - if (tb_env->tb_freq != 0) { - vmclk = qemu_get_clock_ns(vm_clock); - /* Get the time base */ - tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); - /* Get the alternate time base */ - atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); - /* Store the time base value (ie compute the current offset) */ - cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); - /* Store the alternate time base value (compute the current offset) */ - cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); - /* Set the time base frequency to zero */ - tb_env->tb_freq = 0; - /* Now, the time bases are frozen to tb_offset / atb_offset value */ - } -} - -static void cpu_ppc_tb_start (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb, atb, vmclk; - - /* If the time base is not frozen, do nothing */ - if (tb_env->tb_freq == 0) { - vmclk = qemu_get_clock_ns(vm_clock); - /* Get the time base from tb_offset */ - tb = tb_env->tb_offset; - /* Get the alternate time base from atb_offset */ - atb = tb_env->atb_offset; - /* Restore the tb frequency from the decrementer frequency */ - tb_env->tb_freq = tb_env->decr_freq; - /* Store the time base value */ - cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); - /* Store the alternate time base value */ - cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); - } -} - -static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) -{ - ppc_tb_t *tb_env = env->tb_env; - uint32_t decr; - int64_t diff; - - diff = next - qemu_get_clock_ns(vm_clock); - if (diff >= 0) { - decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec()); - } else if (tb_env->flags & PPC_TIMER_BOOKE) { - decr = 0; - } else { - decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec()); - } - LOG_TB("%s: %08" PRIx32 "\n", __func__, decr); - - return decr; -} - -uint32_t cpu_ppc_load_decr (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - - if (kvm_enabled()) { - return env->spr[SPR_DECR]; - } - - return _cpu_ppc_load_decr(env, tb_env->decr_next); -} - -uint32_t cpu_ppc_load_hdecr (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - - return _cpu_ppc_load_decr(env, tb_env->hdecr_next); -} - -uint64_t cpu_ppc_load_purr (CPUPPCState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t diff; - - diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start; - - return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec()); -} - -/* When decrementer expires, - * all we need to do is generate or queue a CPU exception - */ -static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) -{ - /* Raise it */ - LOG_TB("raise decrementer exception\n"); - ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); -} - -static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) -{ - /* Raise it */ - LOG_TB("raise decrementer exception\n"); - ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); -} - -static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, - struct QEMUTimer *timer, - void (*raise_excp)(PowerPCCPU *), - uint32_t decr, uint32_t value, - int is_excp) -{ - CPUPPCState *env = &cpu->env; - ppc_tb_t *tb_env = env->tb_env; - uint64_t now, next; - - LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__, - decr, value); - - if (kvm_enabled()) { - /* KVM handles decrementer exceptions, we don't need our own timer */ - return; - } - - now = qemu_get_clock_ns(vm_clock); - next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq); - if (is_excp) { - next += *nextp - now; - } - if (next == now) { - next++; - } - *nextp = next; - /* Adjust timer */ - qemu_mod_timer(timer, next); - - /* If we set a negative value and the decrementer was positive, raise an - * exception. - */ - if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) - && (value & 0x80000000) - && !(decr & 0x80000000)) { - (*raise_excp)(cpu); - } -} - -static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr, - uint32_t value, int is_excp) -{ - ppc_tb_t *tb_env = cpu->env.tb_env; - - __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, - &cpu_ppc_decr_excp, decr, value, is_excp); -} - -void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0); -} - -static void cpu_ppc_decr_cb(void *opaque) -{ - PowerPCCPU *cpu = opaque; - - _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1); -} - -static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr, - uint32_t value, int is_excp) -{ - ppc_tb_t *tb_env = cpu->env.tb_env; - - if (tb_env->hdecr_timer != NULL) { - __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, - &cpu_ppc_hdecr_excp, hdecr, value, is_excp); - } -} - -void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0); -} - -static void cpu_ppc_hdecr_cb(void *opaque) -{ - PowerPCCPU *cpu = opaque; - - _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1); -} - -static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) -{ - ppc_tb_t *tb_env = cpu->env.tb_env; - - tb_env->purr_load = value; - tb_env->purr_start = qemu_get_clock_ns(vm_clock); -} - -static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) -{ - CPUPPCState *env = opaque; - PowerPCCPU *cpu = ppc_env_get_cpu(env); - ppc_tb_t *tb_env = env->tb_env; - - tb_env->tb_freq = freq; - tb_env->decr_freq = freq; - /* There is a bug in Linux 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee at startup, - * it's not ready to handle it... - */ - _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); - _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); - cpu_ppc_store_purr(cpu, 0x0000000000000000ULL); -} - -/* Set up (once) timebase frequency (in Hz) */ -clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - ppc_tb_t *tb_env; - - tb_env = g_malloc0(sizeof(ppc_tb_t)); - env->tb_env = tb_env; - tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; - /* Create new timer */ - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu); - if (0) { - /* XXX: find a suitable condition to enable the hypervisor decrementer - */ - tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, - cpu); - } else { - tb_env->hdecr_timer = NULL; - } - cpu_ppc_set_tb_clk(env, freq); - - return &cpu_ppc_set_tb_clk; -} - -/* Specific helpers for POWER & PowerPC 601 RTC */ -#if 0 -static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env) -{ - return cpu_ppc_tb_init(env, 7812500); -} -#endif - -void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value) -{ - _cpu_ppc_store_tbu(env, value); -} - -uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env) -{ - return _cpu_ppc_load_tbu(env); -} - -void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value) -{ - cpu_ppc_store_tbl(env, value & 0x3FFFFF80); -} - -uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env) -{ - return cpu_ppc_load_tbl(env) & 0x3FFFFF80; -} - -/*****************************************************************************/ -/* PowerPC 40x timers */ - -/* PIT, FIT & WDT */ -typedef struct ppc40x_timer_t ppc40x_timer_t; -struct ppc40x_timer_t { - uint64_t pit_reload; /* PIT auto-reload value */ - uint64_t fit_next; /* Tick for next FIT interrupt */ - struct QEMUTimer *fit_timer; - uint64_t wdt_next; /* Tick for next WDT interrupt */ - struct QEMUTimer *wdt_timer; - - /* 405 have the PIT, 440 have a DECR. */ - unsigned int decr_excp; -}; - -/* Fixed interval timer */ -static void cpu_4xx_fit_cb (void *opaque) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - ppc_tb_t *tb_env; - ppc40x_timer_t *ppc40x_timer; - uint64_t now, next; - - env = opaque; - cpu = ppc_env_get_cpu(env); - tb_env = env->tb_env; - ppc40x_timer = tb_env->opaque; - now = qemu_get_clock_ns(vm_clock); - switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { - case 0: - next = 1 << 9; - break; - case 1: - next = 1 << 13; - break; - case 2: - next = 1 << 17; - break; - case 3: - next = 1 << 21; - break; - default: - /* Cannot occur, but makes gcc happy */ - return; - } - next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq); - if (next == now) - next++; - qemu_mod_timer(ppc40x_timer->fit_timer, next); - env->spr[SPR_40x_TSR] |= 1 << 26; - if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { - ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); - } - LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, - (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), - env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); -} - -/* Programmable interval timer */ -static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) -{ - ppc40x_timer_t *ppc40x_timer; - uint64_t now, next; - - ppc40x_timer = tb_env->opaque; - if (ppc40x_timer->pit_reload <= 1 || - !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || - (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { - /* Stop PIT */ - LOG_TB("%s: stop PIT\n", __func__); - qemu_del_timer(tb_env->decr_timer); - } else { - LOG_TB("%s: start PIT %016" PRIx64 "\n", - __func__, ppc40x_timer->pit_reload); - now = qemu_get_clock_ns(vm_clock); - next = now + muldiv64(ppc40x_timer->pit_reload, - get_ticks_per_sec(), tb_env->decr_freq); - if (is_excp) - next += tb_env->decr_next - now; - if (next == now) - next++; - qemu_mod_timer(tb_env->decr_timer, next); - tb_env->decr_next = next; - } -} - -static void cpu_4xx_pit_cb (void *opaque) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - ppc_tb_t *tb_env; - ppc40x_timer_t *ppc40x_timer; - - env = opaque; - cpu = ppc_env_get_cpu(env); - tb_env = env->tb_env; - ppc40x_timer = tb_env->opaque; - env->spr[SPR_40x_TSR] |= 1 << 27; - if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { - ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); - } - start_stop_pit(env, tb_env, 1); - LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " - "%016" PRIx64 "\n", __func__, - (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), - (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), - env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], - ppc40x_timer->pit_reload); -} - -/* Watchdog timer */ -static void cpu_4xx_wdt_cb (void *opaque) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - ppc_tb_t *tb_env; - ppc40x_timer_t *ppc40x_timer; - uint64_t now, next; - - env = opaque; - cpu = ppc_env_get_cpu(env); - tb_env = env->tb_env; - ppc40x_timer = tb_env->opaque; - now = qemu_get_clock_ns(vm_clock); - switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { - case 0: - next = 1 << 17; - break; - case 1: - next = 1 << 21; - break; - case 2: - next = 1 << 25; - break; - case 3: - next = 1 << 29; - break; - default: - /* Cannot occur, but makes gcc happy */ - return; - } - next = now + muldiv64(next, get_ticks_per_sec(), tb_env->decr_freq); - if (next == now) - next++; - LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, - env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); - switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { - case 0x0: - case 0x1: - qemu_mod_timer(ppc40x_timer->wdt_timer, next); - ppc40x_timer->wdt_next = next; - env->spr[SPR_40x_TSR] |= 1 << 31; - break; - case 0x2: - qemu_mod_timer(ppc40x_timer->wdt_timer, next); - ppc40x_timer->wdt_next = next; - env->spr[SPR_40x_TSR] |= 1 << 30; - if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { - ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); - } - break; - case 0x3: - env->spr[SPR_40x_TSR] &= ~0x30000000; - env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; - switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { - case 0x0: - /* No reset */ - break; - case 0x1: /* Core reset */ - ppc40x_core_reset(cpu); - break; - case 0x2: /* Chip reset */ - ppc40x_chip_reset(cpu); - break; - case 0x3: /* System reset */ - ppc40x_system_reset(cpu); - break; - } - } -} - -void store_40x_pit (CPUPPCState *env, target_ulong val) -{ - ppc_tb_t *tb_env; - ppc40x_timer_t *ppc40x_timer; - - tb_env = env->tb_env; - ppc40x_timer = tb_env->opaque; - LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val); - ppc40x_timer->pit_reload = val; - start_stop_pit(env, tb_env, 0); -} - -target_ulong load_40x_pit (CPUPPCState *env) -{ - return cpu_ppc_load_decr(env); -} - -static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) -{ - CPUPPCState *env = opaque; - ppc_tb_t *tb_env = env->tb_env; - - LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__, - freq); - tb_env->tb_freq = freq; - tb_env->decr_freq = freq; - /* XXX: we should also update all timers */ -} - -clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, - unsigned int decr_excp) -{ - ppc_tb_t *tb_env; - ppc40x_timer_t *ppc40x_timer; - - tb_env = g_malloc0(sizeof(ppc_tb_t)); - env->tb_env = tb_env; - tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; - ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t)); - tb_env->tb_freq = freq; - tb_env->decr_freq = freq; - tb_env->opaque = ppc40x_timer; - LOG_TB("%s freq %" PRIu32 "\n", __func__, freq); - if (ppc40x_timer != NULL) { - /* We use decr timer for PIT */ - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env); - ppc40x_timer->fit_timer = - qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env); - ppc40x_timer->wdt_timer = - qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env); - ppc40x_timer->decr_excp = decr_excp; - } - - return &ppc_40x_set_tb_clk; -} - -/*****************************************************************************/ -/* Embedded PowerPC Device Control Registers */ -typedef struct ppc_dcrn_t ppc_dcrn_t; -struct ppc_dcrn_t { - dcr_read_cb dcr_read; - dcr_write_cb dcr_write; - void *opaque; -}; - -/* XXX: on 460, DCR addresses are 32 bits wide, - * using DCRIPR to get the 22 upper bits of the DCR address - */ -#define DCRN_NB 1024 -struct ppc_dcr_t { - ppc_dcrn_t dcrn[DCRN_NB]; - int (*read_error)(int dcrn); - int (*write_error)(int dcrn); -}; - -int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) -{ - ppc_dcrn_t *dcr; - - if (dcrn < 0 || dcrn >= DCRN_NB) - goto error; - dcr = &dcr_env->dcrn[dcrn]; - if (dcr->dcr_read == NULL) - goto error; - *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); - - return 0; - - error: - if (dcr_env->read_error != NULL) - return (*dcr_env->read_error)(dcrn); - - return -1; -} - -int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) -{ - ppc_dcrn_t *dcr; - - if (dcrn < 0 || dcrn >= DCRN_NB) - goto error; - dcr = &dcr_env->dcrn[dcrn]; - if (dcr->dcr_write == NULL) - goto error; - (*dcr->dcr_write)(dcr->opaque, dcrn, val); - - return 0; - - error: - if (dcr_env->write_error != NULL) - return (*dcr_env->write_error)(dcrn); - - return -1; -} - -int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, - dcr_read_cb dcr_read, dcr_write_cb dcr_write) -{ - ppc_dcr_t *dcr_env; - ppc_dcrn_t *dcr; - - dcr_env = env->dcr_env; - if (dcr_env == NULL) - return -1; - if (dcrn < 0 || dcrn >= DCRN_NB) - return -1; - dcr = &dcr_env->dcrn[dcrn]; - if (dcr->opaque != NULL || - dcr->dcr_read != NULL || - dcr->dcr_write != NULL) - return -1; - dcr->opaque = opaque; - dcr->dcr_read = dcr_read; - dcr->dcr_write = dcr_write; - - return 0; -} - -int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), - int (*write_error)(int dcrn)) -{ - ppc_dcr_t *dcr_env; - - dcr_env = g_malloc0(sizeof(ppc_dcr_t)); - dcr_env->read_error = read_error; - dcr_env->write_error = write_error; - env->dcr_env = dcr_env; - - return 0; -} - -/*****************************************************************************/ -/* Debug port */ -void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) -{ - addr &= 0xF; - switch (addr) { - case 0: - printf("%c", val); - break; - case 1: - printf("\n"); - fflush(stdout); - break; - case 2: - printf("Set loglevel to %04" PRIx32 "\n", val); - qemu_set_log(val | 0x100); - break; - } -} - -/*****************************************************************************/ -/* NVRAM helpers */ -static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr) -{ - return (*nvram->read_fn)(nvram->opaque, addr); -} - -static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val) -{ - (*nvram->write_fn)(nvram->opaque, addr, val); -} - -static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value) -{ - nvram_write(nvram, addr, value); -} - -static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr) -{ - return nvram_read(nvram, addr); -} - -static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value) -{ - nvram_write(nvram, addr, value >> 8); - nvram_write(nvram, addr + 1, value & 0xFF); -} - -static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr) -{ - uint16_t tmp; - - tmp = nvram_read(nvram, addr) << 8; - tmp |= nvram_read(nvram, addr + 1); - - return tmp; -} - -static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value) -{ - nvram_write(nvram, addr, value >> 24); - nvram_write(nvram, addr + 1, (value >> 16) & 0xFF); - nvram_write(nvram, addr + 2, (value >> 8) & 0xFF); - nvram_write(nvram, addr + 3, value & 0xFF); -} - -uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr) -{ - uint32_t tmp; - - tmp = nvram_read(nvram, addr) << 24; - tmp |= nvram_read(nvram, addr + 1) << 16; - tmp |= nvram_read(nvram, addr + 2) << 8; - tmp |= nvram_read(nvram, addr + 3); - - return tmp; -} - -static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str, - uint32_t max) -{ - int i; - - for (i = 0; i < max && str[i] != '\0'; i++) { - nvram_write(nvram, addr + i, str[i]); - } - nvram_write(nvram, addr + i, str[i]); - nvram_write(nvram, addr + max - 1, '\0'); -} - -int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max) -{ - int i; - - memset(dst, 0, max); - for (i = 0; i < max; i++) { - dst[i] = NVRAM_get_byte(nvram, addr + i); - if (dst[i] == '\0') - break; - } - - return i; -} - -static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) -{ - uint16_t tmp; - uint16_t pd, pd1, pd2; - - tmp = prev >> 8; - pd = prev ^ value; - pd1 = pd & 0x000F; - pd2 = ((pd >> 4) & 0x000F) ^ pd1; - tmp ^= (pd1 << 3) | (pd1 << 8); - tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); - - return tmp; -} - -static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count) -{ - uint32_t i; - uint16_t crc = 0xFFFF; - int odd; - - odd = count & 1; - count &= ~1; - for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); - } - if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); - } - - return crc; -} - -#define CMDLINE_ADDR 0x017ff000 - -int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, - const char *arch, - uint32_t RAM_size, int boot_device, - uint32_t kernel_image, uint32_t kernel_size, - const char *cmdline, - uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image, - int width, int height, int depth) -{ - uint16_t crc; - - /* Set parameters for Open Hack'Ware BIOS */ - NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); - NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ - NVRAM_set_word(nvram, 0x14, NVRAM_size); - NVRAM_set_string(nvram, 0x20, arch, 16); - NVRAM_set_lword(nvram, 0x30, RAM_size); - NVRAM_set_byte(nvram, 0x34, boot_device); - NVRAM_set_lword(nvram, 0x38, kernel_image); - NVRAM_set_lword(nvram, 0x3C, kernel_size); - if (cmdline) { - /* XXX: put the cmdline in NVRAM too ? */ - pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline); - NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); - NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); - } else { - NVRAM_set_lword(nvram, 0x40, 0); - NVRAM_set_lword(nvram, 0x44, 0); - } - NVRAM_set_lword(nvram, 0x48, initrd_image); - NVRAM_set_lword(nvram, 0x4C, initrd_size); - NVRAM_set_lword(nvram, 0x50, NVRAM_image); - - NVRAM_set_word(nvram, 0x54, width); - NVRAM_set_word(nvram, 0x56, height); - NVRAM_set_word(nvram, 0x58, depth); - crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); - NVRAM_set_word(nvram, 0xFC, crc); - - return 0; -} diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 9141373f40..294d0de211 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,19 +1,14 @@ -# shared objects -obj-y = ppc.o ppc_booke.o # PREP target obj-y += mc146818rtc.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o +obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o # PowerPC 4xx boards -obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o -obj-y += ppc440_bamboo.o +obj-y += ppc4xx_devs.o ppc4xx_pci.o # PowerPC E500 boards obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o -# PowerPC 440 Xilinx ML507 reference board. -obj-y += virtex_ml507.o # PowerPC OpenPIC obj-y += openpic.o @@ -22,6 +17,12 @@ obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) +# shared objects +obj-y += ppc.o ppc_booke.o +# IBM pSeries (sPAPR) +obj-$(CONFIG_PSERIES) += spapr.o +# PowerPC 4xx boards +obj-y += ppc405_boards.o ppc405_uc.o ppc440_bamboo.o # PReP obj-y += prep.o # OldWorld PowerMac @@ -30,3 +31,5 @@ obj-y += mac_oldworld.o obj-y += mac_newworld.o # e500 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o +# PowerPC 440 Xilinx ML507 reference board. +obj-y += virtex_ml507.o diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c new file mode 100644 index 0000000000..c9437fc6a7 --- /dev/null +++ b/hw/ppc/ppc.c @@ -0,0 +1,1356 @@ +/* + * QEMU generic PowerPC hardware System Emulator + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/ppc.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "hw/nvram.h" +#include "qemu/log.h" +#include "hw/loader.h" +#include "sysemu/kvm.h" +#include "kvm_ppc.h" + +//#define PPC_DEBUG_IRQ +//#define PPC_DEBUG_TB + +#ifdef PPC_DEBUG_IRQ +# define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) +#else +# define LOG_IRQ(...) do { } while (0) +#endif + + +#ifdef PPC_DEBUG_TB +# define LOG_TB(...) qemu_log(__VA_ARGS__) +#else +# define LOG_TB(...) do { } while (0) +#endif + +static void cpu_ppc_tb_stop (CPUPPCState *env); +static void cpu_ppc_tb_start (CPUPPCState *env); + +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) +{ + CPUPPCState *env = &cpu->env; + unsigned int old_pending = env->pending_interrupts; + + if (level) { + env->pending_interrupts |= 1 << n_IRQ; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + env->pending_interrupts &= ~(1 << n_IRQ); + if (env->pending_interrupts == 0) + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } + + if (old_pending != env->pending_interrupts) { +#ifdef CONFIG_KVM + kvmppc_set_interrupt(cpu, n_IRQ, level); +#endif + } + + LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32 + "req %08x\n", __func__, env, n_IRQ, level, + env->pending_interrupts, env->interrupt_request); +} + +/* PowerPC 6xx / 7xx internal IRQ controller */ +static void ppc6xx_set_irq(void *opaque, int pin, int level) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int cur_level; + + LOG_IRQ("%s: env %p pin %d level %d\n", __func__, + env, pin, level); + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + switch (pin) { + case PPC6xx_INPUT_TBEN: + /* Level sensitive - active high */ + LOG_IRQ("%s: %s the time base\n", + __func__, level ? "start" : "stop"); + if (level) { + cpu_ppc_tb_start(env); + } else { + cpu_ppc_tb_stop(env); + } + case PPC6xx_INPUT_INT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the external IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); + break; + case PPC6xx_INPUT_SMI: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the SMI IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); + break; + case PPC6xx_INPUT_MCP: + /* Negative edge sensitive */ + /* XXX: TODO: actual reaction may depends on HID0 status + * 603/604/740/750: check HID0[EMCP] + */ + if (cur_level == 1 && level == 0) { + LOG_IRQ("%s: raise machine check state\n", + __func__); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); + } + break; + case PPC6xx_INPUT_CKSTP_IN: + /* Level sensitive - active low */ + /* XXX: TODO: relay the signal to CKSTP_OUT pin */ + /* XXX: Note that the only way to restart the CPU is to reset it */ + if (level) { + LOG_IRQ("%s: stop the CPU\n", __func__); + env->halted = 1; + } + break; + case PPC6xx_INPUT_HRESET: + /* Level sensitive - active low */ + if (level) { + LOG_IRQ("%s: reset the CPU\n", __func__); + cpu_interrupt(env, CPU_INTERRUPT_RESET); + } + break; + case PPC6xx_INPUT_SRESET: + LOG_IRQ("%s: set the RESET IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); + break; + default: + /* Unknown pin - do nothing */ + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); + } +} + +void ppc6xx_irq_init(CPUPPCState *env) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, + PPC6xx_INPUT_NB); +} + +#if defined(TARGET_PPC64) +/* PowerPC 970 internal IRQ controller */ +static void ppc970_set_irq(void *opaque, int pin, int level) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int cur_level; + + LOG_IRQ("%s: env %p pin %d level %d\n", __func__, + env, pin, level); + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + switch (pin) { + case PPC970_INPUT_INT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the external IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); + break; + case PPC970_INPUT_THINT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, + level); + ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); + break; + case PPC970_INPUT_MCP: + /* Negative edge sensitive */ + /* XXX: TODO: actual reaction may depends on HID0 status + * 603/604/740/750: check HID0[EMCP] + */ + if (cur_level == 1 && level == 0) { + LOG_IRQ("%s: raise machine check state\n", + __func__); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); + } + break; + case PPC970_INPUT_CKSTP: + /* Level sensitive - active low */ + /* XXX: TODO: relay the signal to CKSTP_OUT pin */ + if (level) { + LOG_IRQ("%s: stop the CPU\n", __func__); + env->halted = 1; + } else { + LOG_IRQ("%s: restart the CPU\n", __func__); + env->halted = 0; + qemu_cpu_kick(CPU(cpu)); + } + break; + case PPC970_INPUT_HRESET: + /* Level sensitive - active low */ + if (level) { + cpu_interrupt(env, CPU_INTERRUPT_RESET); + } + break; + case PPC970_INPUT_SRESET: + LOG_IRQ("%s: set the RESET IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); + break; + case PPC970_INPUT_TBEN: + LOG_IRQ("%s: set the TBEN state to %d\n", __func__, + level); + /* XXX: TODO */ + break; + default: + /* Unknown pin - do nothing */ + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); + } +} + +void ppc970_irq_init(CPUPPCState *env) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, + PPC970_INPUT_NB); +} + +/* POWER7 internal IRQ controller */ +static void power7_set_irq(void *opaque, int pin, int level) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + LOG_IRQ("%s: env %p pin %d level %d\n", __func__, + env, pin, level); + + switch (pin) { + case POWER7_INPUT_INT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the external IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); + break; + default: + /* Unknown pin - do nothing */ + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); + return; + } + if (level) { + env->irq_input_state |= 1 << pin; + } else { + env->irq_input_state &= ~(1 << pin); + } +} + +void ppcPOWER7_irq_init(CPUPPCState *env) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, + POWER7_INPUT_NB); +} +#endif /* defined(TARGET_PPC64) */ + +/* PowerPC 40x internal IRQ controller */ +static void ppc40x_set_irq(void *opaque, int pin, int level) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int cur_level; + + LOG_IRQ("%s: env %p pin %d level %d\n", __func__, + env, pin, level); + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + switch (pin) { + case PPC40x_INPUT_RESET_SYS: + if (level) { + LOG_IRQ("%s: reset the PowerPC system\n", + __func__); + ppc40x_system_reset(cpu); + } + break; + case PPC40x_INPUT_RESET_CHIP: + if (level) { + LOG_IRQ("%s: reset the PowerPC chip\n", __func__); + ppc40x_chip_reset(cpu); + } + break; + case PPC40x_INPUT_RESET_CORE: + /* XXX: TODO: update DBSR[MRR] */ + if (level) { + LOG_IRQ("%s: reset the PowerPC core\n", __func__); + ppc40x_core_reset(cpu); + } + break; + case PPC40x_INPUT_CINT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the critical IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); + break; + case PPC40x_INPUT_INT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the external IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); + break; + case PPC40x_INPUT_HALT: + /* Level sensitive - active low */ + if (level) { + LOG_IRQ("%s: stop the CPU\n", __func__); + env->halted = 1; + } else { + LOG_IRQ("%s: restart the CPU\n", __func__); + env->halted = 0; + qemu_cpu_kick(CPU(cpu)); + } + break; + case PPC40x_INPUT_DEBUG: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the debug pin state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); + break; + default: + /* Unknown pin - do nothing */ + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); + } +} + +void ppc40x_irq_init(CPUPPCState *env) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, + cpu, PPC40x_INPUT_NB); +} + +/* PowerPC E500 internal IRQ controller */ +static void ppce500_set_irq(void *opaque, int pin, int level) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int cur_level; + + LOG_IRQ("%s: env %p pin %d level %d\n", __func__, + env, pin, level); + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + switch (pin) { + case PPCE500_INPUT_MCK: + if (level) { + LOG_IRQ("%s: reset the PowerPC system\n", + __func__); + qemu_system_reset_request(); + } + break; + case PPCE500_INPUT_RESET_CORE: + if (level) { + LOG_IRQ("%s: reset the PowerPC core\n", __func__); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); + } + break; + case PPCE500_INPUT_CINT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the critical IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); + break; + case PPCE500_INPUT_INT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the core IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); + break; + case PPCE500_INPUT_DEBUG: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the debug pin state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); + break; + default: + /* Unknown pin - do nothing */ + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); + } +} + +void ppce500_irq_init(CPUPPCState *env) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, + cpu, PPCE500_INPUT_NB); +} + +/* Enable or Disable the E500 EPR capability */ +void ppce500_set_mpic_proxy(bool enabled) +{ + CPUPPCState *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); + + env->mpic_proxy = enabled; + if (kvm_enabled()) { + kvmppc_set_mpic_proxy(POWERPC_CPU(cs), enabled); + } + } +} + +/*****************************************************************************/ +/* PowerPC time base and decrementer emulation */ + +uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) +{ + /* TB time in tb periods */ + return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset; +} + +uint64_t cpu_ppc_load_tbl (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + if (kvm_enabled()) { + return env->spr[SPR_TBL]; + } + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); + + return tb; +} + +static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); + + return tb >> 32; +} + +uint32_t cpu_ppc_load_tbu (CPUPPCState *env) +{ + if (kvm_enabled()) { + return env->spr[SPR_TBU]; + } + + return _cpu_ppc_load_tbu(env); +} + +static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, + int64_t *tb_offsetp, uint64_t value) +{ + *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()); + LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n", + __func__, value, *tb_offsetp); +} + +void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + tb &= 0xFFFFFFFF00000000ULL; + cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + &tb_env->tb_offset, tb | (uint64_t)value); +} + +static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); + tb &= 0x00000000FFFFFFFFULL; + cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + &tb_env->tb_offset, ((uint64_t)value << 32) | tb); +} + +void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) +{ + _cpu_ppc_store_tbu(env, value); +} + +uint64_t cpu_ppc_load_atbl (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); + + return tb; +} + +uint32_t cpu_ppc_load_atbu (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); + + return tb >> 32; +} + +void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + tb &= 0xFFFFFFFF00000000ULL; + cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + &tb_env->atb_offset, tb | (uint64_t)value); +} + +void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset); + tb &= 0x00000000FFFFFFFFULL; + cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock), + &tb_env->atb_offset, ((uint64_t)value << 32) | tb); +} + +static void cpu_ppc_tb_stop (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb, atb, vmclk; + + /* If the time base is already frozen, do nothing */ + if (tb_env->tb_freq != 0) { + vmclk = qemu_get_clock_ns(vm_clock); + /* Get the time base */ + tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); + /* Get the alternate time base */ + atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); + /* Store the time base value (ie compute the current offset) */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); + /* Store the alternate time base value (compute the current offset) */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); + /* Set the time base frequency to zero */ + tb_env->tb_freq = 0; + /* Now, the time bases are frozen to tb_offset / atb_offset value */ + } +} + +static void cpu_ppc_tb_start (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb, atb, vmclk; + + /* If the time base is not frozen, do nothing */ + if (tb_env->tb_freq == 0) { + vmclk = qemu_get_clock_ns(vm_clock); + /* Get the time base from tb_offset */ + tb = tb_env->tb_offset; + /* Get the alternate time base from atb_offset */ + atb = tb_env->atb_offset; + /* Restore the tb frequency from the decrementer frequency */ + tb_env->tb_freq = tb_env->decr_freq; + /* Store the time base value */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); + /* Store the alternate time base value */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); + } +} + +static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) +{ + ppc_tb_t *tb_env = env->tb_env; + uint32_t decr; + int64_t diff; + + diff = next - qemu_get_clock_ns(vm_clock); + if (diff >= 0) { + decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec()); + } else if (tb_env->flags & PPC_TIMER_BOOKE) { + decr = 0; + } else { + decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec()); + } + LOG_TB("%s: %08" PRIx32 "\n", __func__, decr); + + return decr; +} + +uint32_t cpu_ppc_load_decr (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + + if (kvm_enabled()) { + return env->spr[SPR_DECR]; + } + + return _cpu_ppc_load_decr(env, tb_env->decr_next); +} + +uint32_t cpu_ppc_load_hdecr (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + + return _cpu_ppc_load_decr(env, tb_env->hdecr_next); +} + +uint64_t cpu_ppc_load_purr (CPUPPCState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t diff; + + diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start; + + return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec()); +} + +/* When decrementer expires, + * all we need to do is generate or queue a CPU exception + */ +static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) +{ + /* Raise it */ + LOG_TB("raise decrementer exception\n"); + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); +} + +static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) +{ + /* Raise it */ + LOG_TB("raise decrementer exception\n"); + ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); +} + +static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, + struct QEMUTimer *timer, + void (*raise_excp)(PowerPCCPU *), + uint32_t decr, uint32_t value, + int is_excp) +{ + CPUPPCState *env = &cpu->env; + ppc_tb_t *tb_env = env->tb_env; + uint64_t now, next; + + LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__, + decr, value); + + if (kvm_enabled()) { + /* KVM handles decrementer exceptions, we don't need our own timer */ + return; + } + + now = qemu_get_clock_ns(vm_clock); + next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq); + if (is_excp) { + next += *nextp - now; + } + if (next == now) { + next++; + } + *nextp = next; + /* Adjust timer */ + qemu_mod_timer(timer, next); + + /* If we set a negative value and the decrementer was positive, raise an + * exception. + */ + if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) + && (value & 0x80000000) + && !(decr & 0x80000000)) { + (*raise_excp)(cpu); + } +} + +static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr, + uint32_t value, int is_excp) +{ + ppc_tb_t *tb_env = cpu->env.tb_env; + + __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, + &cpu_ppc_decr_excp, decr, value, is_excp); +} + +void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0); +} + +static void cpu_ppc_decr_cb(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1); +} + +static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr, + uint32_t value, int is_excp) +{ + ppc_tb_t *tb_env = cpu->env.tb_env; + + if (tb_env->hdecr_timer != NULL) { + __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, + &cpu_ppc_hdecr_excp, hdecr, value, is_excp); + } +} + +void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0); +} + +static void cpu_ppc_hdecr_cb(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1); +} + +static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) +{ + ppc_tb_t *tb_env = cpu->env.tb_env; + + tb_env->purr_load = value; + tb_env->purr_start = qemu_get_clock_ns(vm_clock); +} + +static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) +{ + CPUPPCState *env = opaque; + PowerPCCPU *cpu = ppc_env_get_cpu(env); + ppc_tb_t *tb_env = env->tb_env; + + tb_env->tb_freq = freq; + tb_env->decr_freq = freq; + /* There is a bug in Linux 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee at startup, + * it's not ready to handle it... + */ + _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + cpu_ppc_store_purr(cpu, 0x0000000000000000ULL); +} + +/* Set up (once) timebase frequency (in Hz) */ +clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + ppc_tb_t *tb_env; + + tb_env = g_malloc0(sizeof(ppc_tb_t)); + env->tb_env = tb_env; + tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; + /* Create new timer */ + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu); + if (0) { + /* XXX: find a suitable condition to enable the hypervisor decrementer + */ + tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, + cpu); + } else { + tb_env->hdecr_timer = NULL; + } + cpu_ppc_set_tb_clk(env, freq); + + return &cpu_ppc_set_tb_clk; +} + +/* Specific helpers for POWER & PowerPC 601 RTC */ +#if 0 +static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env) +{ + return cpu_ppc_tb_init(env, 7812500); +} +#endif + +void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value) +{ + _cpu_ppc_store_tbu(env, value); +} + +uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env) +{ + return _cpu_ppc_load_tbu(env); +} + +void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value) +{ + cpu_ppc_store_tbl(env, value & 0x3FFFFF80); +} + +uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env) +{ + return cpu_ppc_load_tbl(env) & 0x3FFFFF80; +} + +/*****************************************************************************/ +/* PowerPC 40x timers */ + +/* PIT, FIT & WDT */ +typedef struct ppc40x_timer_t ppc40x_timer_t; +struct ppc40x_timer_t { + uint64_t pit_reload; /* PIT auto-reload value */ + uint64_t fit_next; /* Tick for next FIT interrupt */ + struct QEMUTimer *fit_timer; + uint64_t wdt_next; /* Tick for next WDT interrupt */ + struct QEMUTimer *wdt_timer; + + /* 405 have the PIT, 440 have a DECR. */ + unsigned int decr_excp; +}; + +/* Fixed interval timer */ +static void cpu_4xx_fit_cb (void *opaque) +{ + PowerPCCPU *cpu; + CPUPPCState *env; + ppc_tb_t *tb_env; + ppc40x_timer_t *ppc40x_timer; + uint64_t now, next; + + env = opaque; + cpu = ppc_env_get_cpu(env); + tb_env = env->tb_env; + ppc40x_timer = tb_env->opaque; + now = qemu_get_clock_ns(vm_clock); + switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { + case 0: + next = 1 << 9; + break; + case 1: + next = 1 << 13; + break; + case 2: + next = 1 << 17; + break; + case 3: + next = 1 << 21; + break; + default: + /* Cannot occur, but makes gcc happy */ + return; + } + next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq); + if (next == now) + next++; + qemu_mod_timer(ppc40x_timer->fit_timer, next); + env->spr[SPR_40x_TSR] |= 1 << 26; + if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); + } + LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, + (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), + env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); +} + +/* Programmable interval timer */ +static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) +{ + ppc40x_timer_t *ppc40x_timer; + uint64_t now, next; + + ppc40x_timer = tb_env->opaque; + if (ppc40x_timer->pit_reload <= 1 || + !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || + (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { + /* Stop PIT */ + LOG_TB("%s: stop PIT\n", __func__); + qemu_del_timer(tb_env->decr_timer); + } else { + LOG_TB("%s: start PIT %016" PRIx64 "\n", + __func__, ppc40x_timer->pit_reload); + now = qemu_get_clock_ns(vm_clock); + next = now + muldiv64(ppc40x_timer->pit_reload, + get_ticks_per_sec(), tb_env->decr_freq); + if (is_excp) + next += tb_env->decr_next - now; + if (next == now) + next++; + qemu_mod_timer(tb_env->decr_timer, next); + tb_env->decr_next = next; + } +} + +static void cpu_4xx_pit_cb (void *opaque) +{ + PowerPCCPU *cpu; + CPUPPCState *env; + ppc_tb_t *tb_env; + ppc40x_timer_t *ppc40x_timer; + + env = opaque; + cpu = ppc_env_get_cpu(env); + tb_env = env->tb_env; + ppc40x_timer = tb_env->opaque; + env->spr[SPR_40x_TSR] |= 1 << 27; + if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { + ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); + } + start_stop_pit(env, tb_env, 1); + LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " + "%016" PRIx64 "\n", __func__, + (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), + (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), + env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], + ppc40x_timer->pit_reload); +} + +/* Watchdog timer */ +static void cpu_4xx_wdt_cb (void *opaque) +{ + PowerPCCPU *cpu; + CPUPPCState *env; + ppc_tb_t *tb_env; + ppc40x_timer_t *ppc40x_timer; + uint64_t now, next; + + env = opaque; + cpu = ppc_env_get_cpu(env); + tb_env = env->tb_env; + ppc40x_timer = tb_env->opaque; + now = qemu_get_clock_ns(vm_clock); + switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { + case 0: + next = 1 << 17; + break; + case 1: + next = 1 << 21; + break; + case 2: + next = 1 << 25; + break; + case 3: + next = 1 << 29; + break; + default: + /* Cannot occur, but makes gcc happy */ + return; + } + next = now + muldiv64(next, get_ticks_per_sec(), tb_env->decr_freq); + if (next == now) + next++; + LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, + env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); + switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { + case 0x0: + case 0x1: + qemu_mod_timer(ppc40x_timer->wdt_timer, next); + ppc40x_timer->wdt_next = next; + env->spr[SPR_40x_TSR] |= 1 << 31; + break; + case 0x2: + qemu_mod_timer(ppc40x_timer->wdt_timer, next); + ppc40x_timer->wdt_next = next; + env->spr[SPR_40x_TSR] |= 1 << 30; + if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); + } + break; + case 0x3: + env->spr[SPR_40x_TSR] &= ~0x30000000; + env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; + switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { + case 0x0: + /* No reset */ + break; + case 0x1: /* Core reset */ + ppc40x_core_reset(cpu); + break; + case 0x2: /* Chip reset */ + ppc40x_chip_reset(cpu); + break; + case 0x3: /* System reset */ + ppc40x_system_reset(cpu); + break; + } + } +} + +void store_40x_pit (CPUPPCState *env, target_ulong val) +{ + ppc_tb_t *tb_env; + ppc40x_timer_t *ppc40x_timer; + + tb_env = env->tb_env; + ppc40x_timer = tb_env->opaque; + LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val); + ppc40x_timer->pit_reload = val; + start_stop_pit(env, tb_env, 0); +} + +target_ulong load_40x_pit (CPUPPCState *env) +{ + return cpu_ppc_load_decr(env); +} + +static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) +{ + CPUPPCState *env = opaque; + ppc_tb_t *tb_env = env->tb_env; + + LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__, + freq); + tb_env->tb_freq = freq; + tb_env->decr_freq = freq; + /* XXX: we should also update all timers */ +} + +clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, + unsigned int decr_excp) +{ + ppc_tb_t *tb_env; + ppc40x_timer_t *ppc40x_timer; + + tb_env = g_malloc0(sizeof(ppc_tb_t)); + env->tb_env = tb_env; + tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; + ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t)); + tb_env->tb_freq = freq; + tb_env->decr_freq = freq; + tb_env->opaque = ppc40x_timer; + LOG_TB("%s freq %" PRIu32 "\n", __func__, freq); + if (ppc40x_timer != NULL) { + /* We use decr timer for PIT */ + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env); + ppc40x_timer->fit_timer = + qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env); + ppc40x_timer->wdt_timer = + qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env); + ppc40x_timer->decr_excp = decr_excp; + } + + return &ppc_40x_set_tb_clk; +} + +/*****************************************************************************/ +/* Embedded PowerPC Device Control Registers */ +typedef struct ppc_dcrn_t ppc_dcrn_t; +struct ppc_dcrn_t { + dcr_read_cb dcr_read; + dcr_write_cb dcr_write; + void *opaque; +}; + +/* XXX: on 460, DCR addresses are 32 bits wide, + * using DCRIPR to get the 22 upper bits of the DCR address + */ +#define DCRN_NB 1024 +struct ppc_dcr_t { + ppc_dcrn_t dcrn[DCRN_NB]; + int (*read_error)(int dcrn); + int (*write_error)(int dcrn); +}; + +int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) +{ + ppc_dcrn_t *dcr; + + if (dcrn < 0 || dcrn >= DCRN_NB) + goto error; + dcr = &dcr_env->dcrn[dcrn]; + if (dcr->dcr_read == NULL) + goto error; + *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); + + return 0; + + error: + if (dcr_env->read_error != NULL) + return (*dcr_env->read_error)(dcrn); + + return -1; +} + +int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) +{ + ppc_dcrn_t *dcr; + + if (dcrn < 0 || dcrn >= DCRN_NB) + goto error; + dcr = &dcr_env->dcrn[dcrn]; + if (dcr->dcr_write == NULL) + goto error; + (*dcr->dcr_write)(dcr->opaque, dcrn, val); + + return 0; + + error: + if (dcr_env->write_error != NULL) + return (*dcr_env->write_error)(dcrn); + + return -1; +} + +int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, + dcr_read_cb dcr_read, dcr_write_cb dcr_write) +{ + ppc_dcr_t *dcr_env; + ppc_dcrn_t *dcr; + + dcr_env = env->dcr_env; + if (dcr_env == NULL) + return -1; + if (dcrn < 0 || dcrn >= DCRN_NB) + return -1; + dcr = &dcr_env->dcrn[dcrn]; + if (dcr->opaque != NULL || + dcr->dcr_read != NULL || + dcr->dcr_write != NULL) + return -1; + dcr->opaque = opaque; + dcr->dcr_read = dcr_read; + dcr->dcr_write = dcr_write; + + return 0; +} + +int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), + int (*write_error)(int dcrn)) +{ + ppc_dcr_t *dcr_env; + + dcr_env = g_malloc0(sizeof(ppc_dcr_t)); + dcr_env->read_error = read_error; + dcr_env->write_error = write_error; + env->dcr_env = dcr_env; + + return 0; +} + +/*****************************************************************************/ +/* Debug port */ +void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) +{ + addr &= 0xF; + switch (addr) { + case 0: + printf("%c", val); + break; + case 1: + printf("\n"); + fflush(stdout); + break; + case 2: + printf("Set loglevel to %04" PRIx32 "\n", val); + qemu_set_log(val | 0x100); + break; + } +} + +/*****************************************************************************/ +/* NVRAM helpers */ +static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr) +{ + return (*nvram->read_fn)(nvram->opaque, addr); +} + +static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val) +{ + (*nvram->write_fn)(nvram->opaque, addr, val); +} + +static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value) +{ + nvram_write(nvram, addr, value); +} + +static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr) +{ + return nvram_read(nvram, addr); +} + +static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value) +{ + nvram_write(nvram, addr, value >> 8); + nvram_write(nvram, addr + 1, value & 0xFF); +} + +static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr) +{ + uint16_t tmp; + + tmp = nvram_read(nvram, addr) << 8; + tmp |= nvram_read(nvram, addr + 1); + + return tmp; +} + +static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value) +{ + nvram_write(nvram, addr, value >> 24); + nvram_write(nvram, addr + 1, (value >> 16) & 0xFF); + nvram_write(nvram, addr + 2, (value >> 8) & 0xFF); + nvram_write(nvram, addr + 3, value & 0xFF); +} + +uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr) +{ + uint32_t tmp; + + tmp = nvram_read(nvram, addr) << 24; + tmp |= nvram_read(nvram, addr + 1) << 16; + tmp |= nvram_read(nvram, addr + 2) << 8; + tmp |= nvram_read(nvram, addr + 3); + + return tmp; +} + +static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str, + uint32_t max) +{ + int i; + + for (i = 0; i < max && str[i] != '\0'; i++) { + nvram_write(nvram, addr + i, str[i]); + } + nvram_write(nvram, addr + i, str[i]); + nvram_write(nvram, addr + max - 1, '\0'); +} + +int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max) +{ + int i; + + memset(dst, 0, max); + for (i = 0; i < max; i++) { + dst[i] = NVRAM_get_byte(nvram, addr + i); + if (dst[i] == '\0') + break; + } + + return i; +} + +static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) +{ + uint16_t tmp; + uint16_t pd, pd1, pd2; + + tmp = prev >> 8; + pd = prev ^ value; + pd1 = pd & 0x000F; + pd2 = ((pd >> 4) & 0x000F) ^ pd1; + tmp ^= (pd1 << 3) | (pd1 << 8); + tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); + + return tmp; +} + +static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count) +{ + uint32_t i; + uint16_t crc = 0xFFFF; + int odd; + + odd = count & 1; + count &= ~1; + for (i = 0; i != count; i++) { + crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); + } + if (odd) { + crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); + } + + return crc; +} + +#define CMDLINE_ADDR 0x017ff000 + +int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, + const char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + const char *cmdline, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image, + int width, int height, int depth) +{ + uint16_t crc; + + /* Set parameters for Open Hack'Ware BIOS */ + NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); + NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ + NVRAM_set_word(nvram, 0x14, NVRAM_size); + NVRAM_set_string(nvram, 0x20, arch, 16); + NVRAM_set_lword(nvram, 0x30, RAM_size); + NVRAM_set_byte(nvram, 0x34, boot_device); + NVRAM_set_lword(nvram, 0x38, kernel_image); + NVRAM_set_lword(nvram, 0x3C, kernel_size); + if (cmdline) { + /* XXX: put the cmdline in NVRAM too ? */ + pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline); + NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); + NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); + } else { + NVRAM_set_lword(nvram, 0x40, 0); + NVRAM_set_lword(nvram, 0x44, 0); + } + NVRAM_set_lword(nvram, 0x48, initrd_image); + NVRAM_set_lword(nvram, 0x4C, initrd_size); + NVRAM_set_lword(nvram, 0x50, NVRAM_image); + + NVRAM_set_word(nvram, 0x54, width); + NVRAM_set_word(nvram, 0x56, height); + NVRAM_set_word(nvram, 0x58, depth); + crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); + NVRAM_set_word(nvram, 0xFC, crc); + + return 0; +} diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c new file mode 100644 index 0000000000..ba443cf8ef --- /dev/null +++ b/hw/ppc/ppc405_boards.c @@ -0,0 +1,662 @@ +/* + * QEMU PowerPC 405 evaluation boards emulation + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" +#include "hw/nvram.h" +#include "hw/flash.h" +#include "sysemu/sysemu.h" +#include "block/block.h" +#include "hw/boards.h" +#include "qemu/log.h" +#include "hw/loader.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#define BIOS_FILENAME "ppc405_rom.bin" +#define BIOS_SIZE (2048 * 1024) + +#define KERNEL_LOAD_ADDR 0x00000000 +#define INITRD_LOAD_ADDR 0x01800000 + +#define USE_FLASH_BIOS + +#define DEBUG_BOARD_INIT + +/*****************************************************************************/ +/* PPC405EP reference board (IBM) */ +/* Standalone board with: + * - PowerPC 405EP CPU + * - SDRAM (0x00000000) + * - Flash (0xFFF80000) + * - SRAM (0xFFF00000) + * - NVRAM (0xF0000000) + * - FPGA (0xF0300000) + */ +typedef struct ref405ep_fpga_t ref405ep_fpga_t; +struct ref405ep_fpga_t { + uint8_t reg0; + uint8_t reg1; +}; + +static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr) +{ + ref405ep_fpga_t *fpga; + uint32_t ret; + + fpga = opaque; + switch (addr) { + case 0x0: + ret = fpga->reg0; + break; + case 0x1: + ret = fpga->reg1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void ref405ep_fpga_writeb (void *opaque, + hwaddr addr, uint32_t value) +{ + ref405ep_fpga_t *fpga; + + fpga = opaque; + switch (addr) { + case 0x0: + /* Read only */ + break; + case 0x1: + fpga->reg1 = value; + break; + default: + break; + } +} + +static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr) +{ + uint32_t ret; + + ret = ref405ep_fpga_readb(opaque, addr) << 8; + ret |= ref405ep_fpga_readb(opaque, addr + 1); + + return ret; +} + +static void ref405ep_fpga_writew (void *opaque, + hwaddr addr, uint32_t value) +{ + ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF); + ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF); +} + +static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr) +{ + uint32_t ret; + + ret = ref405ep_fpga_readb(opaque, addr) << 24; + ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16; + ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8; + ret |= ref405ep_fpga_readb(opaque, addr + 3); + + return ret; +} + +static void ref405ep_fpga_writel (void *opaque, + hwaddr addr, uint32_t value) +{ + ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF); + ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF); + ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF); + ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF); +} + +static const MemoryRegionOps ref405ep_fpga_ops = { + .old_mmio = { + .read = { + ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl, + }, + .write = { + ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel, + }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ref405ep_fpga_reset (void *opaque) +{ + ref405ep_fpga_t *fpga; + + fpga = opaque; + fpga->reg0 = 0x00; + fpga->reg1 = 0x0F; +} + +static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base) +{ + ref405ep_fpga_t *fpga; + MemoryRegion *fpga_memory = g_new(MemoryRegion, 1); + + fpga = g_malloc0(sizeof(ref405ep_fpga_t)); + memory_region_init_io(fpga_memory, &ref405ep_fpga_ops, fpga, + "fpga", 0x00000100); + memory_region_add_subregion(sysmem, base, fpga_memory); + qemu_register_reset(&ref405ep_fpga_reset, fpga); +} + +static void ref405ep_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + char *filename; + ppc4xx_bd_info_t bd; + CPUPPCState *env; + qemu_irq *pic; + MemoryRegion *bios; + MemoryRegion *sram = g_new(MemoryRegion, 1); + ram_addr_t bdloc; + MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories)); + hwaddr ram_bases[2], ram_sizes[2]; + target_ulong sram_size; + long bios_size; + //int phy_addr = 0; + //static int phy_addr = 1; + target_ulong kernel_base, initrd_base; + long kernel_size, initrd_size; + int linux_boot; + int fl_idx, fl_sectors, len; + DriveInfo *dinfo; + MemoryRegion *sysmem = get_system_memory(); + + /* XXX: fix this */ + memory_region_init_ram(&ram_memories[0], "ef405ep.ram", 0x08000000); + vmstate_register_ram_global(&ram_memories[0]); + ram_bases[0] = 0; + ram_sizes[0] = 0x08000000; + memory_region_init(&ram_memories[1], "ef405ep.ram1", 0); + ram_bases[1] = 0x00000000; + ram_sizes[1] = 0x00000000; + ram_size = 128 * 1024 * 1024; +#ifdef DEBUG_BOARD_INIT + printf("%s: register cpu\n", __func__); +#endif + env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, + 33333333, &pic, kernel_filename == NULL ? 0 : 1); + /* allocate SRAM */ + sram_size = 512 * 1024; + memory_region_init_ram(sram, "ef405ep.sram", sram_size); + vmstate_register_ram_global(sram); + memory_region_add_subregion(sysmem, 0xFFF00000, sram); + /* allocate and load BIOS */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register BIOS\n", __func__); +#endif + fl_idx = 0; +#ifdef USE_FLASH_BIOS + dinfo = drive_get(IF_PFLASH, 0, fl_idx); + if (dinfo) { + bios_size = bdrv_getlength(dinfo->bdrv); + fl_sectors = (bios_size + 65535) >> 16; +#ifdef DEBUG_BOARD_INIT + printf("Register parallel flash %d size %lx" + " at addr %lx '%s' %d\n", + fl_idx, bios_size, -bios_size, + bdrv_get_device_name(dinfo->bdrv), fl_sectors); +#endif + pflash_cfi02_register((uint32_t)(-bios_size), + NULL, "ef405ep.bios", bios_size, + dinfo->bdrv, 65536, fl_sectors, 1, + 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + fl_idx++; + } else +#endif + { +#ifdef DEBUG_BOARD_INIT + printf("Load BIOS from file\n"); +#endif + bios = g_new(MemoryRegion, 1); + memory_region_init_ram(bios, "ef405ep.bios", BIOS_SIZE); + vmstate_register_ram_global(bios); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = load_image(filename, memory_region_get_ram_ptr(bios)); + g_free(filename); + } else { + bios_size = -1; + } + if (bios_size < 0 || bios_size > BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", + bios_name); + exit(1); + } + bios_size = (bios_size + 0xfff) & ~0xfff; + memory_region_set_readonly(bios, true); + memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios); + } + /* Register FPGA */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register FPGA\n", __func__); +#endif + ref405ep_fpga_init(sysmem, 0xF0300000); + /* Register NVRAM */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register NVRAM\n", __func__); +#endif + m48t59_init(NULL, 0xF0000000, 0, 8192, 8); + /* Load kernel */ + linux_boot = (kernel_filename != NULL); + if (linux_boot) { +#ifdef DEBUG_BOARD_INIT + printf("%s: load kernel\n", __func__); +#endif + memset(&bd, 0, sizeof(bd)); + bd.bi_memstart = 0x00000000; + bd.bi_memsize = ram_size; + bd.bi_flashstart = -bios_size; + bd.bi_flashsize = -bios_size; + bd.bi_flashoffset = 0; + bd.bi_sramstart = 0xFFF00000; + bd.bi_sramsize = sram_size; + bd.bi_bootflags = 0; + bd.bi_intfreq = 133333333; + bd.bi_busfreq = 33333333; + bd.bi_baudrate = 115200; + bd.bi_s_version[0] = 'Q'; + bd.bi_s_version[1] = 'M'; + bd.bi_s_version[2] = 'U'; + bd.bi_s_version[3] = '\0'; + bd.bi_r_version[0] = 'Q'; + bd.bi_r_version[1] = 'E'; + bd.bi_r_version[2] = 'M'; + bd.bi_r_version[3] = 'U'; + bd.bi_r_version[4] = '\0'; + bd.bi_procfreq = 133333333; + bd.bi_plb_busfreq = 33333333; + bd.bi_pci_busfreq = 33333333; + bd.bi_opbfreq = 33333333; + bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001); + env->gpr[3] = bdloc; + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image_targphys(kernel_filename, kernel_base, + ram_size - kernel_base); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + printf("Load kernel size %ld at " TARGET_FMT_lx, + kernel_size, kernel_base); + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + ram_size - initrd_base); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + env->gpr[4] = initrd_base; + env->gpr[5] = initrd_size; + if (kernel_cmdline != NULL) { + len = strlen(kernel_cmdline); + bdloc -= ((len + 255) & ~255); + cpu_physical_memory_write(bdloc, (void *)kernel_cmdline, len + 1); + env->gpr[6] = bdloc; + env->gpr[7] = bdloc + len; + } else { + env->gpr[6] = 0; + env->gpr[7] = 0; + } + env->nip = KERNEL_LOAD_ADDR; + } else { + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; + bdloc = 0; + } +#ifdef DEBUG_BOARD_INIT + printf("%s: Done\n", __func__); +#endif + printf("bdloc " RAM_ADDR_FMT "\n", bdloc); +} + +static QEMUMachine ref405ep_machine = { + .name = "ref405ep", + .desc = "ref405ep", + .init = ref405ep_init, + DEFAULT_MACHINE_OPTIONS, +}; + +/*****************************************************************************/ +/* AMCC Taihu evaluation board */ +/* - PowerPC 405EP processor + * - SDRAM 128 MB at 0x00000000 + * - Boot flash 2 MB at 0xFFE00000 + * - Application flash 32 MB at 0xFC000000 + * - 2 serial ports + * - 2 ethernet PHY + * - 1 USB 1.1 device 0x50000000 + * - 1 LCD display 0x50100000 + * - 1 CPLD 0x50100000 + * - 1 I2C EEPROM + * - 1 I2C thermal sensor + * - a set of LEDs + * - bit-bang SPI port using GPIOs + * - 1 EBC interface connector 0 0x50200000 + * - 1 cardbus controller + expansion slot. + * - 1 PCI expansion slot. + */ +typedef struct taihu_cpld_t taihu_cpld_t; +struct taihu_cpld_t { + uint8_t reg0; + uint8_t reg1; +}; + +static uint32_t taihu_cpld_readb (void *opaque, hwaddr addr) +{ + taihu_cpld_t *cpld; + uint32_t ret; + + cpld = opaque; + switch (addr) { + case 0x0: + ret = cpld->reg0; + break; + case 0x1: + ret = cpld->reg1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void taihu_cpld_writeb (void *opaque, + hwaddr addr, uint32_t value) +{ + taihu_cpld_t *cpld; + + cpld = opaque; + switch (addr) { + case 0x0: + /* Read only */ + break; + case 0x1: + cpld->reg1 = value; + break; + default: + break; + } +} + +static uint32_t taihu_cpld_readw (void *opaque, hwaddr addr) +{ + uint32_t ret; + + ret = taihu_cpld_readb(opaque, addr) << 8; + ret |= taihu_cpld_readb(opaque, addr + 1); + + return ret; +} + +static void taihu_cpld_writew (void *opaque, + hwaddr addr, uint32_t value) +{ + taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF); + taihu_cpld_writeb(opaque, addr + 1, value & 0xFF); +} + +static uint32_t taihu_cpld_readl (void *opaque, hwaddr addr) +{ + uint32_t ret; + + ret = taihu_cpld_readb(opaque, addr) << 24; + ret |= taihu_cpld_readb(opaque, addr + 1) << 16; + ret |= taihu_cpld_readb(opaque, addr + 2) << 8; + ret |= taihu_cpld_readb(opaque, addr + 3); + + return ret; +} + +static void taihu_cpld_writel (void *opaque, + hwaddr addr, uint32_t value) +{ + taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF); + taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF); + taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF); + taihu_cpld_writeb(opaque, addr + 3, value & 0xFF); +} + +static const MemoryRegionOps taihu_cpld_ops = { + .old_mmio = { + .read = { taihu_cpld_readb, taihu_cpld_readw, taihu_cpld_readl, }, + .write = { taihu_cpld_writeb, taihu_cpld_writew, taihu_cpld_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void taihu_cpld_reset (void *opaque) +{ + taihu_cpld_t *cpld; + + cpld = opaque; + cpld->reg0 = 0x01; + cpld->reg1 = 0x80; +} + +static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base) +{ + taihu_cpld_t *cpld; + MemoryRegion *cpld_memory = g_new(MemoryRegion, 1); + + cpld = g_malloc0(sizeof(taihu_cpld_t)); + memory_region_init_io(cpld_memory, &taihu_cpld_ops, cpld, "cpld", 0x100); + memory_region_add_subregion(sysmem, base, cpld_memory); + qemu_register_reset(&taihu_cpld_reset, cpld); +} + +static void taihu_405ep_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *kernel_filename = args->kernel_filename; + const char *initrd_filename = args->initrd_filename; + char *filename; + qemu_irq *pic; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *bios; + MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories)); + hwaddr ram_bases[2], ram_sizes[2]; + long bios_size; + target_ulong kernel_base, initrd_base; + long kernel_size, initrd_size; + int linux_boot; + int fl_idx, fl_sectors; + DriveInfo *dinfo; + + /* RAM is soldered to the board so the size cannot be changed */ + memory_region_init_ram(&ram_memories[0], + "taihu_405ep.ram-0", 0x04000000); + vmstate_register_ram_global(&ram_memories[0]); + ram_bases[0] = 0; + ram_sizes[0] = 0x04000000; + memory_region_init_ram(&ram_memories[1], + "taihu_405ep.ram-1", 0x04000000); + vmstate_register_ram_global(&ram_memories[1]); + ram_bases[1] = 0x04000000; + ram_sizes[1] = 0x04000000; + ram_size = 0x08000000; +#ifdef DEBUG_BOARD_INIT + printf("%s: register cpu\n", __func__); +#endif + ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, + 33333333, &pic, kernel_filename == NULL ? 0 : 1); + /* allocate and load BIOS */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register BIOS\n", __func__); +#endif + fl_idx = 0; +#if defined(USE_FLASH_BIOS) + dinfo = drive_get(IF_PFLASH, 0, fl_idx); + if (dinfo) { + bios_size = bdrv_getlength(dinfo->bdrv); + /* XXX: should check that size is 2MB */ + // bios_size = 2 * 1024 * 1024; + fl_sectors = (bios_size + 65535) >> 16; +#ifdef DEBUG_BOARD_INIT + printf("Register parallel flash %d size %lx" + " at addr %lx '%s' %d\n", + fl_idx, bios_size, -bios_size, + bdrv_get_device_name(dinfo->bdrv), fl_sectors); +#endif + pflash_cfi02_register((uint32_t)(-bios_size), + NULL, "taihu_405ep.bios", bios_size, + dinfo->bdrv, 65536, fl_sectors, 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + fl_idx++; + } else +#endif + { +#ifdef DEBUG_BOARD_INIT + printf("Load BIOS from file\n"); +#endif + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + bios = g_new(MemoryRegion, 1); + memory_region_init_ram(bios, "taihu_405ep.bios", BIOS_SIZE); + vmstate_register_ram_global(bios); + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = load_image(filename, memory_region_get_ram_ptr(bios)); + g_free(filename); + } else { + bios_size = -1; + } + if (bios_size < 0 || bios_size > BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", + bios_name); + exit(1); + } + bios_size = (bios_size + 0xfff) & ~0xfff; + memory_region_set_readonly(bios, true); + memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios); + } + /* Register Linux flash */ + dinfo = drive_get(IF_PFLASH, 0, fl_idx); + if (dinfo) { + bios_size = bdrv_getlength(dinfo->bdrv); + /* XXX: should check that size is 32MB */ + bios_size = 32 * 1024 * 1024; + fl_sectors = (bios_size + 65535) >> 16; +#ifdef DEBUG_BOARD_INIT + printf("Register parallel flash %d size %lx" + " at addr " TARGET_FMT_lx " '%s'\n", + fl_idx, bios_size, (target_ulong)0xfc000000, + bdrv_get_device_name(dinfo->bdrv)); +#endif + pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size, + dinfo->bdrv, 65536, fl_sectors, 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + fl_idx++; + } + /* Register CLPD & LCD display */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register CPLD\n", __func__); +#endif + taihu_cpld_init(sysmem, 0x50100000); + /* Load kernel */ + linux_boot = (kernel_filename != NULL); + if (linux_boot) { +#ifdef DEBUG_BOARD_INIT + printf("%s: load kernel\n", __func__); +#endif + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image_targphys(kernel_filename, kernel_base, + ram_size - kernel_base); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + ram_size - initrd_base); + if (initrd_size < 0) { + fprintf(stderr, + "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + } else { + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; + } +#ifdef DEBUG_BOARD_INIT + printf("%s: Done\n", __func__); +#endif +} + +static QEMUMachine taihu_machine = { + .name = "taihu", + .desc = "taihu", + .init = taihu_405ep_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void ppc405_machine_init(void) +{ + qemu_register_machine(&ref405ep_machine); + qemu_register_machine(&taihu_machine); +} + +machine_init(ppc405_machine_init); diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c new file mode 100644 index 0000000000..8465f6dcd4 --- /dev/null +++ b/hw/ppc/ppc405_uc.c @@ -0,0 +1,2548 @@ +/* + * QEMU PowerPC 405 embedded processors emulation + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" +#include "hw/serial.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" + +#define DEBUG_OPBA +#define DEBUG_SDRAM +#define DEBUG_GPIO +#define DEBUG_SERIAL +#define DEBUG_OCM +//#define DEBUG_I2C +#define DEBUG_GPT +#define DEBUG_MAL +#define DEBUG_CLOCKS +//#define DEBUG_CLOCKS_LL + +ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd, + uint32_t flags) +{ + ram_addr_t bdloc; + int i, n; + + /* We put the bd structure at the top of memory */ + if (bd->bi_memsize >= 0x01000000UL) + bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t); + else + bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t); + stl_be_phys(bdloc + 0x00, bd->bi_memstart); + stl_be_phys(bdloc + 0x04, bd->bi_memsize); + stl_be_phys(bdloc + 0x08, bd->bi_flashstart); + stl_be_phys(bdloc + 0x0C, bd->bi_flashsize); + stl_be_phys(bdloc + 0x10, bd->bi_flashoffset); + stl_be_phys(bdloc + 0x14, bd->bi_sramstart); + stl_be_phys(bdloc + 0x18, bd->bi_sramsize); + stl_be_phys(bdloc + 0x1C, bd->bi_bootflags); + stl_be_phys(bdloc + 0x20, bd->bi_ipaddr); + for (i = 0; i < 6; i++) { + stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]); + } + stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed); + stl_be_phys(bdloc + 0x2C, bd->bi_intfreq); + stl_be_phys(bdloc + 0x30, bd->bi_busfreq); + stl_be_phys(bdloc + 0x34, bd->bi_baudrate); + for (i = 0; i < 4; i++) { + stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]); + } + for (i = 0; i < 32; i++) { + stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]); + } + stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq); + stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq); + for (i = 0; i < 6; i++) { + stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]); + } + n = 0x6A; + if (flags & 0x00000001) { + for (i = 0; i < 6; i++) + stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]); + } + stl_be_phys(bdloc + n, bd->bi_opbfreq); + n += 4; + for (i = 0; i < 2; i++) { + stl_be_phys(bdloc + n, bd->bi_iic_fast[i]); + n += 4; + } + + return bdloc; +} + +/*****************************************************************************/ +/* Shared peripherals */ + +/*****************************************************************************/ +/* Peripheral local bus arbitrer */ +enum { + PLB0_BESR = 0x084, + PLB0_BEAR = 0x086, + PLB0_ACR = 0x087, +}; + +typedef struct ppc4xx_plb_t ppc4xx_plb_t; +struct ppc4xx_plb_t { + uint32_t acr; + uint32_t bear; + uint32_t besr; +}; + +static uint32_t dcr_read_plb (void *opaque, int dcrn) +{ + ppc4xx_plb_t *plb; + uint32_t ret; + + plb = opaque; + switch (dcrn) { + case PLB0_ACR: + ret = plb->acr; + break; + case PLB0_BEAR: + ret = plb->bear; + break; + case PLB0_BESR: + ret = plb->besr; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_plb (void *opaque, int dcrn, uint32_t val) +{ + ppc4xx_plb_t *plb; + + plb = opaque; + switch (dcrn) { + case PLB0_ACR: + /* We don't care about the actual parameters written as + * we don't manage any priorities on the bus + */ + plb->acr = val & 0xF8000000; + break; + case PLB0_BEAR: + /* Read only */ + break; + case PLB0_BESR: + /* Write-clear */ + plb->besr &= ~val; + break; + } +} + +static void ppc4xx_plb_reset (void *opaque) +{ + ppc4xx_plb_t *plb; + + plb = opaque; + plb->acr = 0x00000000; + plb->bear = 0x00000000; + plb->besr = 0x00000000; +} + +static void ppc4xx_plb_init(CPUPPCState *env) +{ + ppc4xx_plb_t *plb; + + plb = g_malloc0(sizeof(ppc4xx_plb_t)); + ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb); + ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb); + ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb); + qemu_register_reset(ppc4xx_plb_reset, plb); +} + +/*****************************************************************************/ +/* PLB to OPB bridge */ +enum { + POB0_BESR0 = 0x0A0, + POB0_BESR1 = 0x0A2, + POB0_BEAR = 0x0A4, +}; + +typedef struct ppc4xx_pob_t ppc4xx_pob_t; +struct ppc4xx_pob_t { + uint32_t bear; + uint32_t besr0; + uint32_t besr1; +}; + +static uint32_t dcr_read_pob (void *opaque, int dcrn) +{ + ppc4xx_pob_t *pob; + uint32_t ret; + + pob = opaque; + switch (dcrn) { + case POB0_BEAR: + ret = pob->bear; + break; + case POB0_BESR0: + ret = pob->besr0; + break; + case POB0_BESR1: + ret = pob->besr1; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_pob (void *opaque, int dcrn, uint32_t val) +{ + ppc4xx_pob_t *pob; + + pob = opaque; + switch (dcrn) { + case POB0_BEAR: + /* Read only */ + break; + case POB0_BESR0: + /* Write-clear */ + pob->besr0 &= ~val; + break; + case POB0_BESR1: + /* Write-clear */ + pob->besr1 &= ~val; + break; + } +} + +static void ppc4xx_pob_reset (void *opaque) +{ + ppc4xx_pob_t *pob; + + pob = opaque; + /* No error */ + pob->bear = 0x00000000; + pob->besr0 = 0x0000000; + pob->besr1 = 0x0000000; +} + +static void ppc4xx_pob_init(CPUPPCState *env) +{ + ppc4xx_pob_t *pob; + + pob = g_malloc0(sizeof(ppc4xx_pob_t)); + ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob); + ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob); + ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob); + qemu_register_reset(ppc4xx_pob_reset, pob); +} + +/*****************************************************************************/ +/* OPB arbitrer */ +typedef struct ppc4xx_opba_t ppc4xx_opba_t; +struct ppc4xx_opba_t { + MemoryRegion io; + uint8_t cr; + uint8_t pr; +}; + +static uint32_t opba_readb (void *opaque, hwaddr addr) +{ + ppc4xx_opba_t *opba; + uint32_t ret; + +#ifdef DEBUG_OPBA + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + opba = opaque; + switch (addr) { + case 0x00: + ret = opba->cr; + break; + case 0x01: + ret = opba->pr; + break; + default: + ret = 0x00; + break; + } + + return ret; +} + +static void opba_writeb (void *opaque, + hwaddr addr, uint32_t value) +{ + ppc4xx_opba_t *opba; + +#ifdef DEBUG_OPBA + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + opba = opaque; + switch (addr) { + case 0x00: + opba->cr = value & 0xF8; + break; + case 0x01: + opba->pr = value & 0xFF; + break; + default: + break; + } +} + +static uint32_t opba_readw (void *opaque, hwaddr addr) +{ + uint32_t ret; + +#ifdef DEBUG_OPBA + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + ret = opba_readb(opaque, addr) << 8; + ret |= opba_readb(opaque, addr + 1); + + return ret; +} + +static void opba_writew (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_OPBA + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + opba_writeb(opaque, addr, value >> 8); + opba_writeb(opaque, addr + 1, value); +} + +static uint32_t opba_readl (void *opaque, hwaddr addr) +{ + uint32_t ret; + +#ifdef DEBUG_OPBA + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + ret = opba_readb(opaque, addr) << 24; + ret |= opba_readb(opaque, addr + 1) << 16; + + return ret; +} + +static void opba_writel (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_OPBA + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + opba_writeb(opaque, addr, value >> 24); + opba_writeb(opaque, addr + 1, value >> 16); +} + +static const MemoryRegionOps opba_ops = { + .old_mmio = { + .read = { opba_readb, opba_readw, opba_readl, }, + .write = { opba_writeb, opba_writew, opba_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ppc4xx_opba_reset (void *opaque) +{ + ppc4xx_opba_t *opba; + + opba = opaque; + opba->cr = 0x00; /* No dynamic priorities - park disabled */ + opba->pr = 0x11; +} + +static void ppc4xx_opba_init(hwaddr base) +{ + ppc4xx_opba_t *opba; + + opba = g_malloc0(sizeof(ppc4xx_opba_t)); +#ifdef DEBUG_OPBA + printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); +#endif + memory_region_init_io(&opba->io, &opba_ops, opba, "opba", 0x002); + memory_region_add_subregion(get_system_memory(), base, &opba->io); + qemu_register_reset(ppc4xx_opba_reset, opba); +} + +/*****************************************************************************/ +/* Code decompression controller */ +/* XXX: TODO */ + +/*****************************************************************************/ +/* Peripheral controller */ +typedef struct ppc4xx_ebc_t ppc4xx_ebc_t; +struct ppc4xx_ebc_t { + uint32_t addr; + uint32_t bcr[8]; + uint32_t bap[8]; + uint32_t bear; + uint32_t besr0; + uint32_t besr1; + uint32_t cfg; +}; + +enum { + EBC0_CFGADDR = 0x012, + EBC0_CFGDATA = 0x013, +}; + +static uint32_t dcr_read_ebc (void *opaque, int dcrn) +{ + ppc4xx_ebc_t *ebc; + uint32_t ret; + + ebc = opaque; + switch (dcrn) { + case EBC0_CFGADDR: + ret = ebc->addr; + break; + case EBC0_CFGDATA: + switch (ebc->addr) { + case 0x00: /* B0CR */ + ret = ebc->bcr[0]; + break; + case 0x01: /* B1CR */ + ret = ebc->bcr[1]; + break; + case 0x02: /* B2CR */ + ret = ebc->bcr[2]; + break; + case 0x03: /* B3CR */ + ret = ebc->bcr[3]; + break; + case 0x04: /* B4CR */ + ret = ebc->bcr[4]; + break; + case 0x05: /* B5CR */ + ret = ebc->bcr[5]; + break; + case 0x06: /* B6CR */ + ret = ebc->bcr[6]; + break; + case 0x07: /* B7CR */ + ret = ebc->bcr[7]; + break; + case 0x10: /* B0AP */ + ret = ebc->bap[0]; + break; + case 0x11: /* B1AP */ + ret = ebc->bap[1]; + break; + case 0x12: /* B2AP */ + ret = ebc->bap[2]; + break; + case 0x13: /* B3AP */ + ret = ebc->bap[3]; + break; + case 0x14: /* B4AP */ + ret = ebc->bap[4]; + break; + case 0x15: /* B5AP */ + ret = ebc->bap[5]; + break; + case 0x16: /* B6AP */ + ret = ebc->bap[6]; + break; + case 0x17: /* B7AP */ + ret = ebc->bap[7]; + break; + case 0x20: /* BEAR */ + ret = ebc->bear; + break; + case 0x21: /* BESR0 */ + ret = ebc->besr0; + break; + case 0x22: /* BESR1 */ + ret = ebc->besr1; + break; + case 0x23: /* CFG */ + ret = ebc->cfg; + break; + default: + ret = 0x00000000; + break; + } + break; + default: + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_ebc (void *opaque, int dcrn, uint32_t val) +{ + ppc4xx_ebc_t *ebc; + + ebc = opaque; + switch (dcrn) { + case EBC0_CFGADDR: + ebc->addr = val; + break; + case EBC0_CFGDATA: + switch (ebc->addr) { + case 0x00: /* B0CR */ + break; + case 0x01: /* B1CR */ + break; + case 0x02: /* B2CR */ + break; + case 0x03: /* B3CR */ + break; + case 0x04: /* B4CR */ + break; + case 0x05: /* B5CR */ + break; + case 0x06: /* B6CR */ + break; + case 0x07: /* B7CR */ + break; + case 0x10: /* B0AP */ + break; + case 0x11: /* B1AP */ + break; + case 0x12: /* B2AP */ + break; + case 0x13: /* B3AP */ + break; + case 0x14: /* B4AP */ + break; + case 0x15: /* B5AP */ + break; + case 0x16: /* B6AP */ + break; + case 0x17: /* B7AP */ + break; + case 0x20: /* BEAR */ + break; + case 0x21: /* BESR0 */ + break; + case 0x22: /* BESR1 */ + break; + case 0x23: /* CFG */ + break; + default: + break; + } + break; + default: + break; + } +} + +static void ebc_reset (void *opaque) +{ + ppc4xx_ebc_t *ebc; + int i; + + ebc = opaque; + ebc->addr = 0x00000000; + ebc->bap[0] = 0x7F8FFE80; + ebc->bcr[0] = 0xFFE28000; + for (i = 0; i < 8; i++) { + ebc->bap[i] = 0x00000000; + ebc->bcr[i] = 0x00000000; + } + ebc->besr0 = 0x00000000; + ebc->besr1 = 0x00000000; + ebc->cfg = 0x80400000; +} + +static void ppc405_ebc_init(CPUPPCState *env) +{ + ppc4xx_ebc_t *ebc; + + ebc = g_malloc0(sizeof(ppc4xx_ebc_t)); + qemu_register_reset(&ebc_reset, ebc); + ppc_dcr_register(env, EBC0_CFGADDR, + ebc, &dcr_read_ebc, &dcr_write_ebc); + ppc_dcr_register(env, EBC0_CFGDATA, + ebc, &dcr_read_ebc, &dcr_write_ebc); +} + +/*****************************************************************************/ +/* DMA controller */ +enum { + DMA0_CR0 = 0x100, + DMA0_CT0 = 0x101, + DMA0_DA0 = 0x102, + DMA0_SA0 = 0x103, + DMA0_SG0 = 0x104, + DMA0_CR1 = 0x108, + DMA0_CT1 = 0x109, + DMA0_DA1 = 0x10A, + DMA0_SA1 = 0x10B, + DMA0_SG1 = 0x10C, + DMA0_CR2 = 0x110, + DMA0_CT2 = 0x111, + DMA0_DA2 = 0x112, + DMA0_SA2 = 0x113, + DMA0_SG2 = 0x114, + DMA0_CR3 = 0x118, + DMA0_CT3 = 0x119, + DMA0_DA3 = 0x11A, + DMA0_SA3 = 0x11B, + DMA0_SG3 = 0x11C, + DMA0_SR = 0x120, + DMA0_SGC = 0x123, + DMA0_SLP = 0x125, + DMA0_POL = 0x126, +}; + +typedef struct ppc405_dma_t ppc405_dma_t; +struct ppc405_dma_t { + qemu_irq irqs[4]; + uint32_t cr[4]; + uint32_t ct[4]; + uint32_t da[4]; + uint32_t sa[4]; + uint32_t sg[4]; + uint32_t sr; + uint32_t sgc; + uint32_t slp; + uint32_t pol; +}; + +static uint32_t dcr_read_dma (void *opaque, int dcrn) +{ + return 0; +} + +static void dcr_write_dma (void *opaque, int dcrn, uint32_t val) +{ +} + +static void ppc405_dma_reset (void *opaque) +{ + ppc405_dma_t *dma; + int i; + + dma = opaque; + for (i = 0; i < 4; i++) { + dma->cr[i] = 0x00000000; + dma->ct[i] = 0x00000000; + dma->da[i] = 0x00000000; + dma->sa[i] = 0x00000000; + dma->sg[i] = 0x00000000; + } + dma->sr = 0x00000000; + dma->sgc = 0x00000000; + dma->slp = 0x7C000000; + dma->pol = 0x00000000; +} + +static void ppc405_dma_init(CPUPPCState *env, qemu_irq irqs[4]) +{ + ppc405_dma_t *dma; + + dma = g_malloc0(sizeof(ppc405_dma_t)); + memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq)); + qemu_register_reset(&ppc405_dma_reset, dma); + ppc_dcr_register(env, DMA0_CR0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CR1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CR2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CR3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SR, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SGC, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SLP, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_POL, + dma, &dcr_read_dma, &dcr_write_dma); +} + +/*****************************************************************************/ +/* GPIO */ +typedef struct ppc405_gpio_t ppc405_gpio_t; +struct ppc405_gpio_t { + MemoryRegion io; + uint32_t or; + uint32_t tcr; + uint32_t osrh; + uint32_t osrl; + uint32_t tsrh; + uint32_t tsrl; + uint32_t odr; + uint32_t ir; + uint32_t rr1; + uint32_t isr1h; + uint32_t isr1l; +}; + +static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr) +{ +#ifdef DEBUG_GPIO + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return 0; +} + +static void ppc405_gpio_writeb (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_GPIO + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif +} + +static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr) +{ +#ifdef DEBUG_GPIO + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return 0; +} + +static void ppc405_gpio_writew (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_GPIO + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif +} + +static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr) +{ +#ifdef DEBUG_GPIO + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return 0; +} + +static void ppc405_gpio_writel (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_GPIO + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif +} + +static const MemoryRegionOps ppc405_gpio_ops = { + .old_mmio = { + .read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, }, + .write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ppc405_gpio_reset (void *opaque) +{ +} + +static void ppc405_gpio_init(hwaddr base) +{ + ppc405_gpio_t *gpio; + + gpio = g_malloc0(sizeof(ppc405_gpio_t)); +#ifdef DEBUG_GPIO + printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); +#endif + memory_region_init_io(&gpio->io, &ppc405_gpio_ops, gpio, "pgio", 0x038); + memory_region_add_subregion(get_system_memory(), base, &gpio->io); + qemu_register_reset(&ppc405_gpio_reset, gpio); +} + +/*****************************************************************************/ +/* On Chip Memory */ +enum { + OCM0_ISARC = 0x018, + OCM0_ISACNTL = 0x019, + OCM0_DSARC = 0x01A, + OCM0_DSACNTL = 0x01B, +}; + +typedef struct ppc405_ocm_t ppc405_ocm_t; +struct ppc405_ocm_t { + MemoryRegion ram; + MemoryRegion isarc_ram; + MemoryRegion dsarc_ram; + uint32_t isarc; + uint32_t isacntl; + uint32_t dsarc; + uint32_t dsacntl; +}; + +static void ocm_update_mappings (ppc405_ocm_t *ocm, + uint32_t isarc, uint32_t isacntl, + uint32_t dsarc, uint32_t dsacntl) +{ +#ifdef DEBUG_OCM + printf("OCM update ISA %08" PRIx32 " %08" PRIx32 " (%08" PRIx32 + " %08" PRIx32 ") DSA %08" PRIx32 " %08" PRIx32 + " (%08" PRIx32 " %08" PRIx32 ")\n", + isarc, isacntl, dsarc, dsacntl, + ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl); +#endif + if (ocm->isarc != isarc || + (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) { + if (ocm->isacntl & 0x80000000) { + /* Unmap previously assigned memory region */ + printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc); + memory_region_del_subregion(get_system_memory(), &ocm->isarc_ram); + } + if (isacntl & 0x80000000) { + /* Map new instruction memory region */ +#ifdef DEBUG_OCM + printf("OCM map ISA %08" PRIx32 "\n", isarc); +#endif + memory_region_add_subregion(get_system_memory(), isarc, + &ocm->isarc_ram); + } + } + if (ocm->dsarc != dsarc || + (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) { + if (ocm->dsacntl & 0x80000000) { + /* Beware not to unmap the region we just mapped */ + if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) { + /* Unmap previously assigned memory region */ +#ifdef DEBUG_OCM + printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc); +#endif + memory_region_del_subregion(get_system_memory(), + &ocm->dsarc_ram); + } + } + if (dsacntl & 0x80000000) { + /* Beware not to remap the region we just mapped */ + if (!(isacntl & 0x80000000) || dsarc != isarc) { + /* Map new data memory region */ +#ifdef DEBUG_OCM + printf("OCM map DSA %08" PRIx32 "\n", dsarc); +#endif + memory_region_add_subregion(get_system_memory(), dsarc, + &ocm->dsarc_ram); + } + } + } +} + +static uint32_t dcr_read_ocm (void *opaque, int dcrn) +{ + ppc405_ocm_t *ocm; + uint32_t ret; + + ocm = opaque; + switch (dcrn) { + case OCM0_ISARC: + ret = ocm->isarc; + break; + case OCM0_ISACNTL: + ret = ocm->isacntl; + break; + case OCM0_DSARC: + ret = ocm->dsarc; + break; + case OCM0_DSACNTL: + ret = ocm->dsacntl; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val) +{ + ppc405_ocm_t *ocm; + uint32_t isarc, dsarc, isacntl, dsacntl; + + ocm = opaque; + isarc = ocm->isarc; + dsarc = ocm->dsarc; + isacntl = ocm->isacntl; + dsacntl = ocm->dsacntl; + switch (dcrn) { + case OCM0_ISARC: + isarc = val & 0xFC000000; + break; + case OCM0_ISACNTL: + isacntl = val & 0xC0000000; + break; + case OCM0_DSARC: + isarc = val & 0xFC000000; + break; + case OCM0_DSACNTL: + isacntl = val & 0xC0000000; + break; + } + ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl); + ocm->isarc = isarc; + ocm->dsarc = dsarc; + ocm->isacntl = isacntl; + ocm->dsacntl = dsacntl; +} + +static void ocm_reset (void *opaque) +{ + ppc405_ocm_t *ocm; + uint32_t isarc, dsarc, isacntl, dsacntl; + + ocm = opaque; + isarc = 0x00000000; + isacntl = 0x00000000; + dsarc = 0x00000000; + dsacntl = 0x00000000; + ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl); + ocm->isarc = isarc; + ocm->dsarc = dsarc; + ocm->isacntl = isacntl; + ocm->dsacntl = dsacntl; +} + +static void ppc405_ocm_init(CPUPPCState *env) +{ + ppc405_ocm_t *ocm; + + ocm = g_malloc0(sizeof(ppc405_ocm_t)); + /* XXX: Size is 4096 or 0x04000000 */ + memory_region_init_ram(&ocm->isarc_ram, "ppc405.ocm", 4096); + vmstate_register_ram_global(&ocm->isarc_ram); + memory_region_init_alias(&ocm->dsarc_ram, "ppc405.dsarc", &ocm->isarc_ram, + 0, 4096); + qemu_register_reset(&ocm_reset, ocm); + ppc_dcr_register(env, OCM0_ISARC, + ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc_dcr_register(env, OCM0_ISACNTL, + ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc_dcr_register(env, OCM0_DSARC, + ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc_dcr_register(env, OCM0_DSACNTL, + ocm, &dcr_read_ocm, &dcr_write_ocm); +} + +/*****************************************************************************/ +/* I2C controller */ +typedef struct ppc4xx_i2c_t ppc4xx_i2c_t; +struct ppc4xx_i2c_t { + qemu_irq irq; + MemoryRegion iomem; + uint8_t mdata; + uint8_t lmadr; + uint8_t hmadr; + uint8_t cntl; + uint8_t mdcntl; + uint8_t sts; + uint8_t extsts; + uint8_t sdata; + uint8_t lsadr; + uint8_t hsadr; + uint8_t clkdiv; + uint8_t intrmsk; + uint8_t xfrcnt; + uint8_t xtcntlss; + uint8_t directcntl; +}; + +static uint32_t ppc4xx_i2c_readb (void *opaque, hwaddr addr) +{ + ppc4xx_i2c_t *i2c; + uint32_t ret; + +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + i2c = opaque; + switch (addr) { + case 0x00: + // i2c_readbyte(&i2c->mdata); + ret = i2c->mdata; + break; + case 0x02: + ret = i2c->sdata; + break; + case 0x04: + ret = i2c->lmadr; + break; + case 0x05: + ret = i2c->hmadr; + break; + case 0x06: + ret = i2c->cntl; + break; + case 0x07: + ret = i2c->mdcntl; + break; + case 0x08: + ret = i2c->sts; + break; + case 0x09: + ret = i2c->extsts; + break; + case 0x0A: + ret = i2c->lsadr; + break; + case 0x0B: + ret = i2c->hsadr; + break; + case 0x0C: + ret = i2c->clkdiv; + break; + case 0x0D: + ret = i2c->intrmsk; + break; + case 0x0E: + ret = i2c->xfrcnt; + break; + case 0x0F: + ret = i2c->xtcntlss; + break; + case 0x10: + ret = i2c->directcntl; + break; + default: + ret = 0x00; + break; + } +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret); +#endif + + return ret; +} + +static void ppc4xx_i2c_writeb (void *opaque, + hwaddr addr, uint32_t value) +{ + ppc4xx_i2c_t *i2c; + +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + i2c = opaque; + switch (addr) { + case 0x00: + i2c->mdata = value; + // i2c_sendbyte(&i2c->mdata); + break; + case 0x02: + i2c->sdata = value; + break; + case 0x04: + i2c->lmadr = value; + break; + case 0x05: + i2c->hmadr = value; + break; + case 0x06: + i2c->cntl = value; + break; + case 0x07: + i2c->mdcntl = value & 0xDF; + break; + case 0x08: + i2c->sts &= ~(value & 0x0A); + break; + case 0x09: + i2c->extsts &= ~(value & 0x8F); + break; + case 0x0A: + i2c->lsadr = value; + break; + case 0x0B: + i2c->hsadr = value; + break; + case 0x0C: + i2c->clkdiv = value; + break; + case 0x0D: + i2c->intrmsk = value; + break; + case 0x0E: + i2c->xfrcnt = value & 0x77; + break; + case 0x0F: + i2c->xtcntlss = value; + break; + case 0x10: + i2c->directcntl = value & 0x7; + break; + } +} + +static uint32_t ppc4xx_i2c_readw (void *opaque, hwaddr addr) +{ + uint32_t ret; + +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + ret = ppc4xx_i2c_readb(opaque, addr) << 8; + ret |= ppc4xx_i2c_readb(opaque, addr + 1); + + return ret; +} + +static void ppc4xx_i2c_writew (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + ppc4xx_i2c_writeb(opaque, addr, value >> 8); + ppc4xx_i2c_writeb(opaque, addr + 1, value); +} + +static uint32_t ppc4xx_i2c_readl (void *opaque, hwaddr addr) +{ + uint32_t ret; + +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + ret = ppc4xx_i2c_readb(opaque, addr) << 24; + ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16; + ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8; + ret |= ppc4xx_i2c_readb(opaque, addr + 3); + + return ret; +} + +static void ppc4xx_i2c_writel (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + ppc4xx_i2c_writeb(opaque, addr, value >> 24); + ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16); + ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8); + ppc4xx_i2c_writeb(opaque, addr + 3, value); +} + +static const MemoryRegionOps i2c_ops = { + .old_mmio = { + .read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, }, + .write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ppc4xx_i2c_reset (void *opaque) +{ + ppc4xx_i2c_t *i2c; + + i2c = opaque; + i2c->mdata = 0x00; + i2c->sdata = 0x00; + i2c->cntl = 0x00; + i2c->mdcntl = 0x00; + i2c->sts = 0x00; + i2c->extsts = 0x00; + i2c->clkdiv = 0x00; + i2c->xfrcnt = 0x00; + i2c->directcntl = 0x0F; +} + +static void ppc405_i2c_init(hwaddr base, qemu_irq irq) +{ + ppc4xx_i2c_t *i2c; + + i2c = g_malloc0(sizeof(ppc4xx_i2c_t)); + i2c->irq = irq; +#ifdef DEBUG_I2C + printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); +#endif + memory_region_init_io(&i2c->iomem, &i2c_ops, i2c, "i2c", 0x011); + memory_region_add_subregion(get_system_memory(), base, &i2c->iomem); + qemu_register_reset(ppc4xx_i2c_reset, i2c); +} + +/*****************************************************************************/ +/* General purpose timers */ +typedef struct ppc4xx_gpt_t ppc4xx_gpt_t; +struct ppc4xx_gpt_t { + MemoryRegion iomem; + int64_t tb_offset; + uint32_t tb_freq; + struct QEMUTimer *timer; + qemu_irq irqs[5]; + uint32_t oe; + uint32_t ol; + uint32_t im; + uint32_t is; + uint32_t ie; + uint32_t comp[5]; + uint32_t mask[5]; +}; + +static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr) +{ +#ifdef DEBUG_GPT + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + /* XXX: generate a bus fault */ + return -1; +} + +static void ppc4xx_gpt_writeb (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + /* XXX: generate a bus fault */ +} + +static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr) +{ +#ifdef DEBUG_GPT + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + /* XXX: generate a bus fault */ + return -1; +} + +static void ppc4xx_gpt_writew (void *opaque, + hwaddr addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + /* XXX: generate a bus fault */ +} + +static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n) +{ + /* XXX: TODO */ + return 0; +} + +static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level) +{ + /* XXX: TODO */ +} + +static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) +{ + uint32_t mask; + int i; + + mask = 0x80000000; + for (i = 0; i < 5; i++) { + if (gpt->oe & mask) { + /* Output is enabled */ + if (ppc4xx_gpt_compare(gpt, i)) { + /* Comparison is OK */ + ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask); + } else { + /* Comparison is KO */ + ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1); + } + } + mask = mask >> 1; + } +} + +static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) +{ + uint32_t mask; + int i; + + mask = 0x00008000; + for (i = 0; i < 5; i++) { + if (gpt->is & gpt->im & mask) + qemu_irq_raise(gpt->irqs[i]); + else + qemu_irq_lower(gpt->irqs[i]); + mask = mask >> 1; + } +} + +static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) +{ + /* XXX: TODO */ +} + +static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr) +{ + ppc4xx_gpt_t *gpt; + uint32_t ret; + int idx; + +#ifdef DEBUG_GPT + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + gpt = opaque; + switch (addr) { + case 0x00: + /* Time base counter */ + ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset, + gpt->tb_freq, get_ticks_per_sec()); + break; + case 0x10: + /* Output enable */ + ret = gpt->oe; + break; + case 0x14: + /* Output level */ + ret = gpt->ol; + break; + case 0x18: + /* Interrupt mask */ + ret = gpt->im; + break; + case 0x1C: + case 0x20: + /* Interrupt status */ + ret = gpt->is; + break; + case 0x24: + /* Interrupt enable */ + ret = gpt->ie; + break; + case 0x80 ... 0x90: + /* Compare timer */ + idx = (addr - 0x80) >> 2; + ret = gpt->comp[idx]; + break; + case 0xC0 ... 0xD0: + /* Compare mask */ + idx = (addr - 0xC0) >> 2; + ret = gpt->mask[idx]; + break; + default: + ret = -1; + break; + } + + return ret; +} + +static void ppc4xx_gpt_writel (void *opaque, + hwaddr addr, uint32_t value) +{ + ppc4xx_gpt_t *gpt; + int idx; + +#ifdef DEBUG_I2C + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, + value); +#endif + gpt = opaque; + switch (addr) { + case 0x00: + /* Time base counter */ + gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq) + - qemu_get_clock_ns(vm_clock); + ppc4xx_gpt_compute_timer(gpt); + break; + case 0x10: + /* Output enable */ + gpt->oe = value & 0xF8000000; + ppc4xx_gpt_set_outputs(gpt); + break; + case 0x14: + /* Output level */ + gpt->ol = value & 0xF8000000; + ppc4xx_gpt_set_outputs(gpt); + break; + case 0x18: + /* Interrupt mask */ + gpt->im = value & 0x0000F800; + break; + case 0x1C: + /* Interrupt status set */ + gpt->is |= value & 0x0000F800; + ppc4xx_gpt_set_irqs(gpt); + break; + case 0x20: + /* Interrupt status clear */ + gpt->is &= ~(value & 0x0000F800); + ppc4xx_gpt_set_irqs(gpt); + break; + case 0x24: + /* Interrupt enable */ + gpt->ie = value & 0x0000F800; + ppc4xx_gpt_set_irqs(gpt); + break; + case 0x80 ... 0x90: + /* Compare timer */ + idx = (addr - 0x80) >> 2; + gpt->comp[idx] = value & 0xF8000000; + ppc4xx_gpt_compute_timer(gpt); + break; + case 0xC0 ... 0xD0: + /* Compare mask */ + idx = (addr - 0xC0) >> 2; + gpt->mask[idx] = value & 0xF8000000; + ppc4xx_gpt_compute_timer(gpt); + break; + } +} + +static const MemoryRegionOps gpt_ops = { + .old_mmio = { + .read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, }, + .write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ppc4xx_gpt_cb (void *opaque) +{ + ppc4xx_gpt_t *gpt; + + gpt = opaque; + ppc4xx_gpt_set_irqs(gpt); + ppc4xx_gpt_set_outputs(gpt); + ppc4xx_gpt_compute_timer(gpt); +} + +static void ppc4xx_gpt_reset (void *opaque) +{ + ppc4xx_gpt_t *gpt; + int i; + + gpt = opaque; + qemu_del_timer(gpt->timer); + gpt->oe = 0x00000000; + gpt->ol = 0x00000000; + gpt->im = 0x00000000; + gpt->is = 0x00000000; + gpt->ie = 0x00000000; + for (i = 0; i < 5; i++) { + gpt->comp[i] = 0x00000000; + gpt->mask[i] = 0x00000000; + } +} + +static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5]) +{ + ppc4xx_gpt_t *gpt; + int i; + + gpt = g_malloc0(sizeof(ppc4xx_gpt_t)); + for (i = 0; i < 5; i++) { + gpt->irqs[i] = irqs[i]; + } + gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt); +#ifdef DEBUG_GPT + printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); +#endif + memory_region_init_io(&gpt->iomem, &gpt_ops, gpt, "gpt", 0x0d4); + memory_region_add_subregion(get_system_memory(), base, &gpt->iomem); + qemu_register_reset(ppc4xx_gpt_reset, gpt); +} + +/*****************************************************************************/ +/* MAL */ +enum { + MAL0_CFG = 0x180, + MAL0_ESR = 0x181, + MAL0_IER = 0x182, + MAL0_TXCASR = 0x184, + MAL0_TXCARR = 0x185, + MAL0_TXEOBISR = 0x186, + MAL0_TXDEIR = 0x187, + MAL0_RXCASR = 0x190, + MAL0_RXCARR = 0x191, + MAL0_RXEOBISR = 0x192, + MAL0_RXDEIR = 0x193, + MAL0_TXCTP0R = 0x1A0, + MAL0_TXCTP1R = 0x1A1, + MAL0_TXCTP2R = 0x1A2, + MAL0_TXCTP3R = 0x1A3, + MAL0_RXCTP0R = 0x1C0, + MAL0_RXCTP1R = 0x1C1, + MAL0_RCBS0 = 0x1E0, + MAL0_RCBS1 = 0x1E1, +}; + +typedef struct ppc40x_mal_t ppc40x_mal_t; +struct ppc40x_mal_t { + qemu_irq irqs[4]; + uint32_t cfg; + uint32_t esr; + uint32_t ier; + uint32_t txcasr; + uint32_t txcarr; + uint32_t txeobisr; + uint32_t txdeir; + uint32_t rxcasr; + uint32_t rxcarr; + uint32_t rxeobisr; + uint32_t rxdeir; + uint32_t txctpr[4]; + uint32_t rxctpr[2]; + uint32_t rcbs[2]; +}; + +static void ppc40x_mal_reset (void *opaque); + +static uint32_t dcr_read_mal (void *opaque, int dcrn) +{ + ppc40x_mal_t *mal; + uint32_t ret; + + mal = opaque; + switch (dcrn) { + case MAL0_CFG: + ret = mal->cfg; + break; + case MAL0_ESR: + ret = mal->esr; + break; + case MAL0_IER: + ret = mal->ier; + break; + case MAL0_TXCASR: + ret = mal->txcasr; + break; + case MAL0_TXCARR: + ret = mal->txcarr; + break; + case MAL0_TXEOBISR: + ret = mal->txeobisr; + break; + case MAL0_TXDEIR: + ret = mal->txdeir; + break; + case MAL0_RXCASR: + ret = mal->rxcasr; + break; + case MAL0_RXCARR: + ret = mal->rxcarr; + break; + case MAL0_RXEOBISR: + ret = mal->rxeobisr; + break; + case MAL0_RXDEIR: + ret = mal->rxdeir; + break; + case MAL0_TXCTP0R: + ret = mal->txctpr[0]; + break; + case MAL0_TXCTP1R: + ret = mal->txctpr[1]; + break; + case MAL0_TXCTP2R: + ret = mal->txctpr[2]; + break; + case MAL0_TXCTP3R: + ret = mal->txctpr[3]; + break; + case MAL0_RXCTP0R: + ret = mal->rxctpr[0]; + break; + case MAL0_RXCTP1R: + ret = mal->rxctpr[1]; + break; + case MAL0_RCBS0: + ret = mal->rcbs[0]; + break; + case MAL0_RCBS1: + ret = mal->rcbs[1]; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_mal (void *opaque, int dcrn, uint32_t val) +{ + ppc40x_mal_t *mal; + int idx; + + mal = opaque; + switch (dcrn) { + case MAL0_CFG: + if (val & 0x80000000) + ppc40x_mal_reset(mal); + mal->cfg = val & 0x00FFC087; + break; + case MAL0_ESR: + /* Read/clear */ + mal->esr &= ~val; + break; + case MAL0_IER: + mal->ier = val & 0x0000001F; + break; + case MAL0_TXCASR: + mal->txcasr = val & 0xF0000000; + break; + case MAL0_TXCARR: + mal->txcarr = val & 0xF0000000; + break; + case MAL0_TXEOBISR: + /* Read/clear */ + mal->txeobisr &= ~val; + break; + case MAL0_TXDEIR: + /* Read/clear */ + mal->txdeir &= ~val; + break; + case MAL0_RXCASR: + mal->rxcasr = val & 0xC0000000; + break; + case MAL0_RXCARR: + mal->rxcarr = val & 0xC0000000; + break; + case MAL0_RXEOBISR: + /* Read/clear */ + mal->rxeobisr &= ~val; + break; + case MAL0_RXDEIR: + /* Read/clear */ + mal->rxdeir &= ~val; + break; + case MAL0_TXCTP0R: + idx = 0; + goto update_tx_ptr; + case MAL0_TXCTP1R: + idx = 1; + goto update_tx_ptr; + case MAL0_TXCTP2R: + idx = 2; + goto update_tx_ptr; + case MAL0_TXCTP3R: + idx = 3; + update_tx_ptr: + mal->txctpr[idx] = val; + break; + case MAL0_RXCTP0R: + idx = 0; + goto update_rx_ptr; + case MAL0_RXCTP1R: + idx = 1; + update_rx_ptr: + mal->rxctpr[idx] = val; + break; + case MAL0_RCBS0: + idx = 0; + goto update_rx_size; + case MAL0_RCBS1: + idx = 1; + update_rx_size: + mal->rcbs[idx] = val & 0x000000FF; + break; + } +} + +static void ppc40x_mal_reset (void *opaque) +{ + ppc40x_mal_t *mal; + + mal = opaque; + mal->cfg = 0x0007C000; + mal->esr = 0x00000000; + mal->ier = 0x00000000; + mal->rxcasr = 0x00000000; + mal->rxdeir = 0x00000000; + mal->rxeobisr = 0x00000000; + mal->txcasr = 0x00000000; + mal->txdeir = 0x00000000; + mal->txeobisr = 0x00000000; +} + +static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]) +{ + ppc40x_mal_t *mal; + int i; + + mal = g_malloc0(sizeof(ppc40x_mal_t)); + for (i = 0; i < 4; i++) + mal->irqs[i] = irqs[i]; + qemu_register_reset(&ppc40x_mal_reset, mal); + ppc_dcr_register(env, MAL0_CFG, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_ESR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_IER, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCASR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCARR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXEOBISR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXDEIR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCASR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCARR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXEOBISR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXDEIR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP0R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP1R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP2R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP3R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCTP0R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCTP1R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RCBS0, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RCBS1, + mal, &dcr_read_mal, &dcr_write_mal); +} + +/*****************************************************************************/ +/* SPR */ +void ppc40x_core_reset(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + target_ulong dbsr; + + printf("Reset PowerPC core\n"); + cpu_interrupt(env, CPU_INTERRUPT_RESET); + dbsr = env->spr[SPR_40x_DBSR]; + dbsr &= ~0x00000300; + dbsr |= 0x00000100; + env->spr[SPR_40x_DBSR] = dbsr; +} + +void ppc40x_chip_reset(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + target_ulong dbsr; + + printf("Reset PowerPC chip\n"); + cpu_interrupt(env, CPU_INTERRUPT_RESET); + /* XXX: TODO reset all internal peripherals */ + dbsr = env->spr[SPR_40x_DBSR]; + dbsr &= ~0x00000300; + dbsr |= 0x00000200; + env->spr[SPR_40x_DBSR] = dbsr; +} + +void ppc40x_system_reset(PowerPCCPU *cpu) +{ + printf("Reset PowerPC system\n"); + qemu_system_reset_request(); +} + +void store_40x_dbcr0 (CPUPPCState *env, uint32_t val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + switch ((val >> 28) & 0x3) { + case 0x0: + /* No action */ + break; + case 0x1: + /* Core reset */ + ppc40x_core_reset(cpu); + break; + case 0x2: + /* Chip reset */ + ppc40x_chip_reset(cpu); + break; + case 0x3: + /* System reset */ + ppc40x_system_reset(cpu); + break; + } +} + +/*****************************************************************************/ +/* PowerPC 405CR */ +enum { + PPC405CR_CPC0_PLLMR = 0x0B0, + PPC405CR_CPC0_CR0 = 0x0B1, + PPC405CR_CPC0_CR1 = 0x0B2, + PPC405CR_CPC0_PSR = 0x0B4, + PPC405CR_CPC0_JTAGID = 0x0B5, + PPC405CR_CPC0_ER = 0x0B9, + PPC405CR_CPC0_FR = 0x0BA, + PPC405CR_CPC0_SR = 0x0BB, +}; + +enum { + PPC405CR_CPU_CLK = 0, + PPC405CR_TMR_CLK = 1, + PPC405CR_PLB_CLK = 2, + PPC405CR_SDRAM_CLK = 3, + PPC405CR_OPB_CLK = 4, + PPC405CR_EXT_CLK = 5, + PPC405CR_UART_CLK = 6, + PPC405CR_CLK_NB = 7, +}; + +typedef struct ppc405cr_cpc_t ppc405cr_cpc_t; +struct ppc405cr_cpc_t { + clk_setup_t clk_setup[PPC405CR_CLK_NB]; + uint32_t sysclk; + uint32_t psr; + uint32_t cr0; + uint32_t cr1; + uint32_t jtagid; + uint32_t pllmr; + uint32_t er; + uint32_t fr; +}; + +static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc) +{ + uint64_t VCO_out, PLL_out; + uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk; + int M, D0, D1, D2; + + D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */ + if (cpc->pllmr & 0x80000000) { + D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */ + D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */ + M = D0 * D1 * D2; + VCO_out = cpc->sysclk * M; + if (VCO_out < 400000000 || VCO_out > 800000000) { + /* PLL cannot lock */ + cpc->pllmr &= ~0x80000000; + goto bypass_pll; + } + PLL_out = VCO_out / D2; + } else { + /* Bypass PLL */ + bypass_pll: + M = D0; + PLL_out = cpc->sysclk * M; + } + CPU_clk = PLL_out; + if (cpc->cr1 & 0x00800000) + TMR_clk = cpc->sysclk; /* Should have a separate clock */ + else + TMR_clk = CPU_clk; + PLB_clk = CPU_clk / D0; + SDRAM_clk = PLB_clk; + D0 = ((cpc->pllmr >> 10) & 0x3) + 1; + OPB_clk = PLB_clk / D0; + D0 = ((cpc->pllmr >> 24) & 0x3) + 2; + EXT_clk = PLB_clk / D0; + D0 = ((cpc->cr0 >> 1) & 0x1F) + 1; + UART_clk = CPU_clk / D0; + /* Setup CPU clocks */ + clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk); + /* Setup time-base clock */ + clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk); + /* Setup PLB clock */ + clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk); + /* Setup SDRAM clock */ + clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk); + /* Setup OPB clock */ + clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk); + /* Setup external clock */ + clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk); + /* Setup UART clock */ + clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk); +} + +static uint32_t dcr_read_crcpc (void *opaque, int dcrn) +{ + ppc405cr_cpc_t *cpc; + uint32_t ret; + + cpc = opaque; + switch (dcrn) { + case PPC405CR_CPC0_PLLMR: + ret = cpc->pllmr; + break; + case PPC405CR_CPC0_CR0: + ret = cpc->cr0; + break; + case PPC405CR_CPC0_CR1: + ret = cpc->cr1; + break; + case PPC405CR_CPC0_PSR: + ret = cpc->psr; + break; + case PPC405CR_CPC0_JTAGID: + ret = cpc->jtagid; + break; + case PPC405CR_CPC0_ER: + ret = cpc->er; + break; + case PPC405CR_CPC0_FR: + ret = cpc->fr; + break; + case PPC405CR_CPC0_SR: + ret = ~(cpc->er | cpc->fr) & 0xFFFF0000; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_crcpc (void *opaque, int dcrn, uint32_t val) +{ + ppc405cr_cpc_t *cpc; + + cpc = opaque; + switch (dcrn) { + case PPC405CR_CPC0_PLLMR: + cpc->pllmr = val & 0xFFF77C3F; + break; + case PPC405CR_CPC0_CR0: + cpc->cr0 = val & 0x0FFFFFFE; + break; + case PPC405CR_CPC0_CR1: + cpc->cr1 = val & 0x00800000; + break; + case PPC405CR_CPC0_PSR: + /* Read-only */ + break; + case PPC405CR_CPC0_JTAGID: + /* Read-only */ + break; + case PPC405CR_CPC0_ER: + cpc->er = val & 0xBFFC0000; + break; + case PPC405CR_CPC0_FR: + cpc->fr = val & 0xBFFC0000; + break; + case PPC405CR_CPC0_SR: + /* Read-only */ + break; + } +} + +static void ppc405cr_cpc_reset (void *opaque) +{ + ppc405cr_cpc_t *cpc; + int D; + + cpc = opaque; + /* Compute PLLMR value from PSR settings */ + cpc->pllmr = 0x80000000; + /* PFWD */ + switch ((cpc->psr >> 30) & 3) { + case 0: + /* Bypass */ + cpc->pllmr &= ~0x80000000; + break; + case 1: + /* Divide by 3 */ + cpc->pllmr |= 5 << 16; + break; + case 2: + /* Divide by 4 */ + cpc->pllmr |= 4 << 16; + break; + case 3: + /* Divide by 6 */ + cpc->pllmr |= 2 << 16; + break; + } + /* PFBD */ + D = (cpc->psr >> 28) & 3; + cpc->pllmr |= (D + 1) << 20; + /* PT */ + D = (cpc->psr >> 25) & 7; + switch (D) { + case 0x2: + cpc->pllmr |= 0x13; + break; + case 0x4: + cpc->pllmr |= 0x15; + break; + case 0x5: + cpc->pllmr |= 0x16; + break; + default: + break; + } + /* PDC */ + D = (cpc->psr >> 23) & 3; + cpc->pllmr |= D << 26; + /* ODP */ + D = (cpc->psr >> 21) & 3; + cpc->pllmr |= D << 10; + /* EBPD */ + D = (cpc->psr >> 17) & 3; + cpc->pllmr |= D << 24; + cpc->cr0 = 0x0000003C; + cpc->cr1 = 0x2B0D8800; + cpc->er = 0x00000000; + cpc->fr = 0x00000000; + ppc405cr_clk_setup(cpc); +} + +static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc) +{ + int D; + + /* XXX: this should be read from IO pins */ + cpc->psr = 0x00000000; /* 8 bits ROM */ + /* PFWD */ + D = 0x2; /* Divide by 4 */ + cpc->psr |= D << 30; + /* PFBD */ + D = 0x1; /* Divide by 2 */ + cpc->psr |= D << 28; + /* PDC */ + D = 0x1; /* Divide by 2 */ + cpc->psr |= D << 23; + /* PT */ + D = 0x5; /* M = 16 */ + cpc->psr |= D << 25; + /* ODP */ + D = 0x1; /* Divide by 2 */ + cpc->psr |= D << 21; + /* EBDP */ + D = 0x2; /* Divide by 4 */ + cpc->psr |= D << 17; +} + +static void ppc405cr_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[7], + uint32_t sysclk) +{ + ppc405cr_cpc_t *cpc; + + cpc = g_malloc0(sizeof(ppc405cr_cpc_t)); + memcpy(cpc->clk_setup, clk_setup, + PPC405CR_CLK_NB * sizeof(clk_setup_t)); + cpc->sysclk = sysclk; + cpc->jtagid = 0x42051049; + ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc405cr_clk_init(cpc); + qemu_register_reset(ppc405cr_cpc_reset, cpc); +} + +CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, + MemoryRegion ram_memories[4], + hwaddr ram_bases[4], + hwaddr ram_sizes[4], + uint32_t sysclk, qemu_irq **picp, + int do_init) +{ + clk_setup_t clk_setup[PPC405CR_CLK_NB]; + qemu_irq dma_irqs[4]; + PowerPCCPU *cpu; + CPUPPCState *env; + qemu_irq *pic, *irqs; + + memset(clk_setup, 0, sizeof(clk_setup)); + cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], + &clk_setup[PPC405CR_TMR_CLK], sysclk); + env = &cpu->env; + /* Memory mapped devices registers */ + /* PLB arbitrer */ + ppc4xx_plb_init(env); + /* PLB to OPB bridge */ + ppc4xx_pob_init(env); + /* OBP arbitrer */ + ppc4xx_opba_init(0xef600600); + /* Universal interrupt controller */ + irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + *picp = pic; + /* SDRAM controller */ + ppc4xx_sdram_init(env, pic[14], 1, ram_memories, + ram_bases, ram_sizes, do_init); + /* External bus controller */ + ppc405_ebc_init(env); + /* DMA controller */ + dma_irqs[0] = pic[26]; + dma_irqs[1] = pic[25]; + dma_irqs[2] = pic[24]; + dma_irqs[3] = pic[23]; + ppc405_dma_init(env, dma_irqs); + /* Serial ports */ + if (serial_hds[0] != NULL) { + serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], + PPC_SERIAL_MM_BAUDBASE, serial_hds[0], + DEVICE_BIG_ENDIAN); + } + if (serial_hds[1] != NULL) { + serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], + PPC_SERIAL_MM_BAUDBASE, serial_hds[1], + DEVICE_BIG_ENDIAN); + } + /* IIC controller */ + ppc405_i2c_init(0xef600500, pic[2]); + /* GPIO */ + ppc405_gpio_init(0xef600700); + /* CPU control */ + ppc405cr_cpc_init(env, clk_setup, sysclk); + + return env; +} + +/*****************************************************************************/ +/* PowerPC 405EP */ +/* CPU control */ +enum { + PPC405EP_CPC0_PLLMR0 = 0x0F0, + PPC405EP_CPC0_BOOT = 0x0F1, + PPC405EP_CPC0_EPCTL = 0x0F3, + PPC405EP_CPC0_PLLMR1 = 0x0F4, + PPC405EP_CPC0_UCR = 0x0F5, + PPC405EP_CPC0_SRR = 0x0F6, + PPC405EP_CPC0_JTAGID = 0x0F7, + PPC405EP_CPC0_PCI = 0x0F9, +#if 0 + PPC405EP_CPC0_ER = xxx, + PPC405EP_CPC0_FR = xxx, + PPC405EP_CPC0_SR = xxx, +#endif +}; + +enum { + PPC405EP_CPU_CLK = 0, + PPC405EP_PLB_CLK = 1, + PPC405EP_OPB_CLK = 2, + PPC405EP_EBC_CLK = 3, + PPC405EP_MAL_CLK = 4, + PPC405EP_PCI_CLK = 5, + PPC405EP_UART0_CLK = 6, + PPC405EP_UART1_CLK = 7, + PPC405EP_CLK_NB = 8, +}; + +typedef struct ppc405ep_cpc_t ppc405ep_cpc_t; +struct ppc405ep_cpc_t { + uint32_t sysclk; + clk_setup_t clk_setup[PPC405EP_CLK_NB]; + uint32_t boot; + uint32_t epctl; + uint32_t pllmr[2]; + uint32_t ucr; + uint32_t srr; + uint32_t jtagid; + uint32_t pci; + /* Clock and power management */ + uint32_t er; + uint32_t fr; + uint32_t sr; +}; + +static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) +{ + uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk; + uint32_t UART0_clk, UART1_clk; + uint64_t VCO_out, PLL_out; + int M, D; + + VCO_out = 0; + if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) { + M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */ +#ifdef DEBUG_CLOCKS_LL + printf("FBMUL %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 20) & 0xF, M); +#endif + D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */ +#ifdef DEBUG_CLOCKS_LL + printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D); +#endif + VCO_out = cpc->sysclk * M * D; + if (VCO_out < 500000000UL || VCO_out > 1000000000UL) { + /* Error - unlock the PLL */ + printf("VCO out of range %" PRIu64 "\n", VCO_out); +#if 0 + cpc->pllmr[1] &= ~0x80000000; + goto pll_bypass; +#endif + } + PLL_out = VCO_out / D; + /* Pretend the PLL is locked */ + cpc->boot |= 0x00000001; + } else { +#if 0 + pll_bypass: +#endif + PLL_out = cpc->sysclk; + if (cpc->pllmr[1] & 0x40000000) { + /* Pretend the PLL is not locked */ + cpc->boot &= ~0x00000001; + } + } + /* Now, compute all other clocks */ + D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */ +#ifdef DEBUG_CLOCKS_LL + printf("CCDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 20) & 0x3, D); +#endif + CPU_clk = PLL_out / D; + D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */ +#ifdef DEBUG_CLOCKS_LL + printf("CBDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 16) & 0x3, D); +#endif + PLB_clk = CPU_clk / D; + D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */ +#ifdef DEBUG_CLOCKS_LL + printf("OPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 12) & 0x3, D); +#endif + OPB_clk = PLB_clk / D; + D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */ +#ifdef DEBUG_CLOCKS_LL + printf("EPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 8) & 0x3, D); +#endif + EBC_clk = PLB_clk / D; + D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */ +#ifdef DEBUG_CLOCKS_LL + printf("MPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 4) & 0x3, D); +#endif + MAL_clk = PLB_clk / D; + D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */ +#ifdef DEBUG_CLOCKS_LL + printf("PPDV %01" PRIx32 " %d\n", cpc->pllmr[0] & 0x3, D); +#endif + PCI_clk = PLB_clk / D; + D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */ +#ifdef DEBUG_CLOCKS_LL + printf("U0DIV %01" PRIx32 " %d\n", cpc->ucr & 0x7F, D); +#endif + UART0_clk = PLL_out / D; + D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */ +#ifdef DEBUG_CLOCKS_LL + printf("U1DIV %01" PRIx32 " %d\n", (cpc->ucr >> 8) & 0x7F, D); +#endif + UART1_clk = PLL_out / D; +#ifdef DEBUG_CLOCKS + printf("Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64 + " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out); + printf("CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32 + " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32 + " UART1 %" PRIu32 "\n", + CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk, + UART0_clk, UART1_clk); +#endif + /* Setup CPU clocks */ + clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk); + /* Setup PLB clock */ + clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk); + /* Setup OPB clock */ + clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk); + /* Setup external clock */ + clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk); + /* Setup MAL clock */ + clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk); + /* Setup PCI clock */ + clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk); + /* Setup UART0 clock */ + clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk); + /* Setup UART1 clock */ + clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk); +} + +static uint32_t dcr_read_epcpc (void *opaque, int dcrn) +{ + ppc405ep_cpc_t *cpc; + uint32_t ret; + + cpc = opaque; + switch (dcrn) { + case PPC405EP_CPC0_BOOT: + ret = cpc->boot; + break; + case PPC405EP_CPC0_EPCTL: + ret = cpc->epctl; + break; + case PPC405EP_CPC0_PLLMR0: + ret = cpc->pllmr[0]; + break; + case PPC405EP_CPC0_PLLMR1: + ret = cpc->pllmr[1]; + break; + case PPC405EP_CPC0_UCR: + ret = cpc->ucr; + break; + case PPC405EP_CPC0_SRR: + ret = cpc->srr; + break; + case PPC405EP_CPC0_JTAGID: + ret = cpc->jtagid; + break; + case PPC405EP_CPC0_PCI: + ret = cpc->pci; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val) +{ + ppc405ep_cpc_t *cpc; + + cpc = opaque; + switch (dcrn) { + case PPC405EP_CPC0_BOOT: + /* Read-only register */ + break; + case PPC405EP_CPC0_EPCTL: + /* Don't care for now */ + cpc->epctl = val & 0xC00000F3; + break; + case PPC405EP_CPC0_PLLMR0: + cpc->pllmr[0] = val & 0x00633333; + ppc405ep_compute_clocks(cpc); + break; + case PPC405EP_CPC0_PLLMR1: + cpc->pllmr[1] = val & 0xC0F73FFF; + ppc405ep_compute_clocks(cpc); + break; + case PPC405EP_CPC0_UCR: + /* UART control - don't care for now */ + cpc->ucr = val & 0x003F7F7F; + break; + case PPC405EP_CPC0_SRR: + cpc->srr = val; + break; + case PPC405EP_CPC0_JTAGID: + /* Read-only */ + break; + case PPC405EP_CPC0_PCI: + cpc->pci = val; + break; + } +} + +static void ppc405ep_cpc_reset (void *opaque) +{ + ppc405ep_cpc_t *cpc = opaque; + + cpc->boot = 0x00000010; /* Boot from PCI - IIC EEPROM disabled */ + cpc->epctl = 0x00000000; + cpc->pllmr[0] = 0x00011010; + cpc->pllmr[1] = 0x40000000; + cpc->ucr = 0x00000000; + cpc->srr = 0x00040000; + cpc->pci = 0x00000000; + cpc->er = 0x00000000; + cpc->fr = 0x00000000; + cpc->sr = 0x00000000; + ppc405ep_compute_clocks(cpc); +} + +/* XXX: sysclk should be between 25 and 100 MHz */ +static void ppc405ep_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[8], + uint32_t sysclk) +{ + ppc405ep_cpc_t *cpc; + + cpc = g_malloc0(sizeof(ppc405ep_cpc_t)); + memcpy(cpc->clk_setup, clk_setup, + PPC405EP_CLK_NB * sizeof(clk_setup_t)); + cpc->jtagid = 0x20267049; + cpc->sysclk = sysclk; + qemu_register_reset(&ppc405ep_cpc_reset, cpc); + ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); +#if 0 + ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); +#endif +} + +CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, + MemoryRegion ram_memories[2], + hwaddr ram_bases[2], + hwaddr ram_sizes[2], + uint32_t sysclk, qemu_irq **picp, + int do_init) +{ + clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; + qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; + PowerPCCPU *cpu; + CPUPPCState *env; + qemu_irq *pic, *irqs; + + memset(clk_setup, 0, sizeof(clk_setup)); + /* init CPUs */ + cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], + &tlb_clk_setup, sysclk); + env = &cpu->env; + clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; + clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; + /* Internal devices init */ + /* Memory mapped devices registers */ + /* PLB arbitrer */ + ppc4xx_plb_init(env); + /* PLB to OPB bridge */ + ppc4xx_pob_init(env); + /* OBP arbitrer */ + ppc4xx_opba_init(0xef600600); + /* Initialize timers */ + ppc_booke_timers_init(cpu, sysclk, 0); + /* Universal interrupt controller */ + irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + *picp = pic; + /* SDRAM controller */ + /* XXX 405EP has no ECC interrupt */ + ppc4xx_sdram_init(env, pic[17], 2, ram_memories, + ram_bases, ram_sizes, do_init); + /* External bus controller */ + ppc405_ebc_init(env); + /* DMA controller */ + dma_irqs[0] = pic[5]; + dma_irqs[1] = pic[6]; + dma_irqs[2] = pic[7]; + dma_irqs[3] = pic[8]; + ppc405_dma_init(env, dma_irqs); + /* IIC controller */ + ppc405_i2c_init(0xef600500, pic[2]); + /* GPIO */ + ppc405_gpio_init(0xef600700); + /* Serial ports */ + if (serial_hds[0] != NULL) { + serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], + PPC_SERIAL_MM_BAUDBASE, serial_hds[0], + DEVICE_BIG_ENDIAN); + } + if (serial_hds[1] != NULL) { + serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], + PPC_SERIAL_MM_BAUDBASE, serial_hds[1], + DEVICE_BIG_ENDIAN); + } + /* OCM */ + ppc405_ocm_init(env); + /* GPT */ + gpt_irqs[0] = pic[19]; + gpt_irqs[1] = pic[20]; + gpt_irqs[2] = pic[21]; + gpt_irqs[3] = pic[22]; + gpt_irqs[4] = pic[23]; + ppc4xx_gpt_init(0xef600000, gpt_irqs); + /* PCI */ + /* Uses pic[3], pic[16], pic[18] */ + /* MAL */ + mal_irqs[0] = pic[11]; + mal_irqs[1] = pic[12]; + mal_irqs[2] = pic[13]; + mal_irqs[3] = pic[14]; + ppc405_mal_init(env, mal_irqs); + /* Ethernet */ + /* Uses pic[9], pic[15], pic[17] */ + /* CPU control */ + ppc405ep_cpc_init(env, clk_setup, sysclk); + + return env; +} diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c new file mode 100644 index 0000000000..66911b58c6 --- /dev/null +++ b/hw/ppc/ppc440_bamboo.c @@ -0,0 +1,306 @@ +/* + * QEMU PowerPC 440 Bamboo board emulation + * + * Copyright 2007 IBM Corporation. + * Authors: + * Jerone Young + * Christian Ehrhardt + * Hollis Blanchard + * + * This work is licensed under the GNU GPL license version 2 or later. + * + */ + +#include "config.h" +#include "qemu-common.h" +#include "net/net.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/boards.h" +#include "sysemu/kvm.h" +#include "kvm_ppc.h" +#include "sysemu/device_tree.h" +#include "hw/loader.h" +#include "elf.h" +#include "exec/address-spaces.h" +#include "hw/serial.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" + +#define BINARY_DEVICE_TREE_FILE "bamboo.dtb" + +/* from u-boot */ +#define KERNEL_ADDR 0x1000000 +#define FDT_ADDR 0x1800000 +#define RAMDISK_ADDR 0x1900000 + +#define PPC440EP_PCI_CONFIG 0xeec00000 +#define PPC440EP_PCI_INTACK 0xeed00000 +#define PPC440EP_PCI_SPECIAL 0xeed00000 +#define PPC440EP_PCI_REGS 0xef400000 +#define PPC440EP_PCI_IO 0xe8000000 +#define PPC440EP_PCI_IOLEN 0x00010000 + +#define PPC440EP_SDRAM_NR_BANKS 4 + +static const unsigned int ppc440ep_sdram_bank_sizes[] = { + 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0 +}; + +static hwaddr entry; + +static int bamboo_load_device_tree(hwaddr addr, + uint32_t ramsize, + hwaddr initrd_base, + hwaddr initrd_size, + const char *kernel_cmdline) +{ + int ret = -1; +#ifdef CONFIG_FDT + uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; + char *filename; + int fdt_size; + void *fdt; + uint32_t tb_freq = 400000000; + uint32_t clock_freq = 400000000; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + if (!filename) { + goto out; + } + fdt = load_device_tree(filename, &fdt_size); + g_free(filename); + if (fdt == NULL) { + goto out; + } + + /* Manipulate device tree in memory. */ + + ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, + sizeof(mem_reg_property)); + if (ret < 0) + fprintf(stderr, "couldn't set /memory/reg\n"); + + ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", + initrd_base); + if (ret < 0) + fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); + + ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", + (initrd_base + initrd_size)); + if (ret < 0) + fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); + + ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", + kernel_cmdline); + if (ret < 0) + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + + /* Copy data from the host device tree into the guest. Since the guest can + * directly access the timebase without host involvement, we must expose + * the correct frequencies. */ + if (kvm_enabled()) { + tb_freq = kvmppc_get_tbfreq(); + clock_freq = kvmppc_get_clockfreq(); + } + + qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency", + clock_freq); + qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency", + tb_freq); + + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); + g_free(fdt); + +out: +#endif + + return ret; +} + +/* Create reset TLB entries for BookE, spanning the 32bit addr space. */ +static void mmubooke_create_initial_mapping(CPUPPCState *env, + target_ulong va, + hwaddr pa) +{ + ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; + + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0x80000000 */ + tlb->EPN = va & TARGET_PAGE_MASK; + tlb->RPN = pa & TARGET_PAGE_MASK; + tlb->PID = 0; + + tlb = &env->tlb.tlbe[1]; + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0xffffffff */ + tlb->EPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->RPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->PID = 0; +} + +static void main_cpu_reset(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + env->gpr[1] = (16<<20) - 8; + env->gpr[3] = FDT_ADDR; + env->nip = entry; + + /* Create a mapping for the kernel. */ + mmubooke_create_initial_mapping(env, 0, 0); +} + +static void bamboo_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram_memories + = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); + hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS]; + hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS]; + qemu_irq *pic; + qemu_irq *irqs; + PCIBus *pcibus; + PowerPCCPU *cpu; + CPUPPCState *env; + uint64_t elf_entry; + uint64_t elf_lowaddr; + hwaddr loadaddr = 0; + target_long initrd_size = 0; + DeviceState *dev; + int success; + int i; + + /* Setup CPU. */ + if (cpu_model == NULL) { + cpu_model = "440EP"; + } + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to initialize CPU!\n"); + exit(1); + } + env = &cpu->env; + + qemu_register_reset(main_cpu_reset, cpu); + ppc_booke_timers_init(cpu, 400000000, 0); + ppc_dcr_init(env, NULL, NULL); + + /* interrupt controller */ + irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + + /* SDRAM controller */ + memset(ram_bases, 0, sizeof(ram_bases)); + memset(ram_sizes, 0, sizeof(ram_sizes)); + ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS, + ram_memories, + ram_bases, ram_sizes, + ppc440ep_sdram_bank_sizes); + /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ + ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories, + ram_bases, ram_sizes, 1); + + /* PCI */ + dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE, + PPC440EP_PCI_CONFIG, + pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]], + pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]], + NULL); + pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); + if (!pcibus) { + fprintf(stderr, "couldn't create PCI controller!\n"); + exit(1); + } + + isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN); + + if (serial_hds[0] != NULL) { + serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], + PPC_SERIAL_MM_BAUDBASE, serial_hds[0], + DEVICE_BIG_ENDIAN); + } + if (serial_hds[1] != NULL) { + serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], + PPC_SERIAL_MM_BAUDBASE, serial_hds[1], + DEVICE_BIG_ENDIAN); + } + + if (pcibus) { + /* Register network interfaces. */ + for (i = 0; i < nb_nics; i++) { + /* There are no PCI NICs on the Bamboo board, but there are + * PCI slots, so we can pick whatever default model we want. */ + pci_nic_init_nofail(&nd_table[i], "e1000", NULL); + } + } + + /* Load kernel. */ + if (kernel_filename) { + success = load_uimage(kernel_filename, &entry, &loadaddr, NULL); + if (success < 0) { + success = load_elf(kernel_filename, NULL, NULL, &elf_entry, + &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); + entry = elf_entry; + loadaddr = elf_lowaddr; + } + /* XXX try again as binary */ + if (success < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + /* Load initrd. */ + if (initrd_filename) { + initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR, + ram_size - RAMDISK_ADDR); + + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n", + initrd_filename, RAMDISK_ADDR); + exit(1); + } + } + + /* If we're loading a kernel directly, we must load the device tree too. */ + if (kernel_filename) { + if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR, + initrd_size, kernel_cmdline) < 0) { + fprintf(stderr, "couldn't load device tree\n"); + exit(1); + } + } + + if (kvm_enabled()) + kvmppc_init(); +} + +static QEMUMachine bamboo_machine = { + .name = "bamboo", + .desc = "bamboo", + .init = bamboo_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void bamboo_machine_init(void) +{ + qemu_register_machine(&bamboo_machine); +} + +machine_init(bamboo_machine_init); diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c new file mode 100644 index 0000000000..30375c0c41 --- /dev/null +++ b/hw/ppc/ppc_booke.c @@ -0,0 +1,273 @@ +/* + * QEMU PowerPC Booke hardware System Emulator + * + * Copyright (c) 2011 AdaCore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/ppc.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "hw/nvram.h" +#include "qemu/log.h" +#include "hw/loader.h" + + +/* Timer Control Register */ + +#define TCR_WP_SHIFT 30 /* Watchdog Timer Period */ +#define TCR_WP_MASK (0x3 << TCR_WP_SHIFT) +#define TCR_WRC_SHIFT 28 /* Watchdog Timer Reset Control */ +#define TCR_WRC_MASK (0x3 << TCR_WRC_SHIFT) +#define TCR_WIE (1 << 27) /* Watchdog Timer Interrupt Enable */ +#define TCR_DIE (1 << 26) /* Decrementer Interrupt Enable */ +#define TCR_FP_SHIFT 24 /* Fixed-Interval Timer Period */ +#define TCR_FP_MASK (0x3 << TCR_FP_SHIFT) +#define TCR_FIE (1 << 23) /* Fixed-Interval Timer Interrupt Enable */ +#define TCR_ARE (1 << 22) /* Auto-Reload Enable */ + +/* Timer Control Register (e500 specific fields) */ + +#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */ +#define TCR_E500_FPEXT_MASK (0xf << TCR_E500_FPEXT_SHIFT) +#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */ +#define TCR_E500_WPEXT_MASK (0xf << TCR_E500_WPEXT_SHIFT) + +/* Timer Status Register */ + +#define TSR_FIS (1 << 26) /* Fixed-Interval Timer Interrupt Status */ +#define TSR_DIS (1 << 27) /* Decrementer Interrupt Status */ +#define TSR_WRS_SHIFT 28 /* Watchdog Timer Reset Status */ +#define TSR_WRS_MASK (0x3 << TSR_WRS_SHIFT) +#define TSR_WIS (1 << 30) /* Watchdog Timer Interrupt Status */ +#define TSR_ENW (1 << 31) /* Enable Next Watchdog Timer */ + +typedef struct booke_timer_t booke_timer_t; +struct booke_timer_t { + + uint64_t fit_next; + struct QEMUTimer *fit_timer; + + uint64_t wdt_next; + struct QEMUTimer *wdt_timer; + + uint32_t flags; +}; + +static void booke_update_irq(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, + (env->spr[SPR_BOOKE_TSR] & TSR_DIS + && env->spr[SPR_BOOKE_TCR] & TCR_DIE)); + + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, + (env->spr[SPR_BOOKE_TSR] & TSR_WIS + && env->spr[SPR_BOOKE_TCR] & TCR_WIE)); + + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, + (env->spr[SPR_BOOKE_TSR] & TSR_FIS + && env->spr[SPR_BOOKE_TCR] & TCR_FIE)); +} + +/* Return the location of the bit of time base at which the FIT will raise an + interrupt */ +static uint8_t booke_get_fit_target(CPUPPCState *env, ppc_tb_t *tb_env) +{ + uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT; + + if (tb_env->flags & PPC_TIMER_E500) { + /* e500 Fixed-interval timer period extension */ + uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK) + >> TCR_E500_FPEXT_SHIFT; + fp = 63 - (fp | fpext << 2); + } else { + fp = env->fit_period[fp]; + } + + return fp; +} + +/* Return the location of the bit of time base at which the WDT will raise an + interrupt */ +static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env) +{ + uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT; + + if (tb_env->flags & PPC_TIMER_E500) { + /* e500 Watchdog timer period extension */ + uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK) + >> TCR_E500_WPEXT_SHIFT; + wp = 63 - (wp | wpext << 2); + } else { + wp = env->wdt_period[wp]; + } + + return wp; +} + +static void booke_update_fixed_timer(CPUPPCState *env, + uint8_t target_bit, + uint64_t *next, + struct QEMUTimer *timer) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t lapse; + uint64_t tb; + uint64_t period = 1 << (target_bit + 1); + uint64_t now; + + now = qemu_get_clock_ns(vm_clock); + tb = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset); + + lapse = period - ((tb - (1 << target_bit)) & (period - 1)); + + *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq); + + /* XXX: If expire time is now. We can't run the callback because we don't + * have access to it. So we just set the timer one nanosecond later. + */ + + if (*next == now) { + (*next)++; + } + + qemu_mod_timer(timer, *next); +} + +static void booke_decr_cb(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + env->spr[SPR_BOOKE_TSR] |= TSR_DIS; + booke_update_irq(cpu); + + if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) { + /* Auto Reload */ + cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]); + } +} + +static void booke_fit_cb(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + ppc_tb_t *tb_env; + booke_timer_t *booke_timer; + + tb_env = env->tb_env; + booke_timer = tb_env->opaque; + env->spr[SPR_BOOKE_TSR] |= TSR_FIS; + + booke_update_irq(cpu); + + booke_update_fixed_timer(env, + booke_get_fit_target(env, tb_env), + &booke_timer->fit_next, + booke_timer->fit_timer); +} + +static void booke_wdt_cb(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + ppc_tb_t *tb_env; + booke_timer_t *booke_timer; + + tb_env = env->tb_env; + booke_timer = tb_env->opaque; + + /* TODO: There's lots of complicated stuff to do here */ + + booke_update_irq(cpu); + + booke_update_fixed_timer(env, + booke_get_wdt_target(env, tb_env), + &booke_timer->wdt_next, + booke_timer->wdt_timer); +} + +void store_booke_tsr(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->spr[SPR_BOOKE_TSR] &= ~val; + booke_update_irq(cpu); +} + +void store_booke_tcr(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + ppc_tb_t *tb_env = env->tb_env; + booke_timer_t *booke_timer = tb_env->opaque; + + tb_env = env->tb_env; + env->spr[SPR_BOOKE_TCR] = val; + + booke_update_irq(cpu); + + booke_update_fixed_timer(env, + booke_get_fit_target(env, tb_env), + &booke_timer->fit_next, + booke_timer->fit_timer); + + booke_update_fixed_timer(env, + booke_get_wdt_target(env, tb_env), + &booke_timer->wdt_next, + booke_timer->wdt_timer); + +} + +static void ppc_booke_timer_reset_handle(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + env->spr[SPR_BOOKE_TSR] = 0; + env->spr[SPR_BOOKE_TCR] = 0; + + booke_update_irq(cpu); +} + +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) +{ + ppc_tb_t *tb_env; + booke_timer_t *booke_timer; + + tb_env = g_malloc0(sizeof(ppc_tb_t)); + booke_timer = g_malloc0(sizeof(booke_timer_t)); + + cpu->env.tb_env = tb_env; + tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED; + + tb_env->tb_freq = freq; + tb_env->decr_freq = freq; + tb_env->opaque = booke_timer; + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu); + + booke_timer->fit_timer = + qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); + booke_timer->wdt_timer = + qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); + + qemu_register_reset(ppc_booke_timer_reset_handle, cpu); +} diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c new file mode 100644 index 0000000000..2709c660c1 --- /dev/null +++ b/hw/ppc/spapr.c @@ -0,0 +1,963 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * Copyright (c) 2010 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "sysemu/sysemu.h" +#include "hw/hw.h" +#include "elf.h" +#include "net/net.h" +#include "sysemu/blockdev.h" +#include "sysemu/cpus.h" +#include "sysemu/kvm.h" +#include "kvm_ppc.h" + +#include "hw/boards.h" +#include "hw/ppc.h" +#include "hw/loader.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" +#include "hw/spapr_pci.h" +#include "hw/xics.h" +#include "hw/pci/msi.h" + +#include "sysemu/kvm.h" +#include "kvm_ppc.h" +#include "hw/pci/pci.h" + +#include "exec/address-spaces.h" +#include "hw/usb.h" +#include "qemu/config-file.h" + +#include + +/* SLOF memory layout: + * + * SLOF raw image loaded at 0, copies its romfs right below the flat + * device-tree, then position SLOF itself 31M below that + * + * So we set FW_OVERHEAD to 40MB which should account for all of that + * and more + * + * We load our kernel at 4M, leaving space for SLOF initial image + */ +#define FDT_MAX_SIZE 0x10000 +#define RTAS_MAX_SIZE 0x10000 +#define FW_MAX_SIZE 0x400000 +#define FW_FILE_NAME "slof.bin" +#define FW_OVERHEAD 0x2800000 +#define KERNEL_LOAD_ADDR FW_MAX_SIZE + +#define MIN_RMA_SLOF 128UL + +#define TIMEBASE_FREQ 512000000ULL + +#define MAX_CPUS 256 +#define XICS_IRQS 1024 + +#define PHANDLE_XICP 0x00001111 + +#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) + +sPAPREnvironment *spapr; + +int spapr_allocate_irq(int hint, bool lsi) +{ + int irq; + + if (hint) { + irq = hint; + /* FIXME: we should probably check for collisions somehow */ + } else { + irq = spapr->next_irq++; + } + + /* Configure irq type */ + if (!xics_get_qirq(spapr->icp, irq)) { + return 0; + } + + xics_set_irq_type(spapr->icp, irq, lsi); + + return irq; +} + +/* Allocate block of consequtive IRQs, returns a number of the first */ +int spapr_allocate_irq_block(int num, bool lsi) +{ + int first = -1; + int i; + + for (i = 0; i < num; ++i) { + int irq; + + irq = spapr_allocate_irq(0, lsi); + if (!irq) { + return -1; + } + + if (0 == i) { + first = irq; + } + + /* If the above doesn't create a consecutive block then that's + * an internal bug */ + assert(irq == (first + i)); + } + + return first; +} + +static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) +{ + int ret = 0, offset; + CPUPPCState *env; + CPUState *cpu; + char cpu_model[32]; + int smt = kvmppc_smt_threads(); + uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; + + assert(spapr->cpu_model); + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = CPU(ppc_env_get_cpu(env)); + uint32_t associativity[] = {cpu_to_be32(0x5), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(cpu->numa_node), + cpu_to_be32(cpu->cpu_index)}; + + if ((cpu->cpu_index % smt) != 0) { + continue; + } + + snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model, + cpu->cpu_index); + + offset = fdt_path_offset(fdt, cpu_model); + if (offset < 0) { + return offset; + } + + if (nb_numa_nodes > 1) { + ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, + sizeof(associativity)); + if (ret < 0) { + return ret; + } + } + + ret = fdt_setprop(fdt, offset, "ibm,pft-size", + pft_size_prop, sizeof(pft_size_prop)); + if (ret < 0) { + return ret; + } + } + return ret; +} + + +static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, + size_t maxsize) +{ + size_t maxcells = maxsize / sizeof(uint32_t); + int i, j, count; + uint32_t *p = prop; + + for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { + struct ppc_one_seg_page_size *sps = &env->sps.sps[i]; + + if (!sps->page_shift) { + break; + } + for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) { + if (sps->enc[count].page_shift == 0) { + break; + } + } + if ((p - prop) >= (maxcells - 3 - count * 2)) { + break; + } + *(p++) = cpu_to_be32(sps->page_shift); + *(p++) = cpu_to_be32(sps->slb_enc); + *(p++) = cpu_to_be32(count); + for (j = 0; j < count; j++) { + *(p++) = cpu_to_be32(sps->enc[j].page_shift); + *(p++) = cpu_to_be32(sps->enc[j].pte_enc); + } + } + + return (p - prop) * sizeof(uint32_t); +} + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + + +static void *spapr_create_fdt_skel(const char *cpu_model, + hwaddr initrd_base, + hwaddr initrd_size, + hwaddr kernel_size, + const char *boot_device, + const char *kernel_cmdline, + uint32_t epow_irq) +{ + void *fdt; + CPUPPCState *env; + uint32_t start_prop = cpu_to_be32(initrd_base); + uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); + char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" + "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; + char qemu_hypertas_prop[] = "hcall-memop1"; + uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; + uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; + char *modelname; + int i, smt = kvmppc_smt_threads(); + unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; + + fdt = g_malloc0(FDT_MAX_SIZE); + _FDT((fdt_create(fdt, FDT_MAX_SIZE))); + + if (kernel_size) { + _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size))); + } + if (initrd_size) { + _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size))); + } + _FDT((fdt_finish_reservemap(fdt))); + + /* Root node */ + _FDT((fdt_begin_node(fdt, ""))); + _FDT((fdt_property_string(fdt, "device_type", "chrp"))); + _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); + + _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); + + /* /chosen */ + _FDT((fdt_begin_node(fdt, "chosen"))); + + /* Set Form1_affinity */ + _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5)))); + + _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline))); + _FDT((fdt_property(fdt, "linux,initrd-start", + &start_prop, sizeof(start_prop)))); + _FDT((fdt_property(fdt, "linux,initrd-end", + &end_prop, sizeof(end_prop)))); + if (kernel_size) { + uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), + cpu_to_be64(kernel_size) }; + + _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); + } + if (boot_device) { + _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + } + _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width))); + _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height))); + _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth))); + + _FDT((fdt_end_node(fdt))); + + /* cpus */ + _FDT((fdt_begin_node(fdt, "cpus"))); + + _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); + + modelname = g_strdup(cpu_model); + + for (i = 0; i < strlen(modelname); i++) { + modelname[i] = toupper(modelname[i]); + } + + /* This is needed during FDT finalization */ + spapr->cpu_model = g_strdup(modelname); + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + CPUState *cpu = CPU(ppc_env_get_cpu(env)); + int index = cpu->cpu_index; + uint32_t servers_prop[smp_threads]; + uint32_t gservers_prop[smp_threads * 2]; + char *nodename; + uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), + 0xffffffff, 0xffffffff}; + uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; + uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; + uint32_t page_sizes_prop[64]; + size_t page_sizes_prop_size; + + if ((index % smt) != 0) { + continue; + } + + nodename = g_strdup_printf("%s@%x", modelname, index); + + _FDT((fdt_begin_node(fdt, nodename))); + + g_free(nodename); + + _FDT((fdt_property_cell(fdt, "reg", index))); + _FDT((fdt_property_string(fdt, "device_type", "cpu"))); + + _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR]))); + _FDT((fdt_property_cell(fdt, "dcache-block-size", + env->dcache_line_size))); + _FDT((fdt_property_cell(fdt, "icache-block-size", + env->icache_line_size))); + _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); + _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); + _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); + _FDT((fdt_property_string(fdt, "status", "okay"))); + _FDT((fdt_property(fdt, "64-bit", NULL, 0))); + + /* Build interrupt servers and gservers properties */ + for (i = 0; i < smp_threads; i++) { + servers_prop[i] = cpu_to_be32(index + i); + /* Hack, direct the group queues back to cpu 0 */ + gservers_prop[i*2] = cpu_to_be32(index + i); + gservers_prop[i*2 + 1] = 0; + } + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s", + servers_prop, sizeof(servers_prop)))); + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", + gservers_prop, sizeof(gservers_prop)))); + + if (env->mmu_model & POWERPC_MMU_1TSEG) { + _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", + segs, sizeof(segs)))); + } + + /* Advertise VMX/VSX (vector extensions) if available + * 0 / no property == no vector extensions + * 1 == VMX / Altivec available + * 2 == VSX available */ + if (env->insns_flags & PPC_ALTIVEC) { + uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; + + _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx))); + } + + /* Advertise DFP (Decimal Floating Point) if available + * 0 / no property == no DFP + * 1 == DFP available */ + if (env->insns_flags2 & PPC2_DFP) { + _FDT((fdt_property_cell(fdt, "ibm,dfp", 1))); + } + + page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop, + sizeof(page_sizes_prop)); + if (page_sizes_prop_size) { + _FDT((fdt_property(fdt, "ibm,segment-page-sizes", + page_sizes_prop, page_sizes_prop_size))); + } + + _FDT((fdt_end_node(fdt))); + } + + g_free(modelname); + + _FDT((fdt_end_node(fdt))); + + /* RTAS */ + _FDT((fdt_begin_node(fdt, "rtas"))); + + _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, + sizeof(hypertas_prop)))); + _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop, + sizeof(qemu_hypertas_prop)))); + + _FDT((fdt_property(fdt, "ibm,associativity-reference-points", + refpoints, sizeof(refpoints)))); + + _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX))); + + _FDT((fdt_end_node(fdt))); + + /* interrupt controller */ + _FDT((fdt_begin_node(fdt, "interrupt-controller"))); + + _FDT((fdt_property_string(fdt, "device_type", + "PowerPC-External-Interrupt-Presentation"))); + _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"))); + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); + _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges", + interrupt_server_ranges_prop, + sizeof(interrupt_server_ranges_prop)))); + _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); + _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP))); + _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP))); + + _FDT((fdt_end_node(fdt))); + + /* vdevice */ + _FDT((fdt_begin_node(fdt, "vdevice"))); + + _FDT((fdt_property_string(fdt, "device_type", "vdevice"))); + _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice"))); + _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); + _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2))); + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); + + _FDT((fdt_end_node(fdt))); + + /* event-sources */ + spapr_events_fdt_skel(fdt, epow_irq); + + _FDT((fdt_end_node(fdt))); /* close root node */ + _FDT((fdt_finish(fdt))); + + return fdt; +} + +static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) +{ + uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), + cpu_to_be32(0x0), cpu_to_be32(0x0), + cpu_to_be32(0x0)}; + char mem_name[32]; + hwaddr node0_size, mem_start; + uint64_t mem_reg_property[2]; + int i, off; + + /* memory node(s) */ + node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + if (spapr->rma_size > node0_size) { + spapr->rma_size = node0_size; + } + + /* RMA */ + mem_reg_property[0] = 0; + mem_reg_property[1] = cpu_to_be64(spapr->rma_size); + off = fdt_add_subnode(fdt, 0, "memory@0"); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + + /* RAM: Node 0 */ + if (node0_size > spapr->rma_size) { + mem_reg_property[0] = cpu_to_be64(spapr->rma_size); + mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size); + + sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + } + + /* RAM: Node 1 and beyond */ + mem_start = node0_size; + for (i = 1; i < nb_numa_nodes; i++) { + mem_reg_property[0] = cpu_to_be64(mem_start); + mem_reg_property[1] = cpu_to_be64(node_mem[i]); + associativity[3] = associativity[4] = cpu_to_be32(i); + sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + mem_start += node_mem[i]; + } + + return 0; +} + +static void spapr_finalize_fdt(sPAPREnvironment *spapr, + hwaddr fdt_addr, + hwaddr rtas_addr, + hwaddr rtas_size) +{ + int ret; + void *fdt; + sPAPRPHBState *phb; + + fdt = g_malloc(FDT_MAX_SIZE); + + /* open out the base tree into a temp buffer for the final tweaks */ + _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); + + ret = spapr_populate_memory(spapr, fdt); + if (ret < 0) { + fprintf(stderr, "couldn't setup memory nodes in fdt\n"); + exit(1); + } + + ret = spapr_populate_vdevice(spapr->vio_bus, fdt); + if (ret < 0) { + fprintf(stderr, "couldn't setup vio devices in fdt\n"); + exit(1); + } + + QLIST_FOREACH(phb, &spapr->phbs, list) { + ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt); + } + + if (ret < 0) { + fprintf(stderr, "couldn't setup PCI devices in fdt\n"); + exit(1); + } + + /* RTAS */ + ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); + if (ret < 0) { + fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); + } + + /* Advertise NUMA via ibm,associativity */ + ret = spapr_fixup_cpu_dt(fdt, spapr); + if (ret < 0) { + fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); + } + + if (!spapr->has_graphics) { + spapr_populate_chosen_stdout(fdt, spapr->vio_bus); + } + + _FDT((fdt_pack(fdt))); + + if (fdt_totalsize(fdt) > FDT_MAX_SIZE) { + hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n", + fdt_totalsize(fdt), FDT_MAX_SIZE); + exit(1); + } + + cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); + + g_free(fdt); +} + +static uint64_t translate_kernel_address(void *opaque, uint64_t addr) +{ + return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; +} + +static void emulate_spapr_hypercall(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + + if (msr_pr) { + hcall_dprintf("Hypercall made with MSR[PR]=1\n"); + env->gpr[3] = H_PRIVILEGE; + } else { + env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]); + } +} + +static void spapr_reset_htab(sPAPREnvironment *spapr) +{ + long shift; + + /* allocate hash page table. For now we always make this 16mb, + * later we should probably make it scale to the size of guest + * RAM */ + + shift = kvmppc_reset_htab(spapr->htab_shift); + + if (shift > 0) { + /* Kernel handles htab, we don't need to allocate one */ + spapr->htab_shift = shift; + } else { + if (!spapr->htab) { + /* Allocate an htab if we don't yet have one */ + spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr)); + } + + /* And clear it */ + memset(spapr->htab, 0, HTAB_SIZE(spapr)); + } + + /* Update the RMA size if necessary */ + if (spapr->vrma_adjust) { + spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); + } +} + +static void ppc_spapr_reset(void) +{ + /* Reset the hash table & recalc the RMA */ + spapr_reset_htab(spapr); + + qemu_devices_reset(); + + /* Load the fdt */ + spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, + spapr->rtas_size); + + /* Set up the entry state */ + first_cpu->gpr[3] = spapr->fdt_addr; + first_cpu->gpr[5] = 0; + first_cpu->halted = 0; + first_cpu->nip = spapr->entry_point; + +} + +static void spapr_cpu_reset(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + + /* All CPUs start halted. CPU0 is unhalted from the machine level + * reset code and the rest are explicitly started up by the guest + * using an RTAS call */ + env->halted = 1; + + env->spr[SPR_HIOR] = 0; + + env->external_htab = spapr->htab; + env->htab_base = -1; + env->htab_mask = HTAB_SIZE(spapr) - 1; + env->spr[SPR_SDR1] = (unsigned long)spapr->htab | + (spapr->htab_shift - 18); +} + +static void spapr_create_nvram(sPAPREnvironment *spapr) +{ + QemuOpts *machine_opts; + DeviceState *dev; + + dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + const char *drivename; + + drivename = qemu_opt_get(machine_opts, "nvram"); + if (drivename) { + BlockDriverState *bs; + + bs = bdrv_find(drivename); + if (!bs) { + fprintf(stderr, "No such block device \"%s\" for nvram\n", + drivename); + exit(1); + } + qdev_prop_set_drive_nofail(dev, "drive", bs); + } + } + + qdev_init_nofail(dev); + + spapr->nvram = (struct sPAPRNVRAM *)dev; +} + +/* Returns whether we want to use VGA or not */ +static int spapr_vga_init(PCIBus *pci_bus) +{ + switch (vga_interface_type) { + case VGA_NONE: + case VGA_STD: + return pci_vga_init(pci_bus) != NULL; + default: + fprintf(stderr, "This vga model is not supported," + "currently it only supports -vga std\n"); + exit(0); + break; + } +} + +/* pSeries LPAR / sPAPR hardware init */ +static void ppc_spapr_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + PowerPCCPU *cpu; + CPUPPCState *env; + PCIHostState *phb; + int i; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + hwaddr rma_alloc_size; + uint32_t initrd_base = 0; + long kernel_size = 0, initrd_size = 0; + long load_limit, rtas_limit, fw_size; + char *filename; + + msi_supported = true; + + spapr = g_malloc0(sizeof(*spapr)); + QLIST_INIT(&spapr->phbs); + + cpu_ppc_hypercall = emulate_spapr_hypercall; + + /* Allocate RMA if necessary */ + rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem); + + if (rma_alloc_size == -1) { + hw_error("qemu: Unable to create RMA\n"); + exit(1); + } + + if (rma_alloc_size && (rma_alloc_size < ram_size)) { + spapr->rma_size = rma_alloc_size; + } else { + spapr->rma_size = ram_size; + + /* With KVM, we don't actually know whether KVM supports an + * unbounded RMA (PR KVM) or is limited by the hash table size + * (HV KVM using VRMA), so we always assume the latter + * + * In that case, we also limit the initial allocations for RTAS + * etc... to 256M since we have no way to know what the VRMA size + * is going to be as it depends on the size of the hash table + * isn't determined yet. + */ + if (kvm_enabled()) { + spapr->vrma_adjust = 1; + spapr->rma_size = MIN(spapr->rma_size, 0x10000000); + } + } + + /* We place the device tree and RTAS just below either the top of the RMA, + * or just below 2GB, whichever is lowere, so that it can be + * processed with 32-bit real mode code if necessary */ + rtas_limit = MIN(spapr->rma_size, 0x80000000); + spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; + spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; + load_limit = spapr->fdt_addr - FW_OVERHEAD; + + /* We aim for a hash table of size 1/128 the size of RAM. The + * normal rule of thumb is 1/64 the size of RAM, but that's much + * more than needed for the Linux guests we support. */ + spapr->htab_shift = 18; /* Minimum architected size */ + while (spapr->htab_shift <= 46) { + if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) { + break; + } + spapr->htab_shift++; + } + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = kvm_enabled() ? "host" : "POWER7"; + } + for (i = 0; i < smp_cpus; i++) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); + exit(1); + } + env = &cpu->env; + + /* Set time-base frequency to 512 MHz */ + cpu_ppc_tb_init(env, TIMEBASE_FREQ); + + /* PAPR always has exception vectors in RAM not ROM */ + env->hreset_excp_prefix = 0; + + /* Tell KVM that we're in PAPR mode */ + if (kvm_enabled()) { + kvmppc_set_papr(cpu); + } + + qemu_register_reset(spapr_cpu_reset, cpu); + } + + /* allocate RAM */ + spapr->ram_limit = ram_size; + if (spapr->ram_limit > rma_alloc_size) { + ram_addr_t nonrma_base = rma_alloc_size; + ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size; + + memory_region_init_ram(ram, "ppc_spapr.ram", nonrma_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(sysmem, nonrma_base, ram); + } + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); + spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, + rtas_limit - spapr->rtas_addr); + if (spapr->rtas_size < 0) { + hw_error("qemu: could not load LPAR rtas '%s'\n", filename); + exit(1); + } + if (spapr->rtas_size > RTAS_MAX_SIZE) { + hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n", + spapr->rtas_size, RTAS_MAX_SIZE); + exit(1); + } + g_free(filename); + + + /* Set up Interrupt Controller */ + spapr->icp = xics_system_init(XICS_IRQS); + spapr->next_irq = XICS_IRQ_BASE; + + /* Set up EPOW events infrastructure */ + spapr_events_init(spapr); + + /* Set up IOMMU */ + spapr_iommu_init(); + + /* Set up VIO bus */ + spapr->vio_bus = spapr_vio_bus_init(); + + for (i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + spapr_vty_create(spapr->vio_bus, serial_hds[i]); + } + } + + /* We always have at least the nvram device on VIO */ + spapr_create_nvram(spapr); + + /* Set up PCI */ + spapr_pci_rtas_init(); + + phb = spapr_create_phb(spapr, 0, "pci"); + + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!nd->model) { + nd->model = g_strdup("ibmveth"); + } + + if (strcmp(nd->model, "ibmveth") == 0) { + spapr_vlan_create(spapr->vio_bus, nd); + } else { + pci_nic_init_nofail(&nd_table[i], nd->model, NULL); + } + } + + for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) { + spapr_vscsi_create(spapr->vio_bus); + } + + /* Graphics */ + if (spapr_vga_init(phb->bus)) { + spapr->has_graphics = true; + } + + if (usb_enabled(spapr->has_graphics)) { + pci_create_simple(phb->bus, -1, "pci-ohci"); + if (spapr->has_graphics) { + usbdevice_create("keyboard"); + usbdevice_create("mouse"); + } + } + + if (spapr->rma_size < (MIN_RMA_SLOF << 20)) { + fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " + "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); + exit(1); + } + + if (kernel_filename) { + uint64_t lowaddr = 0; + + kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, + NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + load_limit - KERNEL_LOAD_ADDR); + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* load initrd */ + if (initrd_filename) { + /* Try to locate the initrd in the gap between the kernel + * and the firmware. Add a bit of space just in case + */ + initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + load_limit - initrd_base); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + } + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); + fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); + if (fw_size < 0) { + hw_error("qemu: could not load LPAR rtas '%s'\n", filename); + exit(1); + } + g_free(filename); + + spapr->entry_point = 0x100; + + /* Prepare the device tree */ + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, + initrd_base, initrd_size, + kernel_size, + boot_device, kernel_cmdline, + spapr->epow_irq); + assert(spapr->fdt_skel != NULL); +} + +static QEMUMachine spapr_machine = { + .name = "pseries", + .desc = "pSeries Logical Partition (PAPR compliant)", + .init = ppc_spapr_init, + .reset = ppc_spapr_reset, + .block_default_type = IF_SCSI, + .max_cpus = MAX_CPUS, + .no_parallel = 1, + .boot_order = NULL, +}; + +static void spapr_machine_init(void) +{ + qemu_register_machine(&spapr_machine); +} + +machine_init(spapr_machine_init); diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c new file mode 100644 index 0000000000..41eab1697c --- /dev/null +++ b/hw/ppc/virtex_ml507.c @@ -0,0 +1,274 @@ +/* + * Model of Xilinx Virtex5 ML507 PPC-440 refdesign. + * + * Copyright (c) 2010 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/serial.h" +#include "hw/flash.h" +#include "sysemu/sysemu.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "sysemu/device_tree.h" +#include "hw/loader.h" +#include "elf.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" + +#include "hw/ppc.h" +#include "hw/ppc4xx.h" +#include "hw/ppc405.h" + +#include "sysemu/blockdev.h" +#include "hw/xilinx.h" + +#define EPAPR_MAGIC (0x45504150) +#define FLASH_SIZE (16 * 1024 * 1024) + +static struct boot_info +{ + uint32_t bootstrap_pc; + uint32_t cmdline; + uint32_t fdt; + uint32_t ima_size; + void *vfdt; +} boot_info; + +/* Create reset TLB entries for BookE, spanning the 32bit addr space. */ +static void mmubooke_create_initial_mapping(CPUPPCState *env, + target_ulong va, + hwaddr pa) +{ + ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; + + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0x80000000 */ + tlb->EPN = va & TARGET_PAGE_MASK; + tlb->RPN = pa & TARGET_PAGE_MASK; + tlb->PID = 0; + + tlb = &env->tlb.tlbe[1]; + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0xffffffff */ + tlb->EPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->RPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->PID = 0; +} + +static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size, + int do_init, + const char *cpu_model, + uint32_t sysclk) +{ + PowerPCCPU *cpu; + CPUPPCState *env; + qemu_irq *irqs; + + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to initialize CPU!\n"); + exit(1); + } + env = &cpu->env; + + ppc_booke_timers_init(cpu, sysclk, 0/* no flags */); + + ppc_dcr_init(env, NULL, NULL); + + /* interrupt controller */ + irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; + ppcuic_init(env, irqs, 0x0C0, 0, 1); + return cpu; +} + +static void main_cpu_reset(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + struct boot_info *bi = env->load_info; + + cpu_reset(CPU(cpu)); + /* Linux Kernel Parameters (passing device tree): + * r3: pointer to the fdt + * r4: 0 + * r5: 0 + * r6: epapr magic + * r7: size of IMA in bytes + * r8: 0 + * r9: 0 + */ + env->gpr[1] = (16<<20) - 8; + /* Provide a device-tree. */ + env->gpr[3] = bi->fdt; + env->nip = bi->bootstrap_pc; + + /* Create a mapping for the kernel. */ + mmubooke_create_initial_mapping(env, 0, 0); + env->gpr[6] = tswap32(EPAPR_MAGIC); + env->gpr[7] = bi->ima_size; +} + +#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" +static int xilinx_load_device_tree(hwaddr addr, + uint32_t ramsize, + hwaddr initrd_base, + hwaddr initrd_size, + const char *kernel_cmdline) +{ + char *path; + int fdt_size; +#ifdef CONFIG_FDT + void *fdt; + int r; + + /* Try the local "ppc.dtb" override. */ + fdt = load_device_tree("ppc.dtb", &fdt_size); + if (!fdt) { + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + if (path) { + fdt = load_device_tree(path, &fdt_size); + g_free(path); + } + if (!fdt) { + return 0; + } + } + + r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + if (r < 0) + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + cpu_physical_memory_write (addr, (void *)fdt, fdt_size); +#else + /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob + to the kernel. */ + fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000); + if (fdt_size < 0) { + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + if (path) { + fdt_size = load_image_targphys(path, addr, 0x10000); + g_free(path); + } + } + + if (kernel_cmdline) { + fprintf(stderr, + "Warning: missing libfdt, cannot pass cmdline to kernel!\n"); + } +#endif + return fdt_size; +} + +static void virtex_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + MemoryRegion *address_space_mem = get_system_memory(); + DeviceState *dev; + PowerPCCPU *cpu; + CPUPPCState *env; + hwaddr ram_base = 0; + DriveInfo *dinfo; + MemoryRegion *phys_ram = g_new(MemoryRegion, 1); + qemu_irq irq[32], *cpu_irq; + int kernel_size; + int i; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "440-Xilinx"; + } + + cpu = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000); + env = &cpu->env; + qemu_register_reset(main_cpu_reset, cpu); + + memory_region_init_ram(phys_ram, "ram", ram_size); + vmstate_register_ram_global(phys_ram); + memory_region_add_subregion(address_space_mem, ram_base, phys_ram); + + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + FLASH_SIZE >> 16, + 1, 0x89, 0x18, 0x0000, 0x0, 1); + + cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT]; + dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(dev, i); + } + + serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200, + serial_hds[0], DEVICE_LITTLE_ENDIAN); + + /* 2 timers at irq 2 @ 62 Mhz. */ + xilinx_timer_create(0x83c00000, irq[3], 0, 62 * 1000000); + + if (kernel_filename) { + uint64_t entry, low, high; + hwaddr boot_offset; + + /* Boots a kernel elf binary. */ + kernel_size = load_elf(kernel_filename, NULL, NULL, + &entry, &low, &high, 1, ELF_MACHINE, 0); + boot_info.bootstrap_pc = entry & 0x00ffffff; + + if (kernel_size < 0) { + boot_offset = 0x1200000; + /* If we failed loading ELF's try a raw image. */ + kernel_size = load_image_targphys(kernel_filename, + boot_offset, + ram_size); + boot_info.bootstrap_pc = boot_offset; + high = boot_info.bootstrap_pc + kernel_size + 8192; + } + + boot_info.ima_size = kernel_size; + + /* Provide a device-tree. */ + boot_info.fdt = high + (8192 * 2); + boot_info.fdt &= ~8191; + xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline); + } + env->load_info = &boot_info; +} + +static QEMUMachine virtex_machine = { + .name = "virtex-ml507", + .desc = "Xilinx Virtex ML507 reference design", + .init = virtex_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void virtex_machine_init(void) +{ + qemu_register_machine(&virtex_machine); +} + +machine_init(virtex_machine_init); diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c deleted file mode 100644 index ba443cf8ef..0000000000 --- a/hw/ppc405_boards.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * QEMU PowerPC 405 evaluation boards emulation - * - * Copyright (c) 2007 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/ppc.h" -#include "hw/ppc405.h" -#include "hw/nvram.h" -#include "hw/flash.h" -#include "sysemu/sysemu.h" -#include "block/block.h" -#include "hw/boards.h" -#include "qemu/log.h" -#include "hw/loader.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#define BIOS_FILENAME "ppc405_rom.bin" -#define BIOS_SIZE (2048 * 1024) - -#define KERNEL_LOAD_ADDR 0x00000000 -#define INITRD_LOAD_ADDR 0x01800000 - -#define USE_FLASH_BIOS - -#define DEBUG_BOARD_INIT - -/*****************************************************************************/ -/* PPC405EP reference board (IBM) */ -/* Standalone board with: - * - PowerPC 405EP CPU - * - SDRAM (0x00000000) - * - Flash (0xFFF80000) - * - SRAM (0xFFF00000) - * - NVRAM (0xF0000000) - * - FPGA (0xF0300000) - */ -typedef struct ref405ep_fpga_t ref405ep_fpga_t; -struct ref405ep_fpga_t { - uint8_t reg0; - uint8_t reg1; -}; - -static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr) -{ - ref405ep_fpga_t *fpga; - uint32_t ret; - - fpga = opaque; - switch (addr) { - case 0x0: - ret = fpga->reg0; - break; - case 0x1: - ret = fpga->reg1; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void ref405ep_fpga_writeb (void *opaque, - hwaddr addr, uint32_t value) -{ - ref405ep_fpga_t *fpga; - - fpga = opaque; - switch (addr) { - case 0x0: - /* Read only */ - break; - case 0x1: - fpga->reg1 = value; - break; - default: - break; - } -} - -static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr) -{ - uint32_t ret; - - ret = ref405ep_fpga_readb(opaque, addr) << 8; - ret |= ref405ep_fpga_readb(opaque, addr + 1); - - return ret; -} - -static void ref405ep_fpga_writew (void *opaque, - hwaddr addr, uint32_t value) -{ - ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF); - ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF); -} - -static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr) -{ - uint32_t ret; - - ret = ref405ep_fpga_readb(opaque, addr) << 24; - ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16; - ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8; - ret |= ref405ep_fpga_readb(opaque, addr + 3); - - return ret; -} - -static void ref405ep_fpga_writel (void *opaque, - hwaddr addr, uint32_t value) -{ - ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF); - ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF); - ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF); - ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF); -} - -static const MemoryRegionOps ref405ep_fpga_ops = { - .old_mmio = { - .read = { - ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl, - }, - .write = { - ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ref405ep_fpga_reset (void *opaque) -{ - ref405ep_fpga_t *fpga; - - fpga = opaque; - fpga->reg0 = 0x00; - fpga->reg1 = 0x0F; -} - -static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base) -{ - ref405ep_fpga_t *fpga; - MemoryRegion *fpga_memory = g_new(MemoryRegion, 1); - - fpga = g_malloc0(sizeof(ref405ep_fpga_t)); - memory_region_init_io(fpga_memory, &ref405ep_fpga_ops, fpga, - "fpga", 0x00000100); - memory_region_add_subregion(sysmem, base, fpga_memory); - qemu_register_reset(&ref405ep_fpga_reset, fpga); -} - -static void ref405ep_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - char *filename; - ppc4xx_bd_info_t bd; - CPUPPCState *env; - qemu_irq *pic; - MemoryRegion *bios; - MemoryRegion *sram = g_new(MemoryRegion, 1); - ram_addr_t bdloc; - MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories)); - hwaddr ram_bases[2], ram_sizes[2]; - target_ulong sram_size; - long bios_size; - //int phy_addr = 0; - //static int phy_addr = 1; - target_ulong kernel_base, initrd_base; - long kernel_size, initrd_size; - int linux_boot; - int fl_idx, fl_sectors, len; - DriveInfo *dinfo; - MemoryRegion *sysmem = get_system_memory(); - - /* XXX: fix this */ - memory_region_init_ram(&ram_memories[0], "ef405ep.ram", 0x08000000); - vmstate_register_ram_global(&ram_memories[0]); - ram_bases[0] = 0; - ram_sizes[0] = 0x08000000; - memory_region_init(&ram_memories[1], "ef405ep.ram1", 0); - ram_bases[1] = 0x00000000; - ram_sizes[1] = 0x00000000; - ram_size = 128 * 1024 * 1024; -#ifdef DEBUG_BOARD_INIT - printf("%s: register cpu\n", __func__); -#endif - env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, - 33333333, &pic, kernel_filename == NULL ? 0 : 1); - /* allocate SRAM */ - sram_size = 512 * 1024; - memory_region_init_ram(sram, "ef405ep.sram", sram_size); - vmstate_register_ram_global(sram); - memory_region_add_subregion(sysmem, 0xFFF00000, sram); - /* allocate and load BIOS */ -#ifdef DEBUG_BOARD_INIT - printf("%s: register BIOS\n", __func__); -#endif - fl_idx = 0; -#ifdef USE_FLASH_BIOS - dinfo = drive_get(IF_PFLASH, 0, fl_idx); - if (dinfo) { - bios_size = bdrv_getlength(dinfo->bdrv); - fl_sectors = (bios_size + 65535) >> 16; -#ifdef DEBUG_BOARD_INIT - printf("Register parallel flash %d size %lx" - " at addr %lx '%s' %d\n", - fl_idx, bios_size, -bios_size, - bdrv_get_device_name(dinfo->bdrv), fl_sectors); -#endif - pflash_cfi02_register((uint32_t)(-bios_size), - NULL, "ef405ep.bios", bios_size, - dinfo->bdrv, 65536, fl_sectors, 1, - 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, - 1); - fl_idx++; - } else -#endif - { -#ifdef DEBUG_BOARD_INIT - printf("Load BIOS from file\n"); -#endif - bios = g_new(MemoryRegion, 1); - memory_region_init_ram(bios, "ef405ep.bios", BIOS_SIZE); - vmstate_register_ram_global(bios); - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = load_image(filename, memory_region_get_ram_ptr(bios)); - g_free(filename); - } else { - bios_size = -1; - } - if (bios_size < 0 || bios_size > BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", - bios_name); - exit(1); - } - bios_size = (bios_size + 0xfff) & ~0xfff; - memory_region_set_readonly(bios, true); - memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios); - } - /* Register FPGA */ -#ifdef DEBUG_BOARD_INIT - printf("%s: register FPGA\n", __func__); -#endif - ref405ep_fpga_init(sysmem, 0xF0300000); - /* Register NVRAM */ -#ifdef DEBUG_BOARD_INIT - printf("%s: register NVRAM\n", __func__); -#endif - m48t59_init(NULL, 0xF0000000, 0, 8192, 8); - /* Load kernel */ - linux_boot = (kernel_filename != NULL); - if (linux_boot) { -#ifdef DEBUG_BOARD_INIT - printf("%s: load kernel\n", __func__); -#endif - memset(&bd, 0, sizeof(bd)); - bd.bi_memstart = 0x00000000; - bd.bi_memsize = ram_size; - bd.bi_flashstart = -bios_size; - bd.bi_flashsize = -bios_size; - bd.bi_flashoffset = 0; - bd.bi_sramstart = 0xFFF00000; - bd.bi_sramsize = sram_size; - bd.bi_bootflags = 0; - bd.bi_intfreq = 133333333; - bd.bi_busfreq = 33333333; - bd.bi_baudrate = 115200; - bd.bi_s_version[0] = 'Q'; - bd.bi_s_version[1] = 'M'; - bd.bi_s_version[2] = 'U'; - bd.bi_s_version[3] = '\0'; - bd.bi_r_version[0] = 'Q'; - bd.bi_r_version[1] = 'E'; - bd.bi_r_version[2] = 'M'; - bd.bi_r_version[3] = 'U'; - bd.bi_r_version[4] = '\0'; - bd.bi_procfreq = 133333333; - bd.bi_plb_busfreq = 33333333; - bd.bi_pci_busfreq = 33333333; - bd.bi_opbfreq = 33333333; - bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001); - env->gpr[3] = bdloc; - kernel_base = KERNEL_LOAD_ADDR; - /* now we can load the kernel */ - kernel_size = load_image_targphys(kernel_filename, kernel_base, - ram_size - kernel_base); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - printf("Load kernel size %ld at " TARGET_FMT_lx, - kernel_size, kernel_base); - /* load initrd */ - if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - ram_size - initrd_base); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_base = 0; - initrd_size = 0; - } - env->gpr[4] = initrd_base; - env->gpr[5] = initrd_size; - if (kernel_cmdline != NULL) { - len = strlen(kernel_cmdline); - bdloc -= ((len + 255) & ~255); - cpu_physical_memory_write(bdloc, (void *)kernel_cmdline, len + 1); - env->gpr[6] = bdloc; - env->gpr[7] = bdloc + len; - } else { - env->gpr[6] = 0; - env->gpr[7] = 0; - } - env->nip = KERNEL_LOAD_ADDR; - } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; - bdloc = 0; - } -#ifdef DEBUG_BOARD_INIT - printf("%s: Done\n", __func__); -#endif - printf("bdloc " RAM_ADDR_FMT "\n", bdloc); -} - -static QEMUMachine ref405ep_machine = { - .name = "ref405ep", - .desc = "ref405ep", - .init = ref405ep_init, - DEFAULT_MACHINE_OPTIONS, -}; - -/*****************************************************************************/ -/* AMCC Taihu evaluation board */ -/* - PowerPC 405EP processor - * - SDRAM 128 MB at 0x00000000 - * - Boot flash 2 MB at 0xFFE00000 - * - Application flash 32 MB at 0xFC000000 - * - 2 serial ports - * - 2 ethernet PHY - * - 1 USB 1.1 device 0x50000000 - * - 1 LCD display 0x50100000 - * - 1 CPLD 0x50100000 - * - 1 I2C EEPROM - * - 1 I2C thermal sensor - * - a set of LEDs - * - bit-bang SPI port using GPIOs - * - 1 EBC interface connector 0 0x50200000 - * - 1 cardbus controller + expansion slot. - * - 1 PCI expansion slot. - */ -typedef struct taihu_cpld_t taihu_cpld_t; -struct taihu_cpld_t { - uint8_t reg0; - uint8_t reg1; -}; - -static uint32_t taihu_cpld_readb (void *opaque, hwaddr addr) -{ - taihu_cpld_t *cpld; - uint32_t ret; - - cpld = opaque; - switch (addr) { - case 0x0: - ret = cpld->reg0; - break; - case 0x1: - ret = cpld->reg1; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void taihu_cpld_writeb (void *opaque, - hwaddr addr, uint32_t value) -{ - taihu_cpld_t *cpld; - - cpld = opaque; - switch (addr) { - case 0x0: - /* Read only */ - break; - case 0x1: - cpld->reg1 = value; - break; - default: - break; - } -} - -static uint32_t taihu_cpld_readw (void *opaque, hwaddr addr) -{ - uint32_t ret; - - ret = taihu_cpld_readb(opaque, addr) << 8; - ret |= taihu_cpld_readb(opaque, addr + 1); - - return ret; -} - -static void taihu_cpld_writew (void *opaque, - hwaddr addr, uint32_t value) -{ - taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF); - taihu_cpld_writeb(opaque, addr + 1, value & 0xFF); -} - -static uint32_t taihu_cpld_readl (void *opaque, hwaddr addr) -{ - uint32_t ret; - - ret = taihu_cpld_readb(opaque, addr) << 24; - ret |= taihu_cpld_readb(opaque, addr + 1) << 16; - ret |= taihu_cpld_readb(opaque, addr + 2) << 8; - ret |= taihu_cpld_readb(opaque, addr + 3); - - return ret; -} - -static void taihu_cpld_writel (void *opaque, - hwaddr addr, uint32_t value) -{ - taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF); - taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF); - taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF); - taihu_cpld_writeb(opaque, addr + 3, value & 0xFF); -} - -static const MemoryRegionOps taihu_cpld_ops = { - .old_mmio = { - .read = { taihu_cpld_readb, taihu_cpld_readw, taihu_cpld_readl, }, - .write = { taihu_cpld_writeb, taihu_cpld_writew, taihu_cpld_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void taihu_cpld_reset (void *opaque) -{ - taihu_cpld_t *cpld; - - cpld = opaque; - cpld->reg0 = 0x01; - cpld->reg1 = 0x80; -} - -static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base) -{ - taihu_cpld_t *cpld; - MemoryRegion *cpld_memory = g_new(MemoryRegion, 1); - - cpld = g_malloc0(sizeof(taihu_cpld_t)); - memory_region_init_io(cpld_memory, &taihu_cpld_ops, cpld, "cpld", 0x100); - memory_region_add_subregion(sysmem, base, cpld_memory); - qemu_register_reset(&taihu_cpld_reset, cpld); -} - -static void taihu_405ep_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *kernel_filename = args->kernel_filename; - const char *initrd_filename = args->initrd_filename; - char *filename; - qemu_irq *pic; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *bios; - MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories)); - hwaddr ram_bases[2], ram_sizes[2]; - long bios_size; - target_ulong kernel_base, initrd_base; - long kernel_size, initrd_size; - int linux_boot; - int fl_idx, fl_sectors; - DriveInfo *dinfo; - - /* RAM is soldered to the board so the size cannot be changed */ - memory_region_init_ram(&ram_memories[0], - "taihu_405ep.ram-0", 0x04000000); - vmstate_register_ram_global(&ram_memories[0]); - ram_bases[0] = 0; - ram_sizes[0] = 0x04000000; - memory_region_init_ram(&ram_memories[1], - "taihu_405ep.ram-1", 0x04000000); - vmstate_register_ram_global(&ram_memories[1]); - ram_bases[1] = 0x04000000; - ram_sizes[1] = 0x04000000; - ram_size = 0x08000000; -#ifdef DEBUG_BOARD_INIT - printf("%s: register cpu\n", __func__); -#endif - ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, - 33333333, &pic, kernel_filename == NULL ? 0 : 1); - /* allocate and load BIOS */ -#ifdef DEBUG_BOARD_INIT - printf("%s: register BIOS\n", __func__); -#endif - fl_idx = 0; -#if defined(USE_FLASH_BIOS) - dinfo = drive_get(IF_PFLASH, 0, fl_idx); - if (dinfo) { - bios_size = bdrv_getlength(dinfo->bdrv); - /* XXX: should check that size is 2MB */ - // bios_size = 2 * 1024 * 1024; - fl_sectors = (bios_size + 65535) >> 16; -#ifdef DEBUG_BOARD_INIT - printf("Register parallel flash %d size %lx" - " at addr %lx '%s' %d\n", - fl_idx, bios_size, -bios_size, - bdrv_get_device_name(dinfo->bdrv), fl_sectors); -#endif - pflash_cfi02_register((uint32_t)(-bios_size), - NULL, "taihu_405ep.bios", bios_size, - dinfo->bdrv, 65536, fl_sectors, 1, - 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, - 1); - fl_idx++; - } else -#endif - { -#ifdef DEBUG_BOARD_INIT - printf("Load BIOS from file\n"); -#endif - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - bios = g_new(MemoryRegion, 1); - memory_region_init_ram(bios, "taihu_405ep.bios", BIOS_SIZE); - vmstate_register_ram_global(bios); - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = load_image(filename, memory_region_get_ram_ptr(bios)); - g_free(filename); - } else { - bios_size = -1; - } - if (bios_size < 0 || bios_size > BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", - bios_name); - exit(1); - } - bios_size = (bios_size + 0xfff) & ~0xfff; - memory_region_set_readonly(bios, true); - memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios); - } - /* Register Linux flash */ - dinfo = drive_get(IF_PFLASH, 0, fl_idx); - if (dinfo) { - bios_size = bdrv_getlength(dinfo->bdrv); - /* XXX: should check that size is 32MB */ - bios_size = 32 * 1024 * 1024; - fl_sectors = (bios_size + 65535) >> 16; -#ifdef DEBUG_BOARD_INIT - printf("Register parallel flash %d size %lx" - " at addr " TARGET_FMT_lx " '%s'\n", - fl_idx, bios_size, (target_ulong)0xfc000000, - bdrv_get_device_name(dinfo->bdrv)); -#endif - pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size, - dinfo->bdrv, 65536, fl_sectors, 1, - 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, - 1); - fl_idx++; - } - /* Register CLPD & LCD display */ -#ifdef DEBUG_BOARD_INIT - printf("%s: register CPLD\n", __func__); -#endif - taihu_cpld_init(sysmem, 0x50100000); - /* Load kernel */ - linux_boot = (kernel_filename != NULL); - if (linux_boot) { -#ifdef DEBUG_BOARD_INIT - printf("%s: load kernel\n", __func__); -#endif - kernel_base = KERNEL_LOAD_ADDR; - /* now we can load the kernel */ - kernel_size = load_image_targphys(kernel_filename, kernel_base, - ram_size - kernel_base); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - /* load initrd */ - if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - ram_size - initrd_base); - if (initrd_size < 0) { - fprintf(stderr, - "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_base = 0; - initrd_size = 0; - } - } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; - } -#ifdef DEBUG_BOARD_INIT - printf("%s: Done\n", __func__); -#endif -} - -static QEMUMachine taihu_machine = { - .name = "taihu", - .desc = "taihu", - .init = taihu_405ep_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void ppc405_machine_init(void) -{ - qemu_register_machine(&ref405ep_machine); - qemu_register_machine(&taihu_machine); -} - -machine_init(ppc405_machine_init); diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c deleted file mode 100644 index 8465f6dcd4..0000000000 --- a/hw/ppc405_uc.c +++ /dev/null @@ -1,2548 +0,0 @@ -/* - * QEMU PowerPC 405 embedded processors emulation - * - * Copyright (c) 2007 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/ppc.h" -#include "hw/ppc405.h" -#include "hw/serial.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "qemu/log.h" -#include "exec/address-spaces.h" - -#define DEBUG_OPBA -#define DEBUG_SDRAM -#define DEBUG_GPIO -#define DEBUG_SERIAL -#define DEBUG_OCM -//#define DEBUG_I2C -#define DEBUG_GPT -#define DEBUG_MAL -#define DEBUG_CLOCKS -//#define DEBUG_CLOCKS_LL - -ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd, - uint32_t flags) -{ - ram_addr_t bdloc; - int i, n; - - /* We put the bd structure at the top of memory */ - if (bd->bi_memsize >= 0x01000000UL) - bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t); - else - bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t); - stl_be_phys(bdloc + 0x00, bd->bi_memstart); - stl_be_phys(bdloc + 0x04, bd->bi_memsize); - stl_be_phys(bdloc + 0x08, bd->bi_flashstart); - stl_be_phys(bdloc + 0x0C, bd->bi_flashsize); - stl_be_phys(bdloc + 0x10, bd->bi_flashoffset); - stl_be_phys(bdloc + 0x14, bd->bi_sramstart); - stl_be_phys(bdloc + 0x18, bd->bi_sramsize); - stl_be_phys(bdloc + 0x1C, bd->bi_bootflags); - stl_be_phys(bdloc + 0x20, bd->bi_ipaddr); - for (i = 0; i < 6; i++) { - stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]); - } - stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed); - stl_be_phys(bdloc + 0x2C, bd->bi_intfreq); - stl_be_phys(bdloc + 0x30, bd->bi_busfreq); - stl_be_phys(bdloc + 0x34, bd->bi_baudrate); - for (i = 0; i < 4; i++) { - stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]); - } - for (i = 0; i < 32; i++) { - stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]); - } - stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq); - stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq); - for (i = 0; i < 6; i++) { - stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]); - } - n = 0x6A; - if (flags & 0x00000001) { - for (i = 0; i < 6; i++) - stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]); - } - stl_be_phys(bdloc + n, bd->bi_opbfreq); - n += 4; - for (i = 0; i < 2; i++) { - stl_be_phys(bdloc + n, bd->bi_iic_fast[i]); - n += 4; - } - - return bdloc; -} - -/*****************************************************************************/ -/* Shared peripherals */ - -/*****************************************************************************/ -/* Peripheral local bus arbitrer */ -enum { - PLB0_BESR = 0x084, - PLB0_BEAR = 0x086, - PLB0_ACR = 0x087, -}; - -typedef struct ppc4xx_plb_t ppc4xx_plb_t; -struct ppc4xx_plb_t { - uint32_t acr; - uint32_t bear; - uint32_t besr; -}; - -static uint32_t dcr_read_plb (void *opaque, int dcrn) -{ - ppc4xx_plb_t *plb; - uint32_t ret; - - plb = opaque; - switch (dcrn) { - case PLB0_ACR: - ret = plb->acr; - break; - case PLB0_BEAR: - ret = plb->bear; - break; - case PLB0_BESR: - ret = plb->besr; - break; - default: - /* Avoid gcc warning */ - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_plb (void *opaque, int dcrn, uint32_t val) -{ - ppc4xx_plb_t *plb; - - plb = opaque; - switch (dcrn) { - case PLB0_ACR: - /* We don't care about the actual parameters written as - * we don't manage any priorities on the bus - */ - plb->acr = val & 0xF8000000; - break; - case PLB0_BEAR: - /* Read only */ - break; - case PLB0_BESR: - /* Write-clear */ - plb->besr &= ~val; - break; - } -} - -static void ppc4xx_plb_reset (void *opaque) -{ - ppc4xx_plb_t *plb; - - plb = opaque; - plb->acr = 0x00000000; - plb->bear = 0x00000000; - plb->besr = 0x00000000; -} - -static void ppc4xx_plb_init(CPUPPCState *env) -{ - ppc4xx_plb_t *plb; - - plb = g_malloc0(sizeof(ppc4xx_plb_t)); - ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb); - ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb); - ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb); - qemu_register_reset(ppc4xx_plb_reset, plb); -} - -/*****************************************************************************/ -/* PLB to OPB bridge */ -enum { - POB0_BESR0 = 0x0A0, - POB0_BESR1 = 0x0A2, - POB0_BEAR = 0x0A4, -}; - -typedef struct ppc4xx_pob_t ppc4xx_pob_t; -struct ppc4xx_pob_t { - uint32_t bear; - uint32_t besr0; - uint32_t besr1; -}; - -static uint32_t dcr_read_pob (void *opaque, int dcrn) -{ - ppc4xx_pob_t *pob; - uint32_t ret; - - pob = opaque; - switch (dcrn) { - case POB0_BEAR: - ret = pob->bear; - break; - case POB0_BESR0: - ret = pob->besr0; - break; - case POB0_BESR1: - ret = pob->besr1; - break; - default: - /* Avoid gcc warning */ - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_pob (void *opaque, int dcrn, uint32_t val) -{ - ppc4xx_pob_t *pob; - - pob = opaque; - switch (dcrn) { - case POB0_BEAR: - /* Read only */ - break; - case POB0_BESR0: - /* Write-clear */ - pob->besr0 &= ~val; - break; - case POB0_BESR1: - /* Write-clear */ - pob->besr1 &= ~val; - break; - } -} - -static void ppc4xx_pob_reset (void *opaque) -{ - ppc4xx_pob_t *pob; - - pob = opaque; - /* No error */ - pob->bear = 0x00000000; - pob->besr0 = 0x0000000; - pob->besr1 = 0x0000000; -} - -static void ppc4xx_pob_init(CPUPPCState *env) -{ - ppc4xx_pob_t *pob; - - pob = g_malloc0(sizeof(ppc4xx_pob_t)); - ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob); - ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob); - ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob); - qemu_register_reset(ppc4xx_pob_reset, pob); -} - -/*****************************************************************************/ -/* OPB arbitrer */ -typedef struct ppc4xx_opba_t ppc4xx_opba_t; -struct ppc4xx_opba_t { - MemoryRegion io; - uint8_t cr; - uint8_t pr; -}; - -static uint32_t opba_readb (void *opaque, hwaddr addr) -{ - ppc4xx_opba_t *opba; - uint32_t ret; - -#ifdef DEBUG_OPBA - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - opba = opaque; - switch (addr) { - case 0x00: - ret = opba->cr; - break; - case 0x01: - ret = opba->pr; - break; - default: - ret = 0x00; - break; - } - - return ret; -} - -static void opba_writeb (void *opaque, - hwaddr addr, uint32_t value) -{ - ppc4xx_opba_t *opba; - -#ifdef DEBUG_OPBA - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - opba = opaque; - switch (addr) { - case 0x00: - opba->cr = value & 0xF8; - break; - case 0x01: - opba->pr = value & 0xFF; - break; - default: - break; - } -} - -static uint32_t opba_readw (void *opaque, hwaddr addr) -{ - uint32_t ret; - -#ifdef DEBUG_OPBA - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - ret = opba_readb(opaque, addr) << 8; - ret |= opba_readb(opaque, addr + 1); - - return ret; -} - -static void opba_writew (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_OPBA - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - opba_writeb(opaque, addr, value >> 8); - opba_writeb(opaque, addr + 1, value); -} - -static uint32_t opba_readl (void *opaque, hwaddr addr) -{ - uint32_t ret; - -#ifdef DEBUG_OPBA - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - ret = opba_readb(opaque, addr) << 24; - ret |= opba_readb(opaque, addr + 1) << 16; - - return ret; -} - -static void opba_writel (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_OPBA - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - opba_writeb(opaque, addr, value >> 24); - opba_writeb(opaque, addr + 1, value >> 16); -} - -static const MemoryRegionOps opba_ops = { - .old_mmio = { - .read = { opba_readb, opba_readw, opba_readl, }, - .write = { opba_writeb, opba_writew, opba_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ppc4xx_opba_reset (void *opaque) -{ - ppc4xx_opba_t *opba; - - opba = opaque; - opba->cr = 0x00; /* No dynamic priorities - park disabled */ - opba->pr = 0x11; -} - -static void ppc4xx_opba_init(hwaddr base) -{ - ppc4xx_opba_t *opba; - - opba = g_malloc0(sizeof(ppc4xx_opba_t)); -#ifdef DEBUG_OPBA - printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); -#endif - memory_region_init_io(&opba->io, &opba_ops, opba, "opba", 0x002); - memory_region_add_subregion(get_system_memory(), base, &opba->io); - qemu_register_reset(ppc4xx_opba_reset, opba); -} - -/*****************************************************************************/ -/* Code decompression controller */ -/* XXX: TODO */ - -/*****************************************************************************/ -/* Peripheral controller */ -typedef struct ppc4xx_ebc_t ppc4xx_ebc_t; -struct ppc4xx_ebc_t { - uint32_t addr; - uint32_t bcr[8]; - uint32_t bap[8]; - uint32_t bear; - uint32_t besr0; - uint32_t besr1; - uint32_t cfg; -}; - -enum { - EBC0_CFGADDR = 0x012, - EBC0_CFGDATA = 0x013, -}; - -static uint32_t dcr_read_ebc (void *opaque, int dcrn) -{ - ppc4xx_ebc_t *ebc; - uint32_t ret; - - ebc = opaque; - switch (dcrn) { - case EBC0_CFGADDR: - ret = ebc->addr; - break; - case EBC0_CFGDATA: - switch (ebc->addr) { - case 0x00: /* B0CR */ - ret = ebc->bcr[0]; - break; - case 0x01: /* B1CR */ - ret = ebc->bcr[1]; - break; - case 0x02: /* B2CR */ - ret = ebc->bcr[2]; - break; - case 0x03: /* B3CR */ - ret = ebc->bcr[3]; - break; - case 0x04: /* B4CR */ - ret = ebc->bcr[4]; - break; - case 0x05: /* B5CR */ - ret = ebc->bcr[5]; - break; - case 0x06: /* B6CR */ - ret = ebc->bcr[6]; - break; - case 0x07: /* B7CR */ - ret = ebc->bcr[7]; - break; - case 0x10: /* B0AP */ - ret = ebc->bap[0]; - break; - case 0x11: /* B1AP */ - ret = ebc->bap[1]; - break; - case 0x12: /* B2AP */ - ret = ebc->bap[2]; - break; - case 0x13: /* B3AP */ - ret = ebc->bap[3]; - break; - case 0x14: /* B4AP */ - ret = ebc->bap[4]; - break; - case 0x15: /* B5AP */ - ret = ebc->bap[5]; - break; - case 0x16: /* B6AP */ - ret = ebc->bap[6]; - break; - case 0x17: /* B7AP */ - ret = ebc->bap[7]; - break; - case 0x20: /* BEAR */ - ret = ebc->bear; - break; - case 0x21: /* BESR0 */ - ret = ebc->besr0; - break; - case 0x22: /* BESR1 */ - ret = ebc->besr1; - break; - case 0x23: /* CFG */ - ret = ebc->cfg; - break; - default: - ret = 0x00000000; - break; - } - break; - default: - ret = 0x00000000; - break; - } - - return ret; -} - -static void dcr_write_ebc (void *opaque, int dcrn, uint32_t val) -{ - ppc4xx_ebc_t *ebc; - - ebc = opaque; - switch (dcrn) { - case EBC0_CFGADDR: - ebc->addr = val; - break; - case EBC0_CFGDATA: - switch (ebc->addr) { - case 0x00: /* B0CR */ - break; - case 0x01: /* B1CR */ - break; - case 0x02: /* B2CR */ - break; - case 0x03: /* B3CR */ - break; - case 0x04: /* B4CR */ - break; - case 0x05: /* B5CR */ - break; - case 0x06: /* B6CR */ - break; - case 0x07: /* B7CR */ - break; - case 0x10: /* B0AP */ - break; - case 0x11: /* B1AP */ - break; - case 0x12: /* B2AP */ - break; - case 0x13: /* B3AP */ - break; - case 0x14: /* B4AP */ - break; - case 0x15: /* B5AP */ - break; - case 0x16: /* B6AP */ - break; - case 0x17: /* B7AP */ - break; - case 0x20: /* BEAR */ - break; - case 0x21: /* BESR0 */ - break; - case 0x22: /* BESR1 */ - break; - case 0x23: /* CFG */ - break; - default: - break; - } - break; - default: - break; - } -} - -static void ebc_reset (void *opaque) -{ - ppc4xx_ebc_t *ebc; - int i; - - ebc = opaque; - ebc->addr = 0x00000000; - ebc->bap[0] = 0x7F8FFE80; - ebc->bcr[0] = 0xFFE28000; - for (i = 0; i < 8; i++) { - ebc->bap[i] = 0x00000000; - ebc->bcr[i] = 0x00000000; - } - ebc->besr0 = 0x00000000; - ebc->besr1 = 0x00000000; - ebc->cfg = 0x80400000; -} - -static void ppc405_ebc_init(CPUPPCState *env) -{ - ppc4xx_ebc_t *ebc; - - ebc = g_malloc0(sizeof(ppc4xx_ebc_t)); - qemu_register_reset(&ebc_reset, ebc); - ppc_dcr_register(env, EBC0_CFGADDR, - ebc, &dcr_read_ebc, &dcr_write_ebc); - ppc_dcr_register(env, EBC0_CFGDATA, - ebc, &dcr_read_ebc, &dcr_write_ebc); -} - -/*****************************************************************************/ -/* DMA controller */ -enum { - DMA0_CR0 = 0x100, - DMA0_CT0 = 0x101, - DMA0_DA0 = 0x102, - DMA0_SA0 = 0x103, - DMA0_SG0 = 0x104, - DMA0_CR1 = 0x108, - DMA0_CT1 = 0x109, - DMA0_DA1 = 0x10A, - DMA0_SA1 = 0x10B, - DMA0_SG1 = 0x10C, - DMA0_CR2 = 0x110, - DMA0_CT2 = 0x111, - DMA0_DA2 = 0x112, - DMA0_SA2 = 0x113, - DMA0_SG2 = 0x114, - DMA0_CR3 = 0x118, - DMA0_CT3 = 0x119, - DMA0_DA3 = 0x11A, - DMA0_SA3 = 0x11B, - DMA0_SG3 = 0x11C, - DMA0_SR = 0x120, - DMA0_SGC = 0x123, - DMA0_SLP = 0x125, - DMA0_POL = 0x126, -}; - -typedef struct ppc405_dma_t ppc405_dma_t; -struct ppc405_dma_t { - qemu_irq irqs[4]; - uint32_t cr[4]; - uint32_t ct[4]; - uint32_t da[4]; - uint32_t sa[4]; - uint32_t sg[4]; - uint32_t sr; - uint32_t sgc; - uint32_t slp; - uint32_t pol; -}; - -static uint32_t dcr_read_dma (void *opaque, int dcrn) -{ - return 0; -} - -static void dcr_write_dma (void *opaque, int dcrn, uint32_t val) -{ -} - -static void ppc405_dma_reset (void *opaque) -{ - ppc405_dma_t *dma; - int i; - - dma = opaque; - for (i = 0; i < 4; i++) { - dma->cr[i] = 0x00000000; - dma->ct[i] = 0x00000000; - dma->da[i] = 0x00000000; - dma->sa[i] = 0x00000000; - dma->sg[i] = 0x00000000; - } - dma->sr = 0x00000000; - dma->sgc = 0x00000000; - dma->slp = 0x7C000000; - dma->pol = 0x00000000; -} - -static void ppc405_dma_init(CPUPPCState *env, qemu_irq irqs[4]) -{ - ppc405_dma_t *dma; - - dma = g_malloc0(sizeof(ppc405_dma_t)); - memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq)); - qemu_register_reset(&ppc405_dma_reset, dma); - ppc_dcr_register(env, DMA0_CR0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CR1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CR2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CR3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SR, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SGC, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SLP, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_POL, - dma, &dcr_read_dma, &dcr_write_dma); -} - -/*****************************************************************************/ -/* GPIO */ -typedef struct ppc405_gpio_t ppc405_gpio_t; -struct ppc405_gpio_t { - MemoryRegion io; - uint32_t or; - uint32_t tcr; - uint32_t osrh; - uint32_t osrl; - uint32_t tsrh; - uint32_t tsrl; - uint32_t odr; - uint32_t ir; - uint32_t rr1; - uint32_t isr1h; - uint32_t isr1l; -}; - -static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr) -{ -#ifdef DEBUG_GPIO - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - - return 0; -} - -static void ppc405_gpio_writeb (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_GPIO - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif -} - -static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr) -{ -#ifdef DEBUG_GPIO - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - - return 0; -} - -static void ppc405_gpio_writew (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_GPIO - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif -} - -static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr) -{ -#ifdef DEBUG_GPIO - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - - return 0; -} - -static void ppc405_gpio_writel (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_GPIO - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif -} - -static const MemoryRegionOps ppc405_gpio_ops = { - .old_mmio = { - .read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, }, - .write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ppc405_gpio_reset (void *opaque) -{ -} - -static void ppc405_gpio_init(hwaddr base) -{ - ppc405_gpio_t *gpio; - - gpio = g_malloc0(sizeof(ppc405_gpio_t)); -#ifdef DEBUG_GPIO - printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); -#endif - memory_region_init_io(&gpio->io, &ppc405_gpio_ops, gpio, "pgio", 0x038); - memory_region_add_subregion(get_system_memory(), base, &gpio->io); - qemu_register_reset(&ppc405_gpio_reset, gpio); -} - -/*****************************************************************************/ -/* On Chip Memory */ -enum { - OCM0_ISARC = 0x018, - OCM0_ISACNTL = 0x019, - OCM0_DSARC = 0x01A, - OCM0_DSACNTL = 0x01B, -}; - -typedef struct ppc405_ocm_t ppc405_ocm_t; -struct ppc405_ocm_t { - MemoryRegion ram; - MemoryRegion isarc_ram; - MemoryRegion dsarc_ram; - uint32_t isarc; - uint32_t isacntl; - uint32_t dsarc; - uint32_t dsacntl; -}; - -static void ocm_update_mappings (ppc405_ocm_t *ocm, - uint32_t isarc, uint32_t isacntl, - uint32_t dsarc, uint32_t dsacntl) -{ -#ifdef DEBUG_OCM - printf("OCM update ISA %08" PRIx32 " %08" PRIx32 " (%08" PRIx32 - " %08" PRIx32 ") DSA %08" PRIx32 " %08" PRIx32 - " (%08" PRIx32 " %08" PRIx32 ")\n", - isarc, isacntl, dsarc, dsacntl, - ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl); -#endif - if (ocm->isarc != isarc || - (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) { - if (ocm->isacntl & 0x80000000) { - /* Unmap previously assigned memory region */ - printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc); - memory_region_del_subregion(get_system_memory(), &ocm->isarc_ram); - } - if (isacntl & 0x80000000) { - /* Map new instruction memory region */ -#ifdef DEBUG_OCM - printf("OCM map ISA %08" PRIx32 "\n", isarc); -#endif - memory_region_add_subregion(get_system_memory(), isarc, - &ocm->isarc_ram); - } - } - if (ocm->dsarc != dsarc || - (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) { - if (ocm->dsacntl & 0x80000000) { - /* Beware not to unmap the region we just mapped */ - if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) { - /* Unmap previously assigned memory region */ -#ifdef DEBUG_OCM - printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc); -#endif - memory_region_del_subregion(get_system_memory(), - &ocm->dsarc_ram); - } - } - if (dsacntl & 0x80000000) { - /* Beware not to remap the region we just mapped */ - if (!(isacntl & 0x80000000) || dsarc != isarc) { - /* Map new data memory region */ -#ifdef DEBUG_OCM - printf("OCM map DSA %08" PRIx32 "\n", dsarc); -#endif - memory_region_add_subregion(get_system_memory(), dsarc, - &ocm->dsarc_ram); - } - } - } -} - -static uint32_t dcr_read_ocm (void *opaque, int dcrn) -{ - ppc405_ocm_t *ocm; - uint32_t ret; - - ocm = opaque; - switch (dcrn) { - case OCM0_ISARC: - ret = ocm->isarc; - break; - case OCM0_ISACNTL: - ret = ocm->isacntl; - break; - case OCM0_DSARC: - ret = ocm->dsarc; - break; - case OCM0_DSACNTL: - ret = ocm->dsacntl; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val) -{ - ppc405_ocm_t *ocm; - uint32_t isarc, dsarc, isacntl, dsacntl; - - ocm = opaque; - isarc = ocm->isarc; - dsarc = ocm->dsarc; - isacntl = ocm->isacntl; - dsacntl = ocm->dsacntl; - switch (dcrn) { - case OCM0_ISARC: - isarc = val & 0xFC000000; - break; - case OCM0_ISACNTL: - isacntl = val & 0xC0000000; - break; - case OCM0_DSARC: - isarc = val & 0xFC000000; - break; - case OCM0_DSACNTL: - isacntl = val & 0xC0000000; - break; - } - ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl); - ocm->isarc = isarc; - ocm->dsarc = dsarc; - ocm->isacntl = isacntl; - ocm->dsacntl = dsacntl; -} - -static void ocm_reset (void *opaque) -{ - ppc405_ocm_t *ocm; - uint32_t isarc, dsarc, isacntl, dsacntl; - - ocm = opaque; - isarc = 0x00000000; - isacntl = 0x00000000; - dsarc = 0x00000000; - dsacntl = 0x00000000; - ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl); - ocm->isarc = isarc; - ocm->dsarc = dsarc; - ocm->isacntl = isacntl; - ocm->dsacntl = dsacntl; -} - -static void ppc405_ocm_init(CPUPPCState *env) -{ - ppc405_ocm_t *ocm; - - ocm = g_malloc0(sizeof(ppc405_ocm_t)); - /* XXX: Size is 4096 or 0x04000000 */ - memory_region_init_ram(&ocm->isarc_ram, "ppc405.ocm", 4096); - vmstate_register_ram_global(&ocm->isarc_ram); - memory_region_init_alias(&ocm->dsarc_ram, "ppc405.dsarc", &ocm->isarc_ram, - 0, 4096); - qemu_register_reset(&ocm_reset, ocm); - ppc_dcr_register(env, OCM0_ISARC, - ocm, &dcr_read_ocm, &dcr_write_ocm); - ppc_dcr_register(env, OCM0_ISACNTL, - ocm, &dcr_read_ocm, &dcr_write_ocm); - ppc_dcr_register(env, OCM0_DSARC, - ocm, &dcr_read_ocm, &dcr_write_ocm); - ppc_dcr_register(env, OCM0_DSACNTL, - ocm, &dcr_read_ocm, &dcr_write_ocm); -} - -/*****************************************************************************/ -/* I2C controller */ -typedef struct ppc4xx_i2c_t ppc4xx_i2c_t; -struct ppc4xx_i2c_t { - qemu_irq irq; - MemoryRegion iomem; - uint8_t mdata; - uint8_t lmadr; - uint8_t hmadr; - uint8_t cntl; - uint8_t mdcntl; - uint8_t sts; - uint8_t extsts; - uint8_t sdata; - uint8_t lsadr; - uint8_t hsadr; - uint8_t clkdiv; - uint8_t intrmsk; - uint8_t xfrcnt; - uint8_t xtcntlss; - uint8_t directcntl; -}; - -static uint32_t ppc4xx_i2c_readb (void *opaque, hwaddr addr) -{ - ppc4xx_i2c_t *i2c; - uint32_t ret; - -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - i2c = opaque; - switch (addr) { - case 0x00: - // i2c_readbyte(&i2c->mdata); - ret = i2c->mdata; - break; - case 0x02: - ret = i2c->sdata; - break; - case 0x04: - ret = i2c->lmadr; - break; - case 0x05: - ret = i2c->hmadr; - break; - case 0x06: - ret = i2c->cntl; - break; - case 0x07: - ret = i2c->mdcntl; - break; - case 0x08: - ret = i2c->sts; - break; - case 0x09: - ret = i2c->extsts; - break; - case 0x0A: - ret = i2c->lsadr; - break; - case 0x0B: - ret = i2c->hsadr; - break; - case 0x0C: - ret = i2c->clkdiv; - break; - case 0x0D: - ret = i2c->intrmsk; - break; - case 0x0E: - ret = i2c->xfrcnt; - break; - case 0x0F: - ret = i2c->xtcntlss; - break; - case 0x10: - ret = i2c->directcntl; - break; - default: - ret = 0x00; - break; - } -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret); -#endif - - return ret; -} - -static void ppc4xx_i2c_writeb (void *opaque, - hwaddr addr, uint32_t value) -{ - ppc4xx_i2c_t *i2c; - -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - i2c = opaque; - switch (addr) { - case 0x00: - i2c->mdata = value; - // i2c_sendbyte(&i2c->mdata); - break; - case 0x02: - i2c->sdata = value; - break; - case 0x04: - i2c->lmadr = value; - break; - case 0x05: - i2c->hmadr = value; - break; - case 0x06: - i2c->cntl = value; - break; - case 0x07: - i2c->mdcntl = value & 0xDF; - break; - case 0x08: - i2c->sts &= ~(value & 0x0A); - break; - case 0x09: - i2c->extsts &= ~(value & 0x8F); - break; - case 0x0A: - i2c->lsadr = value; - break; - case 0x0B: - i2c->hsadr = value; - break; - case 0x0C: - i2c->clkdiv = value; - break; - case 0x0D: - i2c->intrmsk = value; - break; - case 0x0E: - i2c->xfrcnt = value & 0x77; - break; - case 0x0F: - i2c->xtcntlss = value; - break; - case 0x10: - i2c->directcntl = value & 0x7; - break; - } -} - -static uint32_t ppc4xx_i2c_readw (void *opaque, hwaddr addr) -{ - uint32_t ret; - -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - ret = ppc4xx_i2c_readb(opaque, addr) << 8; - ret |= ppc4xx_i2c_readb(opaque, addr + 1); - - return ret; -} - -static void ppc4xx_i2c_writew (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - ppc4xx_i2c_writeb(opaque, addr, value >> 8); - ppc4xx_i2c_writeb(opaque, addr + 1, value); -} - -static uint32_t ppc4xx_i2c_readl (void *opaque, hwaddr addr) -{ - uint32_t ret; - -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - ret = ppc4xx_i2c_readb(opaque, addr) << 24; - ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16; - ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8; - ret |= ppc4xx_i2c_readb(opaque, addr + 3); - - return ret; -} - -static void ppc4xx_i2c_writel (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - ppc4xx_i2c_writeb(opaque, addr, value >> 24); - ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16); - ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8); - ppc4xx_i2c_writeb(opaque, addr + 3, value); -} - -static const MemoryRegionOps i2c_ops = { - .old_mmio = { - .read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, }, - .write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ppc4xx_i2c_reset (void *opaque) -{ - ppc4xx_i2c_t *i2c; - - i2c = opaque; - i2c->mdata = 0x00; - i2c->sdata = 0x00; - i2c->cntl = 0x00; - i2c->mdcntl = 0x00; - i2c->sts = 0x00; - i2c->extsts = 0x00; - i2c->clkdiv = 0x00; - i2c->xfrcnt = 0x00; - i2c->directcntl = 0x0F; -} - -static void ppc405_i2c_init(hwaddr base, qemu_irq irq) -{ - ppc4xx_i2c_t *i2c; - - i2c = g_malloc0(sizeof(ppc4xx_i2c_t)); - i2c->irq = irq; -#ifdef DEBUG_I2C - printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); -#endif - memory_region_init_io(&i2c->iomem, &i2c_ops, i2c, "i2c", 0x011); - memory_region_add_subregion(get_system_memory(), base, &i2c->iomem); - qemu_register_reset(ppc4xx_i2c_reset, i2c); -} - -/*****************************************************************************/ -/* General purpose timers */ -typedef struct ppc4xx_gpt_t ppc4xx_gpt_t; -struct ppc4xx_gpt_t { - MemoryRegion iomem; - int64_t tb_offset; - uint32_t tb_freq; - struct QEMUTimer *timer; - qemu_irq irqs[5]; - uint32_t oe; - uint32_t ol; - uint32_t im; - uint32_t is; - uint32_t ie; - uint32_t comp[5]; - uint32_t mask[5]; -}; - -static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr) -{ -#ifdef DEBUG_GPT - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - /* XXX: generate a bus fault */ - return -1; -} - -static void ppc4xx_gpt_writeb (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - /* XXX: generate a bus fault */ -} - -static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr) -{ -#ifdef DEBUG_GPT - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - /* XXX: generate a bus fault */ - return -1; -} - -static void ppc4xx_gpt_writew (void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - /* XXX: generate a bus fault */ -} - -static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n) -{ - /* XXX: TODO */ - return 0; -} - -static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level) -{ - /* XXX: TODO */ -} - -static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) -{ - uint32_t mask; - int i; - - mask = 0x80000000; - for (i = 0; i < 5; i++) { - if (gpt->oe & mask) { - /* Output is enabled */ - if (ppc4xx_gpt_compare(gpt, i)) { - /* Comparison is OK */ - ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask); - } else { - /* Comparison is KO */ - ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1); - } - } - mask = mask >> 1; - } -} - -static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) -{ - uint32_t mask; - int i; - - mask = 0x00008000; - for (i = 0; i < 5; i++) { - if (gpt->is & gpt->im & mask) - qemu_irq_raise(gpt->irqs[i]); - else - qemu_irq_lower(gpt->irqs[i]); - mask = mask >> 1; - } -} - -static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) -{ - /* XXX: TODO */ -} - -static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr) -{ - ppc4xx_gpt_t *gpt; - uint32_t ret; - int idx; - -#ifdef DEBUG_GPT - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - gpt = opaque; - switch (addr) { - case 0x00: - /* Time base counter */ - ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset, - gpt->tb_freq, get_ticks_per_sec()); - break; - case 0x10: - /* Output enable */ - ret = gpt->oe; - break; - case 0x14: - /* Output level */ - ret = gpt->ol; - break; - case 0x18: - /* Interrupt mask */ - ret = gpt->im; - break; - case 0x1C: - case 0x20: - /* Interrupt status */ - ret = gpt->is; - break; - case 0x24: - /* Interrupt enable */ - ret = gpt->ie; - break; - case 0x80 ... 0x90: - /* Compare timer */ - idx = (addr - 0x80) >> 2; - ret = gpt->comp[idx]; - break; - case 0xC0 ... 0xD0: - /* Compare mask */ - idx = (addr - 0xC0) >> 2; - ret = gpt->mask[idx]; - break; - default: - ret = -1; - break; - } - - return ret; -} - -static void ppc4xx_gpt_writel (void *opaque, - hwaddr addr, uint32_t value) -{ - ppc4xx_gpt_t *gpt; - int idx; - -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - gpt = opaque; - switch (addr) { - case 0x00: - /* Time base counter */ - gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq) - - qemu_get_clock_ns(vm_clock); - ppc4xx_gpt_compute_timer(gpt); - break; - case 0x10: - /* Output enable */ - gpt->oe = value & 0xF8000000; - ppc4xx_gpt_set_outputs(gpt); - break; - case 0x14: - /* Output level */ - gpt->ol = value & 0xF8000000; - ppc4xx_gpt_set_outputs(gpt); - break; - case 0x18: - /* Interrupt mask */ - gpt->im = value & 0x0000F800; - break; - case 0x1C: - /* Interrupt status set */ - gpt->is |= value & 0x0000F800; - ppc4xx_gpt_set_irqs(gpt); - break; - case 0x20: - /* Interrupt status clear */ - gpt->is &= ~(value & 0x0000F800); - ppc4xx_gpt_set_irqs(gpt); - break; - case 0x24: - /* Interrupt enable */ - gpt->ie = value & 0x0000F800; - ppc4xx_gpt_set_irqs(gpt); - break; - case 0x80 ... 0x90: - /* Compare timer */ - idx = (addr - 0x80) >> 2; - gpt->comp[idx] = value & 0xF8000000; - ppc4xx_gpt_compute_timer(gpt); - break; - case 0xC0 ... 0xD0: - /* Compare mask */ - idx = (addr - 0xC0) >> 2; - gpt->mask[idx] = value & 0xF8000000; - ppc4xx_gpt_compute_timer(gpt); - break; - } -} - -static const MemoryRegionOps gpt_ops = { - .old_mmio = { - .read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, }, - .write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ppc4xx_gpt_cb (void *opaque) -{ - ppc4xx_gpt_t *gpt; - - gpt = opaque; - ppc4xx_gpt_set_irqs(gpt); - ppc4xx_gpt_set_outputs(gpt); - ppc4xx_gpt_compute_timer(gpt); -} - -static void ppc4xx_gpt_reset (void *opaque) -{ - ppc4xx_gpt_t *gpt; - int i; - - gpt = opaque; - qemu_del_timer(gpt->timer); - gpt->oe = 0x00000000; - gpt->ol = 0x00000000; - gpt->im = 0x00000000; - gpt->is = 0x00000000; - gpt->ie = 0x00000000; - for (i = 0; i < 5; i++) { - gpt->comp[i] = 0x00000000; - gpt->mask[i] = 0x00000000; - } -} - -static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5]) -{ - ppc4xx_gpt_t *gpt; - int i; - - gpt = g_malloc0(sizeof(ppc4xx_gpt_t)); - for (i = 0; i < 5; i++) { - gpt->irqs[i] = irqs[i]; - } - gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt); -#ifdef DEBUG_GPT - printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); -#endif - memory_region_init_io(&gpt->iomem, &gpt_ops, gpt, "gpt", 0x0d4); - memory_region_add_subregion(get_system_memory(), base, &gpt->iomem); - qemu_register_reset(ppc4xx_gpt_reset, gpt); -} - -/*****************************************************************************/ -/* MAL */ -enum { - MAL0_CFG = 0x180, - MAL0_ESR = 0x181, - MAL0_IER = 0x182, - MAL0_TXCASR = 0x184, - MAL0_TXCARR = 0x185, - MAL0_TXEOBISR = 0x186, - MAL0_TXDEIR = 0x187, - MAL0_RXCASR = 0x190, - MAL0_RXCARR = 0x191, - MAL0_RXEOBISR = 0x192, - MAL0_RXDEIR = 0x193, - MAL0_TXCTP0R = 0x1A0, - MAL0_TXCTP1R = 0x1A1, - MAL0_TXCTP2R = 0x1A2, - MAL0_TXCTP3R = 0x1A3, - MAL0_RXCTP0R = 0x1C0, - MAL0_RXCTP1R = 0x1C1, - MAL0_RCBS0 = 0x1E0, - MAL0_RCBS1 = 0x1E1, -}; - -typedef struct ppc40x_mal_t ppc40x_mal_t; -struct ppc40x_mal_t { - qemu_irq irqs[4]; - uint32_t cfg; - uint32_t esr; - uint32_t ier; - uint32_t txcasr; - uint32_t txcarr; - uint32_t txeobisr; - uint32_t txdeir; - uint32_t rxcasr; - uint32_t rxcarr; - uint32_t rxeobisr; - uint32_t rxdeir; - uint32_t txctpr[4]; - uint32_t rxctpr[2]; - uint32_t rcbs[2]; -}; - -static void ppc40x_mal_reset (void *opaque); - -static uint32_t dcr_read_mal (void *opaque, int dcrn) -{ - ppc40x_mal_t *mal; - uint32_t ret; - - mal = opaque; - switch (dcrn) { - case MAL0_CFG: - ret = mal->cfg; - break; - case MAL0_ESR: - ret = mal->esr; - break; - case MAL0_IER: - ret = mal->ier; - break; - case MAL0_TXCASR: - ret = mal->txcasr; - break; - case MAL0_TXCARR: - ret = mal->txcarr; - break; - case MAL0_TXEOBISR: - ret = mal->txeobisr; - break; - case MAL0_TXDEIR: - ret = mal->txdeir; - break; - case MAL0_RXCASR: - ret = mal->rxcasr; - break; - case MAL0_RXCARR: - ret = mal->rxcarr; - break; - case MAL0_RXEOBISR: - ret = mal->rxeobisr; - break; - case MAL0_RXDEIR: - ret = mal->rxdeir; - break; - case MAL0_TXCTP0R: - ret = mal->txctpr[0]; - break; - case MAL0_TXCTP1R: - ret = mal->txctpr[1]; - break; - case MAL0_TXCTP2R: - ret = mal->txctpr[2]; - break; - case MAL0_TXCTP3R: - ret = mal->txctpr[3]; - break; - case MAL0_RXCTP0R: - ret = mal->rxctpr[0]; - break; - case MAL0_RXCTP1R: - ret = mal->rxctpr[1]; - break; - case MAL0_RCBS0: - ret = mal->rcbs[0]; - break; - case MAL0_RCBS1: - ret = mal->rcbs[1]; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_mal (void *opaque, int dcrn, uint32_t val) -{ - ppc40x_mal_t *mal; - int idx; - - mal = opaque; - switch (dcrn) { - case MAL0_CFG: - if (val & 0x80000000) - ppc40x_mal_reset(mal); - mal->cfg = val & 0x00FFC087; - break; - case MAL0_ESR: - /* Read/clear */ - mal->esr &= ~val; - break; - case MAL0_IER: - mal->ier = val & 0x0000001F; - break; - case MAL0_TXCASR: - mal->txcasr = val & 0xF0000000; - break; - case MAL0_TXCARR: - mal->txcarr = val & 0xF0000000; - break; - case MAL0_TXEOBISR: - /* Read/clear */ - mal->txeobisr &= ~val; - break; - case MAL0_TXDEIR: - /* Read/clear */ - mal->txdeir &= ~val; - break; - case MAL0_RXCASR: - mal->rxcasr = val & 0xC0000000; - break; - case MAL0_RXCARR: - mal->rxcarr = val & 0xC0000000; - break; - case MAL0_RXEOBISR: - /* Read/clear */ - mal->rxeobisr &= ~val; - break; - case MAL0_RXDEIR: - /* Read/clear */ - mal->rxdeir &= ~val; - break; - case MAL0_TXCTP0R: - idx = 0; - goto update_tx_ptr; - case MAL0_TXCTP1R: - idx = 1; - goto update_tx_ptr; - case MAL0_TXCTP2R: - idx = 2; - goto update_tx_ptr; - case MAL0_TXCTP3R: - idx = 3; - update_tx_ptr: - mal->txctpr[idx] = val; - break; - case MAL0_RXCTP0R: - idx = 0; - goto update_rx_ptr; - case MAL0_RXCTP1R: - idx = 1; - update_rx_ptr: - mal->rxctpr[idx] = val; - break; - case MAL0_RCBS0: - idx = 0; - goto update_rx_size; - case MAL0_RCBS1: - idx = 1; - update_rx_size: - mal->rcbs[idx] = val & 0x000000FF; - break; - } -} - -static void ppc40x_mal_reset (void *opaque) -{ - ppc40x_mal_t *mal; - - mal = opaque; - mal->cfg = 0x0007C000; - mal->esr = 0x00000000; - mal->ier = 0x00000000; - mal->rxcasr = 0x00000000; - mal->rxdeir = 0x00000000; - mal->rxeobisr = 0x00000000; - mal->txcasr = 0x00000000; - mal->txdeir = 0x00000000; - mal->txeobisr = 0x00000000; -} - -static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]) -{ - ppc40x_mal_t *mal; - int i; - - mal = g_malloc0(sizeof(ppc40x_mal_t)); - for (i = 0; i < 4; i++) - mal->irqs[i] = irqs[i]; - qemu_register_reset(&ppc40x_mal_reset, mal); - ppc_dcr_register(env, MAL0_CFG, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_ESR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_IER, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCASR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCARR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXEOBISR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXDEIR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCASR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCARR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXEOBISR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXDEIR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP0R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP1R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP2R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP3R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCTP0R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCTP1R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RCBS0, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RCBS1, - mal, &dcr_read_mal, &dcr_write_mal); -} - -/*****************************************************************************/ -/* SPR */ -void ppc40x_core_reset(PowerPCCPU *cpu) -{ - CPUPPCState *env = &cpu->env; - target_ulong dbsr; - - printf("Reset PowerPC core\n"); - cpu_interrupt(env, CPU_INTERRUPT_RESET); - dbsr = env->spr[SPR_40x_DBSR]; - dbsr &= ~0x00000300; - dbsr |= 0x00000100; - env->spr[SPR_40x_DBSR] = dbsr; -} - -void ppc40x_chip_reset(PowerPCCPU *cpu) -{ - CPUPPCState *env = &cpu->env; - target_ulong dbsr; - - printf("Reset PowerPC chip\n"); - cpu_interrupt(env, CPU_INTERRUPT_RESET); - /* XXX: TODO reset all internal peripherals */ - dbsr = env->spr[SPR_40x_DBSR]; - dbsr &= ~0x00000300; - dbsr |= 0x00000200; - env->spr[SPR_40x_DBSR] = dbsr; -} - -void ppc40x_system_reset(PowerPCCPU *cpu) -{ - printf("Reset PowerPC system\n"); - qemu_system_reset_request(); -} - -void store_40x_dbcr0 (CPUPPCState *env, uint32_t val) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - switch ((val >> 28) & 0x3) { - case 0x0: - /* No action */ - break; - case 0x1: - /* Core reset */ - ppc40x_core_reset(cpu); - break; - case 0x2: - /* Chip reset */ - ppc40x_chip_reset(cpu); - break; - case 0x3: - /* System reset */ - ppc40x_system_reset(cpu); - break; - } -} - -/*****************************************************************************/ -/* PowerPC 405CR */ -enum { - PPC405CR_CPC0_PLLMR = 0x0B0, - PPC405CR_CPC0_CR0 = 0x0B1, - PPC405CR_CPC0_CR1 = 0x0B2, - PPC405CR_CPC0_PSR = 0x0B4, - PPC405CR_CPC0_JTAGID = 0x0B5, - PPC405CR_CPC0_ER = 0x0B9, - PPC405CR_CPC0_FR = 0x0BA, - PPC405CR_CPC0_SR = 0x0BB, -}; - -enum { - PPC405CR_CPU_CLK = 0, - PPC405CR_TMR_CLK = 1, - PPC405CR_PLB_CLK = 2, - PPC405CR_SDRAM_CLK = 3, - PPC405CR_OPB_CLK = 4, - PPC405CR_EXT_CLK = 5, - PPC405CR_UART_CLK = 6, - PPC405CR_CLK_NB = 7, -}; - -typedef struct ppc405cr_cpc_t ppc405cr_cpc_t; -struct ppc405cr_cpc_t { - clk_setup_t clk_setup[PPC405CR_CLK_NB]; - uint32_t sysclk; - uint32_t psr; - uint32_t cr0; - uint32_t cr1; - uint32_t jtagid; - uint32_t pllmr; - uint32_t er; - uint32_t fr; -}; - -static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc) -{ - uint64_t VCO_out, PLL_out; - uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk; - int M, D0, D1, D2; - - D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */ - if (cpc->pllmr & 0x80000000) { - D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */ - D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */ - M = D0 * D1 * D2; - VCO_out = cpc->sysclk * M; - if (VCO_out < 400000000 || VCO_out > 800000000) { - /* PLL cannot lock */ - cpc->pllmr &= ~0x80000000; - goto bypass_pll; - } - PLL_out = VCO_out / D2; - } else { - /* Bypass PLL */ - bypass_pll: - M = D0; - PLL_out = cpc->sysclk * M; - } - CPU_clk = PLL_out; - if (cpc->cr1 & 0x00800000) - TMR_clk = cpc->sysclk; /* Should have a separate clock */ - else - TMR_clk = CPU_clk; - PLB_clk = CPU_clk / D0; - SDRAM_clk = PLB_clk; - D0 = ((cpc->pllmr >> 10) & 0x3) + 1; - OPB_clk = PLB_clk / D0; - D0 = ((cpc->pllmr >> 24) & 0x3) + 2; - EXT_clk = PLB_clk / D0; - D0 = ((cpc->cr0 >> 1) & 0x1F) + 1; - UART_clk = CPU_clk / D0; - /* Setup CPU clocks */ - clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk); - /* Setup time-base clock */ - clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk); - /* Setup PLB clock */ - clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk); - /* Setup SDRAM clock */ - clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk); - /* Setup OPB clock */ - clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk); - /* Setup external clock */ - clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk); - /* Setup UART clock */ - clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk); -} - -static uint32_t dcr_read_crcpc (void *opaque, int dcrn) -{ - ppc405cr_cpc_t *cpc; - uint32_t ret; - - cpc = opaque; - switch (dcrn) { - case PPC405CR_CPC0_PLLMR: - ret = cpc->pllmr; - break; - case PPC405CR_CPC0_CR0: - ret = cpc->cr0; - break; - case PPC405CR_CPC0_CR1: - ret = cpc->cr1; - break; - case PPC405CR_CPC0_PSR: - ret = cpc->psr; - break; - case PPC405CR_CPC0_JTAGID: - ret = cpc->jtagid; - break; - case PPC405CR_CPC0_ER: - ret = cpc->er; - break; - case PPC405CR_CPC0_FR: - ret = cpc->fr; - break; - case PPC405CR_CPC0_SR: - ret = ~(cpc->er | cpc->fr) & 0xFFFF0000; - break; - default: - /* Avoid gcc warning */ - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_crcpc (void *opaque, int dcrn, uint32_t val) -{ - ppc405cr_cpc_t *cpc; - - cpc = opaque; - switch (dcrn) { - case PPC405CR_CPC0_PLLMR: - cpc->pllmr = val & 0xFFF77C3F; - break; - case PPC405CR_CPC0_CR0: - cpc->cr0 = val & 0x0FFFFFFE; - break; - case PPC405CR_CPC0_CR1: - cpc->cr1 = val & 0x00800000; - break; - case PPC405CR_CPC0_PSR: - /* Read-only */ - break; - case PPC405CR_CPC0_JTAGID: - /* Read-only */ - break; - case PPC405CR_CPC0_ER: - cpc->er = val & 0xBFFC0000; - break; - case PPC405CR_CPC0_FR: - cpc->fr = val & 0xBFFC0000; - break; - case PPC405CR_CPC0_SR: - /* Read-only */ - break; - } -} - -static void ppc405cr_cpc_reset (void *opaque) -{ - ppc405cr_cpc_t *cpc; - int D; - - cpc = opaque; - /* Compute PLLMR value from PSR settings */ - cpc->pllmr = 0x80000000; - /* PFWD */ - switch ((cpc->psr >> 30) & 3) { - case 0: - /* Bypass */ - cpc->pllmr &= ~0x80000000; - break; - case 1: - /* Divide by 3 */ - cpc->pllmr |= 5 << 16; - break; - case 2: - /* Divide by 4 */ - cpc->pllmr |= 4 << 16; - break; - case 3: - /* Divide by 6 */ - cpc->pllmr |= 2 << 16; - break; - } - /* PFBD */ - D = (cpc->psr >> 28) & 3; - cpc->pllmr |= (D + 1) << 20; - /* PT */ - D = (cpc->psr >> 25) & 7; - switch (D) { - case 0x2: - cpc->pllmr |= 0x13; - break; - case 0x4: - cpc->pllmr |= 0x15; - break; - case 0x5: - cpc->pllmr |= 0x16; - break; - default: - break; - } - /* PDC */ - D = (cpc->psr >> 23) & 3; - cpc->pllmr |= D << 26; - /* ODP */ - D = (cpc->psr >> 21) & 3; - cpc->pllmr |= D << 10; - /* EBPD */ - D = (cpc->psr >> 17) & 3; - cpc->pllmr |= D << 24; - cpc->cr0 = 0x0000003C; - cpc->cr1 = 0x2B0D8800; - cpc->er = 0x00000000; - cpc->fr = 0x00000000; - ppc405cr_clk_setup(cpc); -} - -static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc) -{ - int D; - - /* XXX: this should be read from IO pins */ - cpc->psr = 0x00000000; /* 8 bits ROM */ - /* PFWD */ - D = 0x2; /* Divide by 4 */ - cpc->psr |= D << 30; - /* PFBD */ - D = 0x1; /* Divide by 2 */ - cpc->psr |= D << 28; - /* PDC */ - D = 0x1; /* Divide by 2 */ - cpc->psr |= D << 23; - /* PT */ - D = 0x5; /* M = 16 */ - cpc->psr |= D << 25; - /* ODP */ - D = 0x1; /* Divide by 2 */ - cpc->psr |= D << 21; - /* EBDP */ - D = 0x2; /* Divide by 4 */ - cpc->psr |= D << 17; -} - -static void ppc405cr_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[7], - uint32_t sysclk) -{ - ppc405cr_cpc_t *cpc; - - cpc = g_malloc0(sizeof(ppc405cr_cpc_t)); - memcpy(cpc->clk_setup, clk_setup, - PPC405CR_CLK_NB * sizeof(clk_setup_t)); - cpc->sysclk = sysclk; - cpc->jtagid = 0x42051049; - ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc, - &dcr_read_crcpc, &dcr_write_crcpc); - ppc405cr_clk_init(cpc); - qemu_register_reset(ppc405cr_cpc_reset, cpc); -} - -CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, - MemoryRegion ram_memories[4], - hwaddr ram_bases[4], - hwaddr ram_sizes[4], - uint32_t sysclk, qemu_irq **picp, - int do_init) -{ - clk_setup_t clk_setup[PPC405CR_CLK_NB]; - qemu_irq dma_irqs[4]; - PowerPCCPU *cpu; - CPUPPCState *env; - qemu_irq *pic, *irqs; - - memset(clk_setup, 0, sizeof(clk_setup)); - cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], - &clk_setup[PPC405CR_TMR_CLK], sysclk); - env = &cpu->env; - /* Memory mapped devices registers */ - /* PLB arbitrer */ - ppc4xx_plb_init(env); - /* PLB to OPB bridge */ - ppc4xx_pob_init(env); - /* OBP arbitrer */ - ppc4xx_opba_init(0xef600600); - /* Universal interrupt controller */ - irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); - irqs[PPCUIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; - irqs[PPCUIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; - pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); - *picp = pic; - /* SDRAM controller */ - ppc4xx_sdram_init(env, pic[14], 1, ram_memories, - ram_bases, ram_sizes, do_init); - /* External bus controller */ - ppc405_ebc_init(env); - /* DMA controller */ - dma_irqs[0] = pic[26]; - dma_irqs[1] = pic[25]; - dma_irqs[2] = pic[24]; - dma_irqs[3] = pic[23]; - ppc405_dma_init(env, dma_irqs); - /* Serial ports */ - if (serial_hds[0] != NULL) { - serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], - PPC_SERIAL_MM_BAUDBASE, serial_hds[0], - DEVICE_BIG_ENDIAN); - } - if (serial_hds[1] != NULL) { - serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], - PPC_SERIAL_MM_BAUDBASE, serial_hds[1], - DEVICE_BIG_ENDIAN); - } - /* IIC controller */ - ppc405_i2c_init(0xef600500, pic[2]); - /* GPIO */ - ppc405_gpio_init(0xef600700); - /* CPU control */ - ppc405cr_cpc_init(env, clk_setup, sysclk); - - return env; -} - -/*****************************************************************************/ -/* PowerPC 405EP */ -/* CPU control */ -enum { - PPC405EP_CPC0_PLLMR0 = 0x0F0, - PPC405EP_CPC0_BOOT = 0x0F1, - PPC405EP_CPC0_EPCTL = 0x0F3, - PPC405EP_CPC0_PLLMR1 = 0x0F4, - PPC405EP_CPC0_UCR = 0x0F5, - PPC405EP_CPC0_SRR = 0x0F6, - PPC405EP_CPC0_JTAGID = 0x0F7, - PPC405EP_CPC0_PCI = 0x0F9, -#if 0 - PPC405EP_CPC0_ER = xxx, - PPC405EP_CPC0_FR = xxx, - PPC405EP_CPC0_SR = xxx, -#endif -}; - -enum { - PPC405EP_CPU_CLK = 0, - PPC405EP_PLB_CLK = 1, - PPC405EP_OPB_CLK = 2, - PPC405EP_EBC_CLK = 3, - PPC405EP_MAL_CLK = 4, - PPC405EP_PCI_CLK = 5, - PPC405EP_UART0_CLK = 6, - PPC405EP_UART1_CLK = 7, - PPC405EP_CLK_NB = 8, -}; - -typedef struct ppc405ep_cpc_t ppc405ep_cpc_t; -struct ppc405ep_cpc_t { - uint32_t sysclk; - clk_setup_t clk_setup[PPC405EP_CLK_NB]; - uint32_t boot; - uint32_t epctl; - uint32_t pllmr[2]; - uint32_t ucr; - uint32_t srr; - uint32_t jtagid; - uint32_t pci; - /* Clock and power management */ - uint32_t er; - uint32_t fr; - uint32_t sr; -}; - -static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) -{ - uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk; - uint32_t UART0_clk, UART1_clk; - uint64_t VCO_out, PLL_out; - int M, D; - - VCO_out = 0; - if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) { - M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */ -#ifdef DEBUG_CLOCKS_LL - printf("FBMUL %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 20) & 0xF, M); -#endif - D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */ -#ifdef DEBUG_CLOCKS_LL - printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D); -#endif - VCO_out = cpc->sysclk * M * D; - if (VCO_out < 500000000UL || VCO_out > 1000000000UL) { - /* Error - unlock the PLL */ - printf("VCO out of range %" PRIu64 "\n", VCO_out); -#if 0 - cpc->pllmr[1] &= ~0x80000000; - goto pll_bypass; -#endif - } - PLL_out = VCO_out / D; - /* Pretend the PLL is locked */ - cpc->boot |= 0x00000001; - } else { -#if 0 - pll_bypass: -#endif - PLL_out = cpc->sysclk; - if (cpc->pllmr[1] & 0x40000000) { - /* Pretend the PLL is not locked */ - cpc->boot &= ~0x00000001; - } - } - /* Now, compute all other clocks */ - D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */ -#ifdef DEBUG_CLOCKS_LL - printf("CCDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 20) & 0x3, D); -#endif - CPU_clk = PLL_out / D; - D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */ -#ifdef DEBUG_CLOCKS_LL - printf("CBDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 16) & 0x3, D); -#endif - PLB_clk = CPU_clk / D; - D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */ -#ifdef DEBUG_CLOCKS_LL - printf("OPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 12) & 0x3, D); -#endif - OPB_clk = PLB_clk / D; - D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */ -#ifdef DEBUG_CLOCKS_LL - printf("EPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 8) & 0x3, D); -#endif - EBC_clk = PLB_clk / D; - D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */ -#ifdef DEBUG_CLOCKS_LL - printf("MPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 4) & 0x3, D); -#endif - MAL_clk = PLB_clk / D; - D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */ -#ifdef DEBUG_CLOCKS_LL - printf("PPDV %01" PRIx32 " %d\n", cpc->pllmr[0] & 0x3, D); -#endif - PCI_clk = PLB_clk / D; - D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */ -#ifdef DEBUG_CLOCKS_LL - printf("U0DIV %01" PRIx32 " %d\n", cpc->ucr & 0x7F, D); -#endif - UART0_clk = PLL_out / D; - D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */ -#ifdef DEBUG_CLOCKS_LL - printf("U1DIV %01" PRIx32 " %d\n", (cpc->ucr >> 8) & 0x7F, D); -#endif - UART1_clk = PLL_out / D; -#ifdef DEBUG_CLOCKS - printf("Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64 - " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out); - printf("CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32 - " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32 - " UART1 %" PRIu32 "\n", - CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk, - UART0_clk, UART1_clk); -#endif - /* Setup CPU clocks */ - clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk); - /* Setup PLB clock */ - clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk); - /* Setup OPB clock */ - clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk); - /* Setup external clock */ - clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk); - /* Setup MAL clock */ - clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk); - /* Setup PCI clock */ - clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk); - /* Setup UART0 clock */ - clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk); - /* Setup UART1 clock */ - clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk); -} - -static uint32_t dcr_read_epcpc (void *opaque, int dcrn) -{ - ppc405ep_cpc_t *cpc; - uint32_t ret; - - cpc = opaque; - switch (dcrn) { - case PPC405EP_CPC0_BOOT: - ret = cpc->boot; - break; - case PPC405EP_CPC0_EPCTL: - ret = cpc->epctl; - break; - case PPC405EP_CPC0_PLLMR0: - ret = cpc->pllmr[0]; - break; - case PPC405EP_CPC0_PLLMR1: - ret = cpc->pllmr[1]; - break; - case PPC405EP_CPC0_UCR: - ret = cpc->ucr; - break; - case PPC405EP_CPC0_SRR: - ret = cpc->srr; - break; - case PPC405EP_CPC0_JTAGID: - ret = cpc->jtagid; - break; - case PPC405EP_CPC0_PCI: - ret = cpc->pci; - break; - default: - /* Avoid gcc warning */ - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val) -{ - ppc405ep_cpc_t *cpc; - - cpc = opaque; - switch (dcrn) { - case PPC405EP_CPC0_BOOT: - /* Read-only register */ - break; - case PPC405EP_CPC0_EPCTL: - /* Don't care for now */ - cpc->epctl = val & 0xC00000F3; - break; - case PPC405EP_CPC0_PLLMR0: - cpc->pllmr[0] = val & 0x00633333; - ppc405ep_compute_clocks(cpc); - break; - case PPC405EP_CPC0_PLLMR1: - cpc->pllmr[1] = val & 0xC0F73FFF; - ppc405ep_compute_clocks(cpc); - break; - case PPC405EP_CPC0_UCR: - /* UART control - don't care for now */ - cpc->ucr = val & 0x003F7F7F; - break; - case PPC405EP_CPC0_SRR: - cpc->srr = val; - break; - case PPC405EP_CPC0_JTAGID: - /* Read-only */ - break; - case PPC405EP_CPC0_PCI: - cpc->pci = val; - break; - } -} - -static void ppc405ep_cpc_reset (void *opaque) -{ - ppc405ep_cpc_t *cpc = opaque; - - cpc->boot = 0x00000010; /* Boot from PCI - IIC EEPROM disabled */ - cpc->epctl = 0x00000000; - cpc->pllmr[0] = 0x00011010; - cpc->pllmr[1] = 0x40000000; - cpc->ucr = 0x00000000; - cpc->srr = 0x00040000; - cpc->pci = 0x00000000; - cpc->er = 0x00000000; - cpc->fr = 0x00000000; - cpc->sr = 0x00000000; - ppc405ep_compute_clocks(cpc); -} - -/* XXX: sysclk should be between 25 and 100 MHz */ -static void ppc405ep_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[8], - uint32_t sysclk) -{ - ppc405ep_cpc_t *cpc; - - cpc = g_malloc0(sizeof(ppc405ep_cpc_t)); - memcpy(cpc->clk_setup, clk_setup, - PPC405EP_CLK_NB * sizeof(clk_setup_t)); - cpc->jtagid = 0x20267049; - cpc->sysclk = sysclk; - qemu_register_reset(&ppc405ep_cpc_reset, cpc); - ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); -#if 0 - ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); -#endif -} - -CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, - MemoryRegion ram_memories[2], - hwaddr ram_bases[2], - hwaddr ram_sizes[2], - uint32_t sysclk, qemu_irq **picp, - int do_init) -{ - clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; - qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; - PowerPCCPU *cpu; - CPUPPCState *env; - qemu_irq *pic, *irqs; - - memset(clk_setup, 0, sizeof(clk_setup)); - /* init CPUs */ - cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], - &tlb_clk_setup, sysclk); - env = &cpu->env; - clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; - clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; - /* Internal devices init */ - /* Memory mapped devices registers */ - /* PLB arbitrer */ - ppc4xx_plb_init(env); - /* PLB to OPB bridge */ - ppc4xx_pob_init(env); - /* OBP arbitrer */ - ppc4xx_opba_init(0xef600600); - /* Initialize timers */ - ppc_booke_timers_init(cpu, sysclk, 0); - /* Universal interrupt controller */ - irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); - irqs[PPCUIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; - irqs[PPCUIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; - pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); - *picp = pic; - /* SDRAM controller */ - /* XXX 405EP has no ECC interrupt */ - ppc4xx_sdram_init(env, pic[17], 2, ram_memories, - ram_bases, ram_sizes, do_init); - /* External bus controller */ - ppc405_ebc_init(env); - /* DMA controller */ - dma_irqs[0] = pic[5]; - dma_irqs[1] = pic[6]; - dma_irqs[2] = pic[7]; - dma_irqs[3] = pic[8]; - ppc405_dma_init(env, dma_irqs); - /* IIC controller */ - ppc405_i2c_init(0xef600500, pic[2]); - /* GPIO */ - ppc405_gpio_init(0xef600700); - /* Serial ports */ - if (serial_hds[0] != NULL) { - serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], - PPC_SERIAL_MM_BAUDBASE, serial_hds[0], - DEVICE_BIG_ENDIAN); - } - if (serial_hds[1] != NULL) { - serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], - PPC_SERIAL_MM_BAUDBASE, serial_hds[1], - DEVICE_BIG_ENDIAN); - } - /* OCM */ - ppc405_ocm_init(env); - /* GPT */ - gpt_irqs[0] = pic[19]; - gpt_irqs[1] = pic[20]; - gpt_irqs[2] = pic[21]; - gpt_irqs[3] = pic[22]; - gpt_irqs[4] = pic[23]; - ppc4xx_gpt_init(0xef600000, gpt_irqs); - /* PCI */ - /* Uses pic[3], pic[16], pic[18] */ - /* MAL */ - mal_irqs[0] = pic[11]; - mal_irqs[1] = pic[12]; - mal_irqs[2] = pic[13]; - mal_irqs[3] = pic[14]; - ppc405_mal_init(env, mal_irqs); - /* Ethernet */ - /* Uses pic[9], pic[15], pic[17] */ - /* CPU control */ - ppc405ep_cpc_init(env, clk_setup, sysclk); - - return env; -} diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c deleted file mode 100644 index 66911b58c6..0000000000 --- a/hw/ppc440_bamboo.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * QEMU PowerPC 440 Bamboo board emulation - * - * Copyright 2007 IBM Corporation. - * Authors: - * Jerone Young - * Christian Ehrhardt - * Hollis Blanchard - * - * This work is licensed under the GNU GPL license version 2 or later. - * - */ - -#include "config.h" -#include "qemu-common.h" -#include "net/net.h" -#include "hw/hw.h" -#include "hw/pci/pci.h" -#include "hw/boards.h" -#include "sysemu/kvm.h" -#include "kvm_ppc.h" -#include "sysemu/device_tree.h" -#include "hw/loader.h" -#include "elf.h" -#include "exec/address-spaces.h" -#include "hw/serial.h" -#include "hw/ppc.h" -#include "hw/ppc405.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" - -#define BINARY_DEVICE_TREE_FILE "bamboo.dtb" - -/* from u-boot */ -#define KERNEL_ADDR 0x1000000 -#define FDT_ADDR 0x1800000 -#define RAMDISK_ADDR 0x1900000 - -#define PPC440EP_PCI_CONFIG 0xeec00000 -#define PPC440EP_PCI_INTACK 0xeed00000 -#define PPC440EP_PCI_SPECIAL 0xeed00000 -#define PPC440EP_PCI_REGS 0xef400000 -#define PPC440EP_PCI_IO 0xe8000000 -#define PPC440EP_PCI_IOLEN 0x00010000 - -#define PPC440EP_SDRAM_NR_BANKS 4 - -static const unsigned int ppc440ep_sdram_bank_sizes[] = { - 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0 -}; - -static hwaddr entry; - -static int bamboo_load_device_tree(hwaddr addr, - uint32_t ramsize, - hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) -{ - int ret = -1; -#ifdef CONFIG_FDT - uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; - char *filename; - int fdt_size; - void *fdt; - uint32_t tb_freq = 400000000; - uint32_t clock_freq = 400000000; - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); - if (!filename) { - goto out; - } - fdt = load_device_tree(filename, &fdt_size); - g_free(filename); - if (fdt == NULL) { - goto out; - } - - /* Manipulate device tree in memory. */ - - ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, - sizeof(mem_reg_property)); - if (ret < 0) - fprintf(stderr, "couldn't set /memory/reg\n"); - - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - initrd_base); - if (ret < 0) - fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); - - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - (initrd_base + initrd_size)); - if (ret < 0) - fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); - - ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - kernel_cmdline); - if (ret < 0) - fprintf(stderr, "couldn't set /chosen/bootargs\n"); - - /* Copy data from the host device tree into the guest. Since the guest can - * directly access the timebase without host involvement, we must expose - * the correct frequencies. */ - if (kvm_enabled()) { - tb_freq = kvmppc_get_tbfreq(); - clock_freq = kvmppc_get_clockfreq(); - } - - qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency", - clock_freq); - qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency", - tb_freq); - - ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); - g_free(fdt); - -out: -#endif - - return ret; -} - -/* Create reset TLB entries for BookE, spanning the 32bit addr space. */ -static void mmubooke_create_initial_mapping(CPUPPCState *env, - target_ulong va, - hwaddr pa) -{ - ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; - - tlb->attr = 0; - tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); - tlb->size = 1 << 31; /* up to 0x80000000 */ - tlb->EPN = va & TARGET_PAGE_MASK; - tlb->RPN = pa & TARGET_PAGE_MASK; - tlb->PID = 0; - - tlb = &env->tlb.tlbe[1]; - tlb->attr = 0; - tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); - tlb->size = 1 << 31; /* up to 0xffffffff */ - tlb->EPN = 0x80000000 & TARGET_PAGE_MASK; - tlb->RPN = 0x80000000 & TARGET_PAGE_MASK; - tlb->PID = 0; -} - -static void main_cpu_reset(void *opaque) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - - cpu_reset(CPU(cpu)); - env->gpr[1] = (16<<20) - 8; - env->gpr[3] = FDT_ADDR; - env->nip = entry; - - /* Create a mapping for the kernel. */ - mmubooke_create_initial_mapping(env, 0, 0); -} - -static void bamboo_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram_memories - = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); - hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS]; - hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS]; - qemu_irq *pic; - qemu_irq *irqs; - PCIBus *pcibus; - PowerPCCPU *cpu; - CPUPPCState *env; - uint64_t elf_entry; - uint64_t elf_lowaddr; - hwaddr loadaddr = 0; - target_long initrd_size = 0; - DeviceState *dev; - int success; - int i; - - /* Setup CPU. */ - if (cpu_model == NULL) { - cpu_model = "440EP"; - } - cpu = cpu_ppc_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to initialize CPU!\n"); - exit(1); - } - env = &cpu->env; - - qemu_register_reset(main_cpu_reset, cpu); - ppc_booke_timers_init(cpu, 400000000, 0); - ppc_dcr_init(env, NULL, NULL); - - /* interrupt controller */ - irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); - irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; - irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; - pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); - - /* SDRAM controller */ - memset(ram_bases, 0, sizeof(ram_bases)); - memset(ram_sizes, 0, sizeof(ram_sizes)); - ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS, - ram_memories, - ram_bases, ram_sizes, - ppc440ep_sdram_bank_sizes); - /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ - ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, 1); - - /* PCI */ - dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE, - PPC440EP_PCI_CONFIG, - pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]], - pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]], - NULL); - pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); - if (!pcibus) { - fprintf(stderr, "couldn't create PCI controller!\n"); - exit(1); - } - - isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN); - - if (serial_hds[0] != NULL) { - serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], - PPC_SERIAL_MM_BAUDBASE, serial_hds[0], - DEVICE_BIG_ENDIAN); - } - if (serial_hds[1] != NULL) { - serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], - PPC_SERIAL_MM_BAUDBASE, serial_hds[1], - DEVICE_BIG_ENDIAN); - } - - if (pcibus) { - /* Register network interfaces. */ - for (i = 0; i < nb_nics; i++) { - /* There are no PCI NICs on the Bamboo board, but there are - * PCI slots, so we can pick whatever default model we want. */ - pci_nic_init_nofail(&nd_table[i], "e1000", NULL); - } - } - - /* Load kernel. */ - if (kernel_filename) { - success = load_uimage(kernel_filename, &entry, &loadaddr, NULL); - if (success < 0) { - success = load_elf(kernel_filename, NULL, NULL, &elf_entry, - &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); - entry = elf_entry; - loadaddr = elf_lowaddr; - } - /* XXX try again as binary */ - if (success < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - } - - /* Load initrd. */ - if (initrd_filename) { - initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR, - ram_size - RAMDISK_ADDR); - - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n", - initrd_filename, RAMDISK_ADDR); - exit(1); - } - } - - /* If we're loading a kernel directly, we must load the device tree too. */ - if (kernel_filename) { - if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR, - initrd_size, kernel_cmdline) < 0) { - fprintf(stderr, "couldn't load device tree\n"); - exit(1); - } - } - - if (kvm_enabled()) - kvmppc_init(); -} - -static QEMUMachine bamboo_machine = { - .name = "bamboo", - .desc = "bamboo", - .init = bamboo_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void bamboo_machine_init(void) -{ - qemu_register_machine(&bamboo_machine); -} - -machine_init(bamboo_machine_init); diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c deleted file mode 100644 index 30375c0c41..0000000000 --- a/hw/ppc_booke.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * QEMU PowerPC Booke hardware System Emulator - * - * Copyright (c) 2011 AdaCore - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/ppc.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "hw/nvram.h" -#include "qemu/log.h" -#include "hw/loader.h" - - -/* Timer Control Register */ - -#define TCR_WP_SHIFT 30 /* Watchdog Timer Period */ -#define TCR_WP_MASK (0x3 << TCR_WP_SHIFT) -#define TCR_WRC_SHIFT 28 /* Watchdog Timer Reset Control */ -#define TCR_WRC_MASK (0x3 << TCR_WRC_SHIFT) -#define TCR_WIE (1 << 27) /* Watchdog Timer Interrupt Enable */ -#define TCR_DIE (1 << 26) /* Decrementer Interrupt Enable */ -#define TCR_FP_SHIFT 24 /* Fixed-Interval Timer Period */ -#define TCR_FP_MASK (0x3 << TCR_FP_SHIFT) -#define TCR_FIE (1 << 23) /* Fixed-Interval Timer Interrupt Enable */ -#define TCR_ARE (1 << 22) /* Auto-Reload Enable */ - -/* Timer Control Register (e500 specific fields) */ - -#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */ -#define TCR_E500_FPEXT_MASK (0xf << TCR_E500_FPEXT_SHIFT) -#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */ -#define TCR_E500_WPEXT_MASK (0xf << TCR_E500_WPEXT_SHIFT) - -/* Timer Status Register */ - -#define TSR_FIS (1 << 26) /* Fixed-Interval Timer Interrupt Status */ -#define TSR_DIS (1 << 27) /* Decrementer Interrupt Status */ -#define TSR_WRS_SHIFT 28 /* Watchdog Timer Reset Status */ -#define TSR_WRS_MASK (0x3 << TSR_WRS_SHIFT) -#define TSR_WIS (1 << 30) /* Watchdog Timer Interrupt Status */ -#define TSR_ENW (1 << 31) /* Enable Next Watchdog Timer */ - -typedef struct booke_timer_t booke_timer_t; -struct booke_timer_t { - - uint64_t fit_next; - struct QEMUTimer *fit_timer; - - uint64_t wdt_next; - struct QEMUTimer *wdt_timer; - - uint32_t flags; -}; - -static void booke_update_irq(PowerPCCPU *cpu) -{ - CPUPPCState *env = &cpu->env; - - ppc_set_irq(cpu, PPC_INTERRUPT_DECR, - (env->spr[SPR_BOOKE_TSR] & TSR_DIS - && env->spr[SPR_BOOKE_TCR] & TCR_DIE)); - - ppc_set_irq(cpu, PPC_INTERRUPT_WDT, - (env->spr[SPR_BOOKE_TSR] & TSR_WIS - && env->spr[SPR_BOOKE_TCR] & TCR_WIE)); - - ppc_set_irq(cpu, PPC_INTERRUPT_FIT, - (env->spr[SPR_BOOKE_TSR] & TSR_FIS - && env->spr[SPR_BOOKE_TCR] & TCR_FIE)); -} - -/* Return the location of the bit of time base at which the FIT will raise an - interrupt */ -static uint8_t booke_get_fit_target(CPUPPCState *env, ppc_tb_t *tb_env) -{ - uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT; - - if (tb_env->flags & PPC_TIMER_E500) { - /* e500 Fixed-interval timer period extension */ - uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK) - >> TCR_E500_FPEXT_SHIFT; - fp = 63 - (fp | fpext << 2); - } else { - fp = env->fit_period[fp]; - } - - return fp; -} - -/* Return the location of the bit of time base at which the WDT will raise an - interrupt */ -static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env) -{ - uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT; - - if (tb_env->flags & PPC_TIMER_E500) { - /* e500 Watchdog timer period extension */ - uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK) - >> TCR_E500_WPEXT_SHIFT; - wp = 63 - (wp | wpext << 2); - } else { - wp = env->wdt_period[wp]; - } - - return wp; -} - -static void booke_update_fixed_timer(CPUPPCState *env, - uint8_t target_bit, - uint64_t *next, - struct QEMUTimer *timer) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t lapse; - uint64_t tb; - uint64_t period = 1 << (target_bit + 1); - uint64_t now; - - now = qemu_get_clock_ns(vm_clock); - tb = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset); - - lapse = period - ((tb - (1 << target_bit)) & (period - 1)); - - *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq); - - /* XXX: If expire time is now. We can't run the callback because we don't - * have access to it. So we just set the timer one nanosecond later. - */ - - if (*next == now) { - (*next)++; - } - - qemu_mod_timer(timer, *next); -} - -static void booke_decr_cb(void *opaque) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - - env->spr[SPR_BOOKE_TSR] |= TSR_DIS; - booke_update_irq(cpu); - - if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) { - /* Auto Reload */ - cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]); - } -} - -static void booke_fit_cb(void *opaque) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - ppc_tb_t *tb_env; - booke_timer_t *booke_timer; - - tb_env = env->tb_env; - booke_timer = tb_env->opaque; - env->spr[SPR_BOOKE_TSR] |= TSR_FIS; - - booke_update_irq(cpu); - - booke_update_fixed_timer(env, - booke_get_fit_target(env, tb_env), - &booke_timer->fit_next, - booke_timer->fit_timer); -} - -static void booke_wdt_cb(void *opaque) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - ppc_tb_t *tb_env; - booke_timer_t *booke_timer; - - tb_env = env->tb_env; - booke_timer = tb_env->opaque; - - /* TODO: There's lots of complicated stuff to do here */ - - booke_update_irq(cpu); - - booke_update_fixed_timer(env, - booke_get_wdt_target(env, tb_env), - &booke_timer->wdt_next, - booke_timer->wdt_timer); -} - -void store_booke_tsr(CPUPPCState *env, target_ulong val) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - - env->spr[SPR_BOOKE_TSR] &= ~val; - booke_update_irq(cpu); -} - -void store_booke_tcr(CPUPPCState *env, target_ulong val) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - ppc_tb_t *tb_env = env->tb_env; - booke_timer_t *booke_timer = tb_env->opaque; - - tb_env = env->tb_env; - env->spr[SPR_BOOKE_TCR] = val; - - booke_update_irq(cpu); - - booke_update_fixed_timer(env, - booke_get_fit_target(env, tb_env), - &booke_timer->fit_next, - booke_timer->fit_timer); - - booke_update_fixed_timer(env, - booke_get_wdt_target(env, tb_env), - &booke_timer->wdt_next, - booke_timer->wdt_timer); - -} - -static void ppc_booke_timer_reset_handle(void *opaque) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - - env->spr[SPR_BOOKE_TSR] = 0; - env->spr[SPR_BOOKE_TCR] = 0; - - booke_update_irq(cpu); -} - -void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) -{ - ppc_tb_t *tb_env; - booke_timer_t *booke_timer; - - tb_env = g_malloc0(sizeof(ppc_tb_t)); - booke_timer = g_malloc0(sizeof(booke_timer_t)); - - cpu->env.tb_env = tb_env; - tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED; - - tb_env->tb_freq = freq; - tb_env->decr_freq = freq; - tb_env->opaque = booke_timer; - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu); - - booke_timer->fit_timer = - qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); - booke_timer->wdt_timer = - qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); - - qemu_register_reset(ppc_booke_timer_reset_handle, cpu); -} diff --git a/hw/puv3.c b/hw/puv3.c deleted file mode 100644 index f9d0c2bab1..0000000000 --- a/hw/puv3.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Generic PKUnity SoC machine and board descriptor - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu-common.h" -#include "ui/console.h" -#include "elf.h" -#include "exec/address-spaces.h" -#include "hw/sysbus.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/pc.h" - -#undef DEBUG_PUV3 -#include "hw/puv3.h" - -#define KERNEL_LOAD_ADDR 0x03000000 -#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ - -static void puv3_intc_cpu_handler(void *opaque, int irq, int level) -{ - CPUUniCore32State *env = opaque; - - assert(irq == 0); - if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -static void puv3_soc_init(CPUUniCore32State *env) -{ - qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR]; - DeviceState *dev; - MemoryRegion *i8042 = g_new(MemoryRegion, 1); - int i; - - /* Initialize interrupt controller */ - cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1); - dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc); - for (i = 0; i < PUV3_IRQS_NR; i++) { - irqs[i] = qdev_get_gpio_in(dev, i); - } - - /* Initialize minimal necessary devices for kernel booting */ - sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL); - sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL); - sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]); - sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE, - irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1], - irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3], - irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5], - irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7], - irqs[PUV3_IRQS_GPIOHIGH], NULL); - - /* Keyboard (i8042), mouse disabled for nographic */ - i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4); - memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042); -} - -static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size) -{ - MemoryRegion *ram_memory = g_new(MemoryRegion, 1); - - /* SDRAM at address zero. */ - memory_region_init_ram(ram_memory, "puv3.ram", ram_size); - vmstate_register_ram_global(ram_memory); - memory_region_add_subregion(get_system_memory(), 0, ram_memory); -} - -static void puv3_load_kernel(const char *kernel_filename) -{ - int size; - - assert(kernel_filename != NULL); - - /* only zImage format supported */ - size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, - KERNEL_MAX_SIZE); - if (size < 0) { - hw_error("Load kernel error: '%s'\n", kernel_filename); - } - - /* cheat curses that we have a graphic console, only under ocd console */ - graphic_console_init(NULL, NULL, NULL, NULL, NULL); -} - -static void puv3_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *initrd_filename = args->initrd_filename; - CPUUniCore32State *env; - - if (initrd_filename) { - hw_error("Please use kernel built-in initramdisk.\n"); - } - - if (!cpu_model) { - cpu_model = "UniCore-II"; - } - - env = cpu_init(cpu_model); - if (!env) { - hw_error("Unable to find CPU definition\n"); - } - - puv3_soc_init(env); - puv3_board_init(env, ram_size); - puv3_load_kernel(kernel_filename); -} - -static QEMUMachine puv3_machine = { - .name = "puv3", - .desc = "PKUnity Version-3 based on UniCore32", - .init = puv3_init, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void puv3_machine_init(void) -{ - qemu_register_machine(&puv3_machine); -} - -machine_init(puv3_machine_init) diff --git a/hw/r2d.c b/hw/r2d.c deleted file mode 100644 index faa03d2069..0000000000 --- a/hw/r2d.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Renesas SH7751R R2D-PLUS emulation - * - * Copyright (c) 2007 Magnus Damm - * Copyright (c) 2008 Paul Mundt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "hw/sh.h" -#include "hw/devices.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/pci/pci.h" -#include "net/net.h" -#include "hw/sh7750_regs.h" -#include "hw/ide.h" -#include "hw/loader.h" -#include "hw/usb.h" -#include "hw/flash.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#define FLASH_BASE 0x00000000 -#define FLASH_SIZE 0x02000000 - -#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ -#define SDRAM_SIZE 0x04000000 - -#define SM501_VRAM_SIZE 0x800000 - -#define BOOT_PARAMS_OFFSET 0x0010000 -/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */ -#define LINUX_LOAD_OFFSET 0x0800000 -#define INITRD_LOAD_OFFSET 0x1800000 - -#define PA_IRLMSK 0x00 -#define PA_POWOFF 0x30 -#define PA_VERREG 0x32 -#define PA_OUTPORT 0x36 - -typedef struct { - uint16_t bcr; - uint16_t irlmsk; - uint16_t irlmon; - uint16_t cfctl; - uint16_t cfpow; - uint16_t dispctl; - uint16_t sdmpow; - uint16_t rtcce; - uint16_t pcicd; - uint16_t voyagerrts; - uint16_t cfrst; - uint16_t admrts; - uint16_t extrst; - uint16_t cfcdintclr; - uint16_t keyctlclr; - uint16_t pad0; - uint16_t pad1; - uint16_t verreg; - uint16_t inport; - uint16_t outport; - uint16_t bverreg; - -/* output pin */ - qemu_irq irl; - MemoryRegion iomem; -} r2d_fpga_t; - -enum r2d_fpga_irq { - PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T, - SDCARD, PCI_INTA, PCI_INTB, EXT, TP, - NR_IRQS -}; - -static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = { - [CF_IDE] = { 1, 1<<9 }, - [CF_CD] = { 2, 1<<8 }, - [PCI_INTA] = { 9, 1<<14 }, - [PCI_INTB] = { 10, 1<<13 }, - [PCI_INTC] = { 3, 1<<12 }, - [PCI_INTD] = { 0, 1<<11 }, - [SM501] = { 4, 1<<10 }, - [KEY] = { 5, 1<<6 }, - [RTC_A] = { 6, 1<<5 }, - [RTC_T] = { 7, 1<<4 }, - [SDCARD] = { 8, 1<<7 }, - [EXT] = { 11, 1<<0 }, - [TP] = { 12, 1<<15 }, -}; - -static void update_irl(r2d_fpga_t *fpga) -{ - int i, irl = 15; - for (i = 0; i < NR_IRQS; i++) - if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk) - if (irqtab[i].irl < irl) - irl = irqtab[i].irl; - qemu_set_irq(fpga->irl, irl ^ 15); -} - -static void r2d_fpga_irq_set(void *opaque, int n, int level) -{ - r2d_fpga_t *fpga = opaque; - if (level) - fpga->irlmon |= irqtab[n].msk; - else - fpga->irlmon &= ~irqtab[n].msk; - update_irl(fpga); -} - -static uint32_t r2d_fpga_read(void *opaque, hwaddr addr) -{ - r2d_fpga_t *s = opaque; - - switch (addr) { - case PA_IRLMSK: - return s->irlmsk; - case PA_OUTPORT: - return s->outport; - case PA_POWOFF: - return 0x00; - case PA_VERREG: - return 0x10; - } - - return 0; -} - -static void -r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value) -{ - r2d_fpga_t *s = opaque; - - switch (addr) { - case PA_IRLMSK: - s->irlmsk = value; - update_irl(s); - break; - case PA_OUTPORT: - s->outport = value; - break; - case PA_POWOFF: - if (value & 1) { - qemu_system_shutdown_request(); - } - break; - case PA_VERREG: - /* Discard writes */ - break; - } -} - -static const MemoryRegionOps r2d_fpga_ops = { - .old_mmio = { - .read = { r2d_fpga_read, r2d_fpga_read, NULL, }, - .write = { r2d_fpga_write, r2d_fpga_write, NULL, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem, - hwaddr base, qemu_irq irl) -{ - r2d_fpga_t *s; - - s = g_malloc0(sizeof(r2d_fpga_t)); - - s->irl = irl; - - memory_region_init_io(&s->iomem, &r2d_fpga_ops, s, "r2d-fpga", 0x40); - memory_region_add_subregion(sysmem, base, &s->iomem); - return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS); -} - -typedef struct ResetData { - SuperHCPU *cpu; - uint32_t vector; -} ResetData; - -static void main_cpu_reset(void *opaque) -{ - ResetData *s = (ResetData *)opaque; - CPUSH4State *env = &s->cpu->env; - - cpu_reset(CPU(s->cpu)); - env->pc = s->vector; -} - -static struct QEMU_PACKED -{ - int mount_root_rdonly; - int ramdisk_flags; - int orig_root_dev; - int loader_type; - int initrd_start; - int initrd_size; - - char pad[232]; - - char kernel_cmdline[256]; -} boot_params; - -static void r2d_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - SuperHCPU *cpu; - CPUSH4State *env; - ResetData *reset_info; - struct SH7750State *s; - MemoryRegion *sdram = g_new(MemoryRegion, 1); - qemu_irq *irq; - DriveInfo *dinfo; - int i; - DeviceState *dev; - SysBusDevice *busdev; - MemoryRegion *address_space_mem = get_system_memory(); - - if (cpu_model == NULL) { - cpu_model = "SH7751R"; - } - - cpu = cpu_sh4_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - reset_info = g_malloc0(sizeof(ResetData)); - reset_info->cpu = cpu; - reset_info->vector = env->pc; - qemu_register_reset(main_cpu_reset, reset_info); - - /* Allocate memory space */ - memory_region_init_ram(sdram, "r2d.sdram", SDRAM_SIZE); - vmstate_register_ram_global(sdram); - memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram); - /* Register peripherals */ - s = sh7750_init(env, address_space_mem); - irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s)); - - dev = qdev_create(NULL, "sh_pci"); - busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); - sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000)); - sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000)); - sysbus_connect_irq(busdev, 0, irq[PCI_INTA]); - sysbus_connect_irq(busdev, 1, irq[PCI_INTB]); - sysbus_connect_irq(busdev, 2, irq[PCI_INTC]); - sysbus_connect_irq(busdev, 3, irq[PCI_INTD]); - - sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE, - irq[SM501], serial_hds[2]); - - /* onboard CF (True IDE mode, Master only). */ - dinfo = drive_get(IF_IDE, 0, 0); - dev = qdev_create(NULL, "mmio-ide"); - busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, irq[CF_IDE]); - qdev_prop_set_uint32(dev, "shift", 1); - qdev_init_nofail(dev); - sysbus_mmio_map(busdev, 0, 0x14001000); - sysbus_mmio_map(busdev, 1, 0x1400080c); - mmio_ide_init_drives(dev, dinfo, NULL); - - /* onboard flash memory */ - dinfo = drive_get(IF_PFLASH, 0, 0); - pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE, - dinfo ? dinfo->bdrv : NULL, (16 * 1024), - FLASH_SIZE >> 16, - 1, 4, 0x0000, 0x0000, 0x0000, 0x0000, - 0x555, 0x2aa, 0); - - /* NIC: rtl8139 on-board, and 2 slots. */ - for (i = 0; i < nb_nics; i++) - pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL); - - /* USB keyboard */ - usbdevice_create("keyboard"); - - /* Todo: register on board registers */ - memset(&boot_params, 0, sizeof(boot_params)); - - if (kernel_filename) { - int kernel_size; - - kernel_size = load_image_targphys(kernel_filename, - SDRAM_BASE + LINUX_LOAD_OFFSET, - INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } - - /* initialization which should be done by firmware */ - stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */ - stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */ - reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */ - } - - if (initrd_filename) { - int initrd_size; - - initrd_size = load_image_targphys(initrd_filename, - SDRAM_BASE + INITRD_LOAD_OFFSET, - SDRAM_SIZE - INITRD_LOAD_OFFSET); - - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename); - exit(1); - } - - /* initialization which should be done by firmware */ - boot_params.loader_type = 1; - boot_params.initrd_start = INITRD_LOAD_OFFSET; - boot_params.initrd_size = initrd_size; - } - - if (kernel_cmdline) { - /* I see no evidence that this .kernel_cmdline buffer requires - NUL-termination, so using strncpy should be ok. */ - strncpy(boot_params.kernel_cmdline, kernel_cmdline, - sizeof(boot_params.kernel_cmdline)); - } - - rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params), - SDRAM_BASE + BOOT_PARAMS_OFFSET); -} - -static QEMUMachine r2d_machine = { - .name = "r2d", - .desc = "r2d-plus board", - .init = r2d_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void r2d_machine_init(void) -{ - qemu_register_machine(&r2d_machine); -} - -machine_init(r2d_machine_init); diff --git a/hw/realview.c b/hw/realview.c deleted file mode 100644 index 5fb490c832..0000000000 --- a/hw/realview.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * ARM RealView Baseboard System emulation. - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "hw/primecell.h" -#include "hw/devices.h" -#include "hw/pci/pci.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/i2c.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -#define SMP_BOOT_ADDR 0xe0000000 -#define SMP_BOOTREG_ADDR 0x10000030 - -/* Board init. */ - -static struct arm_boot_info realview_binfo = { - .smp_loader_start = SMP_BOOT_ADDR, - .smp_bootreg_addr = SMP_BOOTREG_ADDR, -}; - -/* The following two lists must be consistent. */ -enum realview_board_type { - BOARD_EB, - BOARD_EB_MPCORE, - BOARD_PB_A8, - BOARD_PBX_A9, -}; - -static const int realview_board_id[] = { - 0x33b, - 0x33b, - 0x769, - 0x76d -}; - -static void realview_init(QEMUMachineInitArgs *args, - enum realview_board_type board_type) -{ - ARMCPU *cpu = NULL; - CPUARMState *env; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram_lo = g_new(MemoryRegion, 1); - MemoryRegion *ram_hi = g_new(MemoryRegion, 1); - MemoryRegion *ram_alias = g_new(MemoryRegion, 1); - MemoryRegion *ram_hack = g_new(MemoryRegion, 1); - DeviceState *dev, *sysctl, *gpio2, *pl041; - SysBusDevice *busdev; - qemu_irq *irqp; - qemu_irq pic[64]; - qemu_irq mmc_irq[2]; - PCIBus *pci_bus; - NICInfo *nd; - i2c_bus *i2c; - int n; - int done_nic = 0; - qemu_irq cpu_irq[4]; - int is_mpcore = 0; - int is_pb = 0; - uint32_t proc_id = 0; - uint32_t sys_id; - ram_addr_t low_ram_size; - ram_addr_t ram_size = args->ram_size; - - switch (board_type) { - case BOARD_EB: - break; - case BOARD_EB_MPCORE: - is_mpcore = 1; - break; - case BOARD_PB_A8: - is_pb = 1; - break; - case BOARD_PBX_A9: - is_mpcore = 1; - is_pb = 1; - break; - } - for (n = 0; n < smp_cpus; n++) { - cpu = cpu_arm_init(args->cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; - } - env = &cpu->env; - if (arm_feature(env, ARM_FEATURE_V7)) { - if (is_mpcore) { - proc_id = 0x0c000000; - } else { - proc_id = 0x0e000000; - } - } else if (arm_feature(env, ARM_FEATURE_V6K)) { - proc_id = 0x06000000; - } else if (arm_feature(env, ARM_FEATURE_V6)) { - proc_id = 0x04000000; - } else { - proc_id = 0x02000000; - } - - if (is_pb && ram_size > 0x20000000) { - /* Core tile RAM. */ - low_ram_size = ram_size - 0x20000000; - ram_size = 0x20000000; - memory_region_init_ram(ram_lo, "realview.lowmem", low_ram_size); - vmstate_register_ram_global(ram_lo); - memory_region_add_subregion(sysmem, 0x20000000, ram_lo); - } - - memory_region_init_ram(ram_hi, "realview.highmem", ram_size); - vmstate_register_ram_global(ram_hi); - low_ram_size = ram_size; - if (low_ram_size > 0x10000000) - low_ram_size = 0x10000000; - /* SDRAM at address zero. */ - memory_region_init_alias(ram_alias, "realview.alias", - ram_hi, 0, low_ram_size); - memory_region_add_subregion(sysmem, 0, ram_alias); - if (is_pb) { - /* And again at a high address. */ - memory_region_add_subregion(sysmem, 0x70000000, ram_hi); - } else { - ram_size = low_ram_size; - } - - sys_id = is_pb ? 0x01780500 : 0xc1400400; - sysctl = qdev_create(NULL, "realview_sysctl"); - qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_prop_set_uint32(sysctl, "proc_id", proc_id); - qdev_init_nofail(sysctl); - sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); - - if (is_mpcore) { - hwaddr periphbase; - dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore"); - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - if (is_pb) { - periphbase = 0x1f000000; - } else { - periphbase = 0x10100000; - } - sysbus_mmio_map(busdev, 0, periphbase); - for (n = 0; n < smp_cpus; n++) { - sysbus_connect_irq(busdev, n, cpu_irq[n]); - } - sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL); - /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */ - realview_binfo.gic_cpu_if_addr = periphbase + 0x100; - } else { - uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000; - /* For now just create the nIRQ GIC, and ignore the others. */ - dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]); - } - for (n = 0; n < 64; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - pl041 = qdev_create(NULL, "pl041"); - qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); - sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); - sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]); - - sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); - sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]); - - sysbus_create_simple("pl011", 0x10009000, pic[12]); - sysbus_create_simple("pl011", 0x1000a000, pic[13]); - sysbus_create_simple("pl011", 0x1000b000, pic[14]); - sysbus_create_simple("pl011", 0x1000c000, pic[15]); - - /* DMA controller is optional, apparently. */ - sysbus_create_simple("pl081", 0x10030000, pic[24]); - - sysbus_create_simple("sp804", 0x10011000, pic[4]); - sysbus_create_simple("sp804", 0x10012000, pic[5]); - - sysbus_create_simple("pl061", 0x10013000, pic[6]); - sysbus_create_simple("pl061", 0x10014000, pic[7]); - gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]); - - sysbus_create_simple("pl111", 0x10020000, pic[23]); - - dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL); - /* Wire up MMC card detect and read-only signals. These have - * to go to both the PL061 GPIO and the sysctl register. - * Note that the PL181 orders these lines (readonly,inserted) - * and the PL061 has them the other way about. Also the card - * detect line is inverted. - */ - mmc_irq[0] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT), - qdev_get_gpio_in(gpio2, 1)); - mmc_irq[1] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN), - qemu_irq_invert(qdev_get_gpio_in(gpio2, 0))); - qdev_connect_gpio_out(dev, 0, mmc_irq[0]); - qdev_connect_gpio_out(dev, 1, mmc_irq[1]); - - sysbus_create_simple("pl031", 0x10017000, pic[10]); - - if (!is_pb) { - dev = qdev_create(NULL, "realview_pci"); - busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); - sysbus_mmio_map(busdev, 0, 0x61000000); /* PCI self-config */ - sysbus_mmio_map(busdev, 1, 0x62000000); /* PCI config */ - sysbus_mmio_map(busdev, 2, 0x63000000); /* PCI I/O */ - sysbus_connect_irq(busdev, 0, pic[48]); - sysbus_connect_irq(busdev, 1, pic[49]); - sysbus_connect_irq(busdev, 2, pic[50]); - sysbus_connect_irq(busdev, 3, pic[51]); - pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); - if (usb_enabled(false)) { - pci_create_simple(pci_bus, -1, "pci-ohci"); - } - n = drive_get_max_bus(IF_SCSI); - while (n >= 0) { - pci_create_simple(pci_bus, -1, "lsi53c895a"); - n--; - } - } - for(n = 0; n < nb_nics; n++) { - nd = &nd_table[n]; - - if (!done_nic && (!nd->model || - strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) { - if (is_pb) { - lan9118_init(nd, 0x4e000000, pic[28]); - } else { - smc91c111_init(nd, 0x4e000000, pic[28]); - } - done_nic = 1; - } else { - pci_nic_init_nofail(nd, "rtl8139", NULL); - } - } - - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); - i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "ds1338", 0x68); - - /* Memory map for RealView Emulation Baseboard: */ - /* 0x10000000 System registers. */ - /* 0x10001000 System controller. */ - /* 0x10002000 Two-Wire Serial Bus. */ - /* 0x10003000 Reserved. */ - /* 0x10004000 AACI. */ - /* 0x10005000 MCI. */ - /* 0x10006000 KMI0. */ - /* 0x10007000 KMI1. */ - /* 0x10008000 Character LCD. (EB) */ - /* 0x10009000 UART0. */ - /* 0x1000a000 UART1. */ - /* 0x1000b000 UART2. */ - /* 0x1000c000 UART3. */ - /* 0x1000d000 SSPI. */ - /* 0x1000e000 SCI. */ - /* 0x1000f000 Reserved. */ - /* 0x10010000 Watchdog. */ - /* 0x10011000 Timer 0+1. */ - /* 0x10012000 Timer 2+3. */ - /* 0x10013000 GPIO 0. */ - /* 0x10014000 GPIO 1. */ - /* 0x10015000 GPIO 2. */ - /* 0x10002000 Two-Wire Serial Bus - DVI. (PB) */ - /* 0x10017000 RTC. */ - /* 0x10018000 DMC. */ - /* 0x10019000 PCI controller config. */ - /* 0x10020000 CLCD. */ - /* 0x10030000 DMA Controller. */ - /* 0x10040000 GIC1. (EB) */ - /* 0x10050000 GIC2. (EB) */ - /* 0x10060000 GIC3. (EB) */ - /* 0x10070000 GIC4. (EB) */ - /* 0x10080000 SMC. */ - /* 0x1e000000 GIC1. (PB) */ - /* 0x1e001000 GIC2. (PB) */ - /* 0x1e002000 GIC3. (PB) */ - /* 0x1e003000 GIC4. (PB) */ - /* 0x40000000 NOR flash. */ - /* 0x44000000 DoC flash. */ - /* 0x48000000 SRAM. */ - /* 0x4c000000 Configuration flash. */ - /* 0x4e000000 Ethernet. */ - /* 0x4f000000 USB. */ - /* 0x50000000 PISMO. */ - /* 0x54000000 PISMO. */ - /* 0x58000000 PISMO. */ - /* 0x5c000000 PISMO. */ - /* 0x60000000 PCI. */ - /* 0x61000000 PCI Self Config. */ - /* 0x62000000 PCI Config. */ - /* 0x63000000 PCI IO. */ - /* 0x64000000 PCI mem 0. */ - /* 0x68000000 PCI mem 1. */ - /* 0x6c000000 PCI mem 2. */ - - /* ??? Hack to map an additional page of ram for the secondary CPU - startup code. I guess this works on real hardware because the - BootROM happens to be in ROM/flash or in memory that isn't clobbered - until after Linux boots the secondary CPUs. */ - memory_region_init_ram(ram_hack, "realview.hack", 0x1000); - vmstate_register_ram_global(ram_hack); - memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); - - realview_binfo.ram_size = ram_size; - realview_binfo.kernel_filename = args->kernel_filename; - realview_binfo.kernel_cmdline = args->kernel_cmdline; - realview_binfo.initrd_filename = args->initrd_filename; - realview_binfo.nb_cpus = smp_cpus; - realview_binfo.board_id = realview_board_id[board_type]; - realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); - arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo); -} - -static void realview_eb_init(QEMUMachineInitArgs *args) -{ - if (!args->cpu_model) { - args->cpu_model = "arm926"; - } - realview_init(args, BOARD_EB); -} - -static void realview_eb_mpcore_init(QEMUMachineInitArgs *args) -{ - if (!args->cpu_model) { - args->cpu_model = "arm11mpcore"; - } - realview_init(args, BOARD_EB_MPCORE); -} - -static void realview_pb_a8_init(QEMUMachineInitArgs *args) -{ - if (!args->cpu_model) { - args->cpu_model = "cortex-a8"; - } - realview_init(args, BOARD_PB_A8); -} - -static void realview_pbx_a9_init(QEMUMachineInitArgs *args) -{ - if (!args->cpu_model) { - args->cpu_model = "cortex-a9"; - } - realview_init(args, BOARD_PBX_A9); -} - -static QEMUMachine realview_eb_machine = { - .name = "realview-eb", - .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", - .init = realview_eb_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine realview_eb_mpcore_machine = { - .name = "realview-eb-mpcore", - .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)", - .init = realview_eb_mpcore_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine realview_pb_a8_machine = { - .name = "realview-pb-a8", - .desc = "ARM RealView Platform Baseboard for Cortex-A8", - .init = realview_pb_a8_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine realview_pbx_a9_machine = { - .name = "realview-pbx-a9", - .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9", - .init = realview_pbx_a9_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static void realview_machine_init(void) -{ - qemu_register_machine(&realview_eb_machine); - qemu_register_machine(&realview_eb_mpcore_machine); - qemu_register_machine(&realview_pb_a8_machine); - qemu_register_machine(&realview_pbx_a9_machine); -} - -machine_init(realview_machine_init); diff --git a/hw/sh4/Makefile.objs b/hw/sh4/Makefile.objs index 68c5921790..b2e1f1e044 100644 --- a/hw/sh4/Makefile.objs +++ b/hw/sh4/Makefile.objs @@ -1,5 +1,7 @@ -obj-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o +obj-y = sh7750.o sh7750_regnames.o tc58128.o obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o obj-y += ide/mmio.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += shix.o r2d.o diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c new file mode 100644 index 0000000000..faa03d2069 --- /dev/null +++ b/hw/sh4/r2d.c @@ -0,0 +1,364 @@ +/* + * Renesas SH7751R R2D-PLUS emulation + * + * Copyright (c) 2007 Magnus Damm + * Copyright (c) 2008 Paul Mundt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/devices.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/pci/pci.h" +#include "net/net.h" +#include "hw/sh7750_regs.h" +#include "hw/ide.h" +#include "hw/loader.h" +#include "hw/usb.h" +#include "hw/flash.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +#define FLASH_BASE 0x00000000 +#define FLASH_SIZE 0x02000000 + +#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ +#define SDRAM_SIZE 0x04000000 + +#define SM501_VRAM_SIZE 0x800000 + +#define BOOT_PARAMS_OFFSET 0x0010000 +/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */ +#define LINUX_LOAD_OFFSET 0x0800000 +#define INITRD_LOAD_OFFSET 0x1800000 + +#define PA_IRLMSK 0x00 +#define PA_POWOFF 0x30 +#define PA_VERREG 0x32 +#define PA_OUTPORT 0x36 + +typedef struct { + uint16_t bcr; + uint16_t irlmsk; + uint16_t irlmon; + uint16_t cfctl; + uint16_t cfpow; + uint16_t dispctl; + uint16_t sdmpow; + uint16_t rtcce; + uint16_t pcicd; + uint16_t voyagerrts; + uint16_t cfrst; + uint16_t admrts; + uint16_t extrst; + uint16_t cfcdintclr; + uint16_t keyctlclr; + uint16_t pad0; + uint16_t pad1; + uint16_t verreg; + uint16_t inport; + uint16_t outport; + uint16_t bverreg; + +/* output pin */ + qemu_irq irl; + MemoryRegion iomem; +} r2d_fpga_t; + +enum r2d_fpga_irq { + PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T, + SDCARD, PCI_INTA, PCI_INTB, EXT, TP, + NR_IRQS +}; + +static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = { + [CF_IDE] = { 1, 1<<9 }, + [CF_CD] = { 2, 1<<8 }, + [PCI_INTA] = { 9, 1<<14 }, + [PCI_INTB] = { 10, 1<<13 }, + [PCI_INTC] = { 3, 1<<12 }, + [PCI_INTD] = { 0, 1<<11 }, + [SM501] = { 4, 1<<10 }, + [KEY] = { 5, 1<<6 }, + [RTC_A] = { 6, 1<<5 }, + [RTC_T] = { 7, 1<<4 }, + [SDCARD] = { 8, 1<<7 }, + [EXT] = { 11, 1<<0 }, + [TP] = { 12, 1<<15 }, +}; + +static void update_irl(r2d_fpga_t *fpga) +{ + int i, irl = 15; + for (i = 0; i < NR_IRQS; i++) + if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk) + if (irqtab[i].irl < irl) + irl = irqtab[i].irl; + qemu_set_irq(fpga->irl, irl ^ 15); +} + +static void r2d_fpga_irq_set(void *opaque, int n, int level) +{ + r2d_fpga_t *fpga = opaque; + if (level) + fpga->irlmon |= irqtab[n].msk; + else + fpga->irlmon &= ~irqtab[n].msk; + update_irl(fpga); +} + +static uint32_t r2d_fpga_read(void *opaque, hwaddr addr) +{ + r2d_fpga_t *s = opaque; + + switch (addr) { + case PA_IRLMSK: + return s->irlmsk; + case PA_OUTPORT: + return s->outport; + case PA_POWOFF: + return 0x00; + case PA_VERREG: + return 0x10; + } + + return 0; +} + +static void +r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value) +{ + r2d_fpga_t *s = opaque; + + switch (addr) { + case PA_IRLMSK: + s->irlmsk = value; + update_irl(s); + break; + case PA_OUTPORT: + s->outport = value; + break; + case PA_POWOFF: + if (value & 1) { + qemu_system_shutdown_request(); + } + break; + case PA_VERREG: + /* Discard writes */ + break; + } +} + +static const MemoryRegionOps r2d_fpga_ops = { + .old_mmio = { + .read = { r2d_fpga_read, r2d_fpga_read, NULL, }, + .write = { r2d_fpga_write, r2d_fpga_write, NULL, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem, + hwaddr base, qemu_irq irl) +{ + r2d_fpga_t *s; + + s = g_malloc0(sizeof(r2d_fpga_t)); + + s->irl = irl; + + memory_region_init_io(&s->iomem, &r2d_fpga_ops, s, "r2d-fpga", 0x40); + memory_region_add_subregion(sysmem, base, &s->iomem); + return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS); +} + +typedef struct ResetData { + SuperHCPU *cpu; + uint32_t vector; +} ResetData; + +static void main_cpu_reset(void *opaque) +{ + ResetData *s = (ResetData *)opaque; + CPUSH4State *env = &s->cpu->env; + + cpu_reset(CPU(s->cpu)); + env->pc = s->vector; +} + +static struct QEMU_PACKED +{ + int mount_root_rdonly; + int ramdisk_flags; + int orig_root_dev; + int loader_type; + int initrd_start; + int initrd_size; + + char pad[232]; + + char kernel_cmdline[256]; +} boot_params; + +static void r2d_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + SuperHCPU *cpu; + CPUSH4State *env; + ResetData *reset_info; + struct SH7750State *s; + MemoryRegion *sdram = g_new(MemoryRegion, 1); + qemu_irq *irq; + DriveInfo *dinfo; + int i; + DeviceState *dev; + SysBusDevice *busdev; + MemoryRegion *address_space_mem = get_system_memory(); + + if (cpu_model == NULL) { + cpu_model = "SH7751R"; + } + + cpu = cpu_sh4_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + reset_info = g_malloc0(sizeof(ResetData)); + reset_info->cpu = cpu; + reset_info->vector = env->pc; + qemu_register_reset(main_cpu_reset, reset_info); + + /* Allocate memory space */ + memory_region_init_ram(sdram, "r2d.sdram", SDRAM_SIZE); + vmstate_register_ram_global(sdram); + memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram); + /* Register peripherals */ + s = sh7750_init(env, address_space_mem); + irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s)); + + dev = qdev_create(NULL, "sh_pci"); + busdev = SYS_BUS_DEVICE(dev); + qdev_init_nofail(dev); + sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000)); + sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000)); + sysbus_connect_irq(busdev, 0, irq[PCI_INTA]); + sysbus_connect_irq(busdev, 1, irq[PCI_INTB]); + sysbus_connect_irq(busdev, 2, irq[PCI_INTC]); + sysbus_connect_irq(busdev, 3, irq[PCI_INTD]); + + sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE, + irq[SM501], serial_hds[2]); + + /* onboard CF (True IDE mode, Master only). */ + dinfo = drive_get(IF_IDE, 0, 0); + dev = qdev_create(NULL, "mmio-ide"); + busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, irq[CF_IDE]); + qdev_prop_set_uint32(dev, "shift", 1); + qdev_init_nofail(dev); + sysbus_mmio_map(busdev, 0, 0x14001000); + sysbus_mmio_map(busdev, 1, 0x1400080c); + mmio_ide_init_drives(dev, dinfo, NULL); + + /* onboard flash memory */ + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE, + dinfo ? dinfo->bdrv : NULL, (16 * 1024), + FLASH_SIZE >> 16, + 1, 4, 0x0000, 0x0000, 0x0000, 0x0000, + 0x555, 0x2aa, 0); + + /* NIC: rtl8139 on-board, and 2 slots. */ + for (i = 0; i < nb_nics; i++) + pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL); + + /* USB keyboard */ + usbdevice_create("keyboard"); + + /* Todo: register on board registers */ + memset(&boot_params, 0, sizeof(boot_params)); + + if (kernel_filename) { + int kernel_size; + + kernel_size = load_image_targphys(kernel_filename, + SDRAM_BASE + LINUX_LOAD_OFFSET, + INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + /* initialization which should be done by firmware */ + stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */ + stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */ + reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */ + } + + if (initrd_filename) { + int initrd_size; + + initrd_size = load_image_targphys(initrd_filename, + SDRAM_BASE + INITRD_LOAD_OFFSET, + SDRAM_SIZE - INITRD_LOAD_OFFSET); + + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename); + exit(1); + } + + /* initialization which should be done by firmware */ + boot_params.loader_type = 1; + boot_params.initrd_start = INITRD_LOAD_OFFSET; + boot_params.initrd_size = initrd_size; + } + + if (kernel_cmdline) { + /* I see no evidence that this .kernel_cmdline buffer requires + NUL-termination, so using strncpy should be ok. */ + strncpy(boot_params.kernel_cmdline, kernel_cmdline, + sizeof(boot_params.kernel_cmdline)); + } + + rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params), + SDRAM_BASE + BOOT_PARAMS_OFFSET); +} + +static QEMUMachine r2d_machine = { + .name = "r2d", + .desc = "r2d-plus board", + .init = r2d_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void r2d_machine_init(void) +{ + qemu_register_machine(&r2d_machine); +} + +machine_init(r2d_machine_init); diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c new file mode 100644 index 0000000000..192579d065 --- /dev/null +++ b/hw/sh4/shix.c @@ -0,0 +1,103 @@ +/* + * SHIX 2.0 board description + * + * Copyright (c) 2005 Samuel Tardieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* + Shix 2.0 board by Alexis Polti, described at + http://perso.enst.fr/~polti/realisations/shix20/ + + More information in target-sh4/README.sh4 +*/ +#include "hw/hw.h" +#include "hw/sh.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "exec/address-spaces.h" + +#define BIOS_FILENAME "shix_bios.bin" +#define BIOS_ADDRESS 0xA0000000 + +static void shix_init(QEMUMachineInitArgs *args) +{ + const char *cpu_model = args->cpu_model; + int ret; + CPUSH4State *env; + struct SH7750State *s; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *rom = g_new(MemoryRegion, 1); + MemoryRegion *sdram = g_new(MemoryRegion, 2); + + if (!cpu_model) + cpu_model = "any"; + + printf("Initializing CPU\n"); + env = cpu_init(cpu_model); + + /* Allocate memory space */ + printf("Allocating ROM\n"); + memory_region_init_ram(rom, "shix.rom", 0x4000); + vmstate_register_ram_global(rom); + memory_region_set_readonly(rom, true); + memory_region_add_subregion(sysmem, 0x00000000, rom); + printf("Allocating SDRAM 1\n"); + memory_region_init_ram(&sdram[0], "shix.sdram1", 0x01000000); + vmstate_register_ram_global(&sdram[0]); + memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]); + printf("Allocating SDRAM 2\n"); + memory_region_init_ram(&sdram[1], "shix.sdram2", 0x01000000); + vmstate_register_ram_global(&sdram[1]); + memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]); + + /* Load BIOS in 0 (and access it through P2, 0xA0000000) */ + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + printf("%s: load BIOS '%s'\n", __func__, bios_name); + ret = load_image_targphys(bios_name, 0, 0x4000); + if (ret < 0) { /* Check bios size */ + fprintf(stderr, "ret=%d\n", ret); + fprintf(stderr, "qemu: could not load SHIX bios '%s'\n", + bios_name); + exit(1); + } + + /* Register peripherals */ + s = sh7750_init(env, sysmem); + /* XXXXX Check success */ + tc58128_init(s, "shix_linux_nand.bin", NULL); + fprintf(stderr, "initialization terminated\n"); +} + +static QEMUMachine shix_machine = { + .name = "shix", + .desc = "shix card", + .init = shix_init, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void shix_machine_init(void) +{ + qemu_register_machine(&shix_machine); +} + +machine_init(shix_machine_init); diff --git a/hw/shix.c b/hw/shix.c deleted file mode 100644 index 192579d065..0000000000 --- a/hw/shix.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SHIX 2.0 board description - * - * Copyright (c) 2005 Samuel Tardieu - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - Shix 2.0 board by Alexis Polti, described at - http://perso.enst.fr/~polti/realisations/shix20/ - - More information in target-sh4/README.sh4 -*/ -#include "hw/hw.h" -#include "hw/sh.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "exec/address-spaces.h" - -#define BIOS_FILENAME "shix_bios.bin" -#define BIOS_ADDRESS 0xA0000000 - -static void shix_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - int ret; - CPUSH4State *env; - struct SH7750State *s; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *rom = g_new(MemoryRegion, 1); - MemoryRegion *sdram = g_new(MemoryRegion, 2); - - if (!cpu_model) - cpu_model = "any"; - - printf("Initializing CPU\n"); - env = cpu_init(cpu_model); - - /* Allocate memory space */ - printf("Allocating ROM\n"); - memory_region_init_ram(rom, "shix.rom", 0x4000); - vmstate_register_ram_global(rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(sysmem, 0x00000000, rom); - printf("Allocating SDRAM 1\n"); - memory_region_init_ram(&sdram[0], "shix.sdram1", 0x01000000); - vmstate_register_ram_global(&sdram[0]); - memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]); - printf("Allocating SDRAM 2\n"); - memory_region_init_ram(&sdram[1], "shix.sdram2", 0x01000000); - vmstate_register_ram_global(&sdram[1]); - memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]); - - /* Load BIOS in 0 (and access it through P2, 0xA0000000) */ - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - printf("%s: load BIOS '%s'\n", __func__, bios_name); - ret = load_image_targphys(bios_name, 0, 0x4000); - if (ret < 0) { /* Check bios size */ - fprintf(stderr, "ret=%d\n", ret); - fprintf(stderr, "qemu: could not load SHIX bios '%s'\n", - bios_name); - exit(1); - } - - /* Register peripherals */ - s = sh7750_init(env, sysmem); - /* XXXXX Check success */ - tc58128_init(s, "shix_linux_nand.bin", NULL); - fprintf(stderr, "initialization terminated\n"); -} - -static QEMUMachine shix_machine = { - .name = "shix", - .desc = "shix card", - .init = shix_init, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void shix_machine_init(void) -{ - qemu_register_machine(&shix_machine); -} - -machine_init(shix_machine_init); diff --git a/hw/smbios.c b/hw/smbios.c deleted file mode 100644 index 672ee9b0e7..0000000000 --- a/hw/smbios.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * SMBIOS Support - * - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * - * Authors: - * Alex Williamson - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "sysemu/sysemu.h" -#include "hw/smbios.h" -#include "hw/loader.h" - -/* - * Structures shared with the BIOS - */ -struct smbios_header { - uint16_t length; - uint8_t type; -} QEMU_PACKED; - -struct smbios_field { - struct smbios_header header; - uint8_t type; - uint16_t offset; - uint8_t data[]; -} QEMU_PACKED; - -struct smbios_table { - struct smbios_header header; - uint8_t data[]; -} QEMU_PACKED; - -#define SMBIOS_FIELD_ENTRY 0 -#define SMBIOS_TABLE_ENTRY 1 - - -static uint8_t *smbios_entries; -static size_t smbios_entries_len; -static int smbios_type4_count = 0; - -static void smbios_validate_table(void) -{ - if (smbios_type4_count && smbios_type4_count != smp_cpus) { - fprintf(stderr, - "Number of SMBIOS Type 4 tables must match cpu count.\n"); - exit(1); - } -} - -uint8_t *smbios_get_table(size_t *length) -{ - smbios_validate_table(); - *length = smbios_entries_len; - return smbios_entries; -} - -/* - * To avoid unresolvable overlaps in data, don't allow both - * tables and fields for the same smbios type. - */ -static void smbios_check_collision(int type, int entry) -{ - uint16_t *num_entries = (uint16_t *)smbios_entries; - struct smbios_header *header; - char *p; - int i; - - if (!num_entries) - return; - - p = (char *)(num_entries + 1); - - for (i = 0; i < *num_entries; i++) { - header = (struct smbios_header *)p; - if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) { - struct smbios_field *field = (void *)header; - if (type == field->type) { - fprintf(stderr, "SMBIOS type %d field already defined, " - "cannot add table\n", type); - exit(1); - } - } else if (entry == SMBIOS_FIELD_ENTRY && - header->type == SMBIOS_TABLE_ENTRY) { - struct smbios_structure_header *table = (void *)(header + 1); - if (type == table->type) { - fprintf(stderr, "SMBIOS type %d table already defined, " - "cannot add field\n", type); - exit(1); - } - } - p += le16_to_cpu(header->length); - } -} - -void smbios_add_field(int type, int offset, int len, void *data) -{ - struct smbios_field *field; - - smbios_check_collision(type, SMBIOS_FIELD_ENTRY); - - if (!smbios_entries) { - smbios_entries_len = sizeof(uint16_t); - smbios_entries = g_malloc0(smbios_entries_len); - } - smbios_entries = g_realloc(smbios_entries, smbios_entries_len + - sizeof(*field) + len); - field = (struct smbios_field *)(smbios_entries + smbios_entries_len); - field->header.type = SMBIOS_FIELD_ENTRY; - field->header.length = cpu_to_le16(sizeof(*field) + len); - - field->type = type; - field->offset = cpu_to_le16(offset); - memcpy(field->data, data, len); - - smbios_entries_len += sizeof(*field) + len; - (*(uint16_t *)smbios_entries) = - cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); -} - -static void smbios_build_type_0_fields(const char *t) -{ - char buf[1024]; - - if (get_param_value(buf, sizeof(buf), "vendor", t)) - smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "version", t)) - smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "date", t)) - smbios_add_field(0, offsetof(struct smbios_type_0, - bios_release_date_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "release", t)) { - int major, minor; - sscanf(buf, "%d.%d", &major, &minor); - smbios_add_field(0, offsetof(struct smbios_type_0, - system_bios_major_release), 1, &major); - smbios_add_field(0, offsetof(struct smbios_type_0, - system_bios_minor_release), 1, &minor); - } -} - -static void smbios_build_type_1_fields(const char *t) -{ - char buf[1024]; - - if (get_param_value(buf, sizeof(buf), "manufacturer", t)) - smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "product", t)) - smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "version", t)) - smbios_add_field(1, offsetof(struct smbios_type_1, version_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "serial", t)) - smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "uuid", t)) { - if (qemu_uuid_parse(buf, qemu_uuid) != 0) { - fprintf(stderr, "Invalid SMBIOS UUID string\n"); - exit(1); - } - } - if (get_param_value(buf, sizeof(buf), "sku", t)) - smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str), - strlen(buf) + 1, buf); - if (get_param_value(buf, sizeof(buf), "family", t)) - smbios_add_field(1, offsetof(struct smbios_type_1, family_str), - strlen(buf) + 1, buf); -} - -int smbios_entry_add(const char *t) -{ - char buf[1024]; - - if (get_param_value(buf, sizeof(buf), "file", t)) { - struct smbios_structure_header *header; - struct smbios_table *table; - int size = get_image_size(buf); - - if (size == -1 || size < sizeof(struct smbios_structure_header)) { - fprintf(stderr, "Cannot read smbios file %s\n", buf); - exit(1); - } - - if (!smbios_entries) { - smbios_entries_len = sizeof(uint16_t); - smbios_entries = g_malloc0(smbios_entries_len); - } - - smbios_entries = g_realloc(smbios_entries, smbios_entries_len + - sizeof(*table) + size); - table = (struct smbios_table *)(smbios_entries + smbios_entries_len); - table->header.type = SMBIOS_TABLE_ENTRY; - table->header.length = cpu_to_le16(sizeof(*table) + size); - - if (load_image(buf, table->data) != size) { - fprintf(stderr, "Failed to load smbios file %s", buf); - exit(1); - } - - header = (struct smbios_structure_header *)(table->data); - smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY); - if (header->type == 4) { - smbios_type4_count++; - } - - smbios_entries_len += sizeof(*table) + size; - (*(uint16_t *)smbios_entries) = - cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); - return 0; - } - - if (get_param_value(buf, sizeof(buf), "type", t)) { - unsigned long type = strtoul(buf, NULL, 0); - switch (type) { - case 0: - smbios_build_type_0_fields(t); - return 0; - case 1: - smbios_build_type_1_fields(t); - return 0; - default: - fprintf(stderr, "Don't know how to build fields for SMBIOS type " - "%ld\n", type); - exit(1); - } - } - - fprintf(stderr, "smbios: must specify type= or file=\n"); - return -1; -} diff --git a/hw/spapr.c b/hw/spapr.c deleted file mode 100644 index 2709c660c1..0000000000 --- a/hw/spapr.c +++ /dev/null @@ -1,963 +0,0 @@ -/* - * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator - * - * Copyright (c) 2004-2007 Fabrice Bellard - * Copyright (c) 2007 Jocelyn Mayer - * Copyright (c) 2010 David Gibson, IBM Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ -#include "sysemu/sysemu.h" -#include "hw/hw.h" -#include "elf.h" -#include "net/net.h" -#include "sysemu/blockdev.h" -#include "sysemu/cpus.h" -#include "sysemu/kvm.h" -#include "kvm_ppc.h" - -#include "hw/boards.h" -#include "hw/ppc.h" -#include "hw/loader.h" - -#include "hw/spapr.h" -#include "hw/spapr_vio.h" -#include "hw/spapr_pci.h" -#include "hw/xics.h" -#include "hw/pci/msi.h" - -#include "sysemu/kvm.h" -#include "kvm_ppc.h" -#include "hw/pci/pci.h" - -#include "exec/address-spaces.h" -#include "hw/usb.h" -#include "qemu/config-file.h" - -#include - -/* SLOF memory layout: - * - * SLOF raw image loaded at 0, copies its romfs right below the flat - * device-tree, then position SLOF itself 31M below that - * - * So we set FW_OVERHEAD to 40MB which should account for all of that - * and more - * - * We load our kernel at 4M, leaving space for SLOF initial image - */ -#define FDT_MAX_SIZE 0x10000 -#define RTAS_MAX_SIZE 0x10000 -#define FW_MAX_SIZE 0x400000 -#define FW_FILE_NAME "slof.bin" -#define FW_OVERHEAD 0x2800000 -#define KERNEL_LOAD_ADDR FW_MAX_SIZE - -#define MIN_RMA_SLOF 128UL - -#define TIMEBASE_FREQ 512000000ULL - -#define MAX_CPUS 256 -#define XICS_IRQS 1024 - -#define PHANDLE_XICP 0x00001111 - -#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) - -sPAPREnvironment *spapr; - -int spapr_allocate_irq(int hint, bool lsi) -{ - int irq; - - if (hint) { - irq = hint; - /* FIXME: we should probably check for collisions somehow */ - } else { - irq = spapr->next_irq++; - } - - /* Configure irq type */ - if (!xics_get_qirq(spapr->icp, irq)) { - return 0; - } - - xics_set_irq_type(spapr->icp, irq, lsi); - - return irq; -} - -/* Allocate block of consequtive IRQs, returns a number of the first */ -int spapr_allocate_irq_block(int num, bool lsi) -{ - int first = -1; - int i; - - for (i = 0; i < num; ++i) { - int irq; - - irq = spapr_allocate_irq(0, lsi); - if (!irq) { - return -1; - } - - if (0 == i) { - first = irq; - } - - /* If the above doesn't create a consecutive block then that's - * an internal bug */ - assert(irq == (first + i)); - } - - return first; -} - -static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) -{ - int ret = 0, offset; - CPUPPCState *env; - CPUState *cpu; - char cpu_model[32]; - int smt = kvmppc_smt_threads(); - uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; - - assert(spapr->cpu_model); - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - uint32_t associativity[] = {cpu_to_be32(0x5), - cpu_to_be32(0x0), - cpu_to_be32(0x0), - cpu_to_be32(0x0), - cpu_to_be32(cpu->numa_node), - cpu_to_be32(cpu->cpu_index)}; - - if ((cpu->cpu_index % smt) != 0) { - continue; - } - - snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model, - cpu->cpu_index); - - offset = fdt_path_offset(fdt, cpu_model); - if (offset < 0) { - return offset; - } - - if (nb_numa_nodes > 1) { - ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, - sizeof(associativity)); - if (ret < 0) { - return ret; - } - } - - ret = fdt_setprop(fdt, offset, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)); - if (ret < 0) { - return ret; - } - } - return ret; -} - - -static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, - size_t maxsize) -{ - size_t maxcells = maxsize / sizeof(uint32_t); - int i, j, count; - uint32_t *p = prop; - - for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { - struct ppc_one_seg_page_size *sps = &env->sps.sps[i]; - - if (!sps->page_shift) { - break; - } - for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) { - if (sps->enc[count].page_shift == 0) { - break; - } - } - if ((p - prop) >= (maxcells - 3 - count * 2)) { - break; - } - *(p++) = cpu_to_be32(sps->page_shift); - *(p++) = cpu_to_be32(sps->slb_enc); - *(p++) = cpu_to_be32(count); - for (j = 0; j < count; j++) { - *(p++) = cpu_to_be32(sps->enc[j].page_shift); - *(p++) = cpu_to_be32(sps->enc[j].pte_enc); - } - } - - return (p - prop) * sizeof(uint32_t); -} - -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) - - -static void *spapr_create_fdt_skel(const char *cpu_model, - hwaddr initrd_base, - hwaddr initrd_size, - hwaddr kernel_size, - const char *boot_device, - const char *kernel_cmdline, - uint32_t epow_irq) -{ - void *fdt; - CPUPPCState *env; - uint32_t start_prop = cpu_to_be32(initrd_base); - uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); - char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" - "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; - char qemu_hypertas_prop[] = "hcall-memop1"; - uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; - uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; - char *modelname; - int i, smt = kvmppc_smt_threads(); - unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; - - fdt = g_malloc0(FDT_MAX_SIZE); - _FDT((fdt_create(fdt, FDT_MAX_SIZE))); - - if (kernel_size) { - _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size))); - } - if (initrd_size) { - _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size))); - } - _FDT((fdt_finish_reservemap(fdt))); - - /* Root node */ - _FDT((fdt_begin_node(fdt, ""))); - _FDT((fdt_property_string(fdt, "device_type", "chrp"))); - _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); - - _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); - _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); - - /* /chosen */ - _FDT((fdt_begin_node(fdt, "chosen"))); - - /* Set Form1_affinity */ - _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5)))); - - _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline))); - _FDT((fdt_property(fdt, "linux,initrd-start", - &start_prop, sizeof(start_prop)))); - _FDT((fdt_property(fdt, "linux,initrd-end", - &end_prop, sizeof(end_prop)))); - if (kernel_size) { - uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), - cpu_to_be64(kernel_size) }; - - _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); - } - if (boot_device) { - _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); - } - _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width))); - _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height))); - _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth))); - - _FDT((fdt_end_node(fdt))); - - /* cpus */ - _FDT((fdt_begin_node(fdt, "cpus"))); - - _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); - _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); - - modelname = g_strdup(cpu_model); - - for (i = 0; i < strlen(modelname); i++) { - modelname[i] = toupper(modelname[i]); - } - - /* This is needed during FDT finalization */ - spapr->cpu_model = g_strdup(modelname); - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - CPUState *cpu = CPU(ppc_env_get_cpu(env)); - int index = cpu->cpu_index; - uint32_t servers_prop[smp_threads]; - uint32_t gservers_prop[smp_threads * 2]; - char *nodename; - uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), - 0xffffffff, 0xffffffff}; - uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; - uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; - uint32_t page_sizes_prop[64]; - size_t page_sizes_prop_size; - - if ((index % smt) != 0) { - continue; - } - - nodename = g_strdup_printf("%s@%x", modelname, index); - - _FDT((fdt_begin_node(fdt, nodename))); - - g_free(nodename); - - _FDT((fdt_property_cell(fdt, "reg", index))); - _FDT((fdt_property_string(fdt, "device_type", "cpu"))); - - _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR]))); - _FDT((fdt_property_cell(fdt, "dcache-block-size", - env->dcache_line_size))); - _FDT((fdt_property_cell(fdt, "icache-block-size", - env->icache_line_size))); - _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); - _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); - _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); - _FDT((fdt_property_string(fdt, "status", "okay"))); - _FDT((fdt_property(fdt, "64-bit", NULL, 0))); - - /* Build interrupt servers and gservers properties */ - for (i = 0; i < smp_threads; i++) { - servers_prop[i] = cpu_to_be32(index + i); - /* Hack, direct the group queues back to cpu 0 */ - gservers_prop[i*2] = cpu_to_be32(index + i); - gservers_prop[i*2 + 1] = 0; - } - _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s", - servers_prop, sizeof(servers_prop)))); - _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", - gservers_prop, sizeof(gservers_prop)))); - - if (env->mmu_model & POWERPC_MMU_1TSEG) { - _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", - segs, sizeof(segs)))); - } - - /* Advertise VMX/VSX (vector extensions) if available - * 0 / no property == no vector extensions - * 1 == VMX / Altivec available - * 2 == VSX available */ - if (env->insns_flags & PPC_ALTIVEC) { - uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; - - _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx))); - } - - /* Advertise DFP (Decimal Floating Point) if available - * 0 / no property == no DFP - * 1 == DFP available */ - if (env->insns_flags2 & PPC2_DFP) { - _FDT((fdt_property_cell(fdt, "ibm,dfp", 1))); - } - - page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop, - sizeof(page_sizes_prop)); - if (page_sizes_prop_size) { - _FDT((fdt_property(fdt, "ibm,segment-page-sizes", - page_sizes_prop, page_sizes_prop_size))); - } - - _FDT((fdt_end_node(fdt))); - } - - g_free(modelname); - - _FDT((fdt_end_node(fdt))); - - /* RTAS */ - _FDT((fdt_begin_node(fdt, "rtas"))); - - _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, - sizeof(hypertas_prop)))); - _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop, - sizeof(qemu_hypertas_prop)))); - - _FDT((fdt_property(fdt, "ibm,associativity-reference-points", - refpoints, sizeof(refpoints)))); - - _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX))); - - _FDT((fdt_end_node(fdt))); - - /* interrupt controller */ - _FDT((fdt_begin_node(fdt, "interrupt-controller"))); - - _FDT((fdt_property_string(fdt, "device_type", - "PowerPC-External-Interrupt-Presentation"))); - _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"))); - _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); - _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges", - interrupt_server_ranges_prop, - sizeof(interrupt_server_ranges_prop)))); - _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); - _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP))); - _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP))); - - _FDT((fdt_end_node(fdt))); - - /* vdevice */ - _FDT((fdt_begin_node(fdt, "vdevice"))); - - _FDT((fdt_property_string(fdt, "device_type", "vdevice"))); - _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice"))); - _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); - _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); - _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2))); - _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); - - _FDT((fdt_end_node(fdt))); - - /* event-sources */ - spapr_events_fdt_skel(fdt, epow_irq); - - _FDT((fdt_end_node(fdt))); /* close root node */ - _FDT((fdt_finish(fdt))); - - return fdt; -} - -static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) -{ - uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), - cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(0x0)}; - char mem_name[32]; - hwaddr node0_size, mem_start; - uint64_t mem_reg_property[2]; - int i, off; - - /* memory node(s) */ - node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; - if (spapr->rma_size > node0_size) { - spapr->rma_size = node0_size; - } - - /* RMA */ - mem_reg_property[0] = 0; - mem_reg_property[1] = cpu_to_be64(spapr->rma_size); - off = fdt_add_subnode(fdt, 0, "memory@0"); - _FDT(off); - _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); - _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, - sizeof(associativity)))); - - /* RAM: Node 0 */ - if (node0_size > spapr->rma_size) { - mem_reg_property[0] = cpu_to_be64(spapr->rma_size); - mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size); - - sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size); - off = fdt_add_subnode(fdt, 0, mem_name); - _FDT(off); - _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); - _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, - sizeof(associativity)))); - } - - /* RAM: Node 1 and beyond */ - mem_start = node0_size; - for (i = 1; i < nb_numa_nodes; i++) { - mem_reg_property[0] = cpu_to_be64(mem_start); - mem_reg_property[1] = cpu_to_be64(node_mem[i]); - associativity[3] = associativity[4] = cpu_to_be32(i); - sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); - off = fdt_add_subnode(fdt, 0, mem_name); - _FDT(off); - _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); - _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, - sizeof(associativity)))); - mem_start += node_mem[i]; - } - - return 0; -} - -static void spapr_finalize_fdt(sPAPREnvironment *spapr, - hwaddr fdt_addr, - hwaddr rtas_addr, - hwaddr rtas_size) -{ - int ret; - void *fdt; - sPAPRPHBState *phb; - - fdt = g_malloc(FDT_MAX_SIZE); - - /* open out the base tree into a temp buffer for the final tweaks */ - _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); - - ret = spapr_populate_memory(spapr, fdt); - if (ret < 0) { - fprintf(stderr, "couldn't setup memory nodes in fdt\n"); - exit(1); - } - - ret = spapr_populate_vdevice(spapr->vio_bus, fdt); - if (ret < 0) { - fprintf(stderr, "couldn't setup vio devices in fdt\n"); - exit(1); - } - - QLIST_FOREACH(phb, &spapr->phbs, list) { - ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt); - } - - if (ret < 0) { - fprintf(stderr, "couldn't setup PCI devices in fdt\n"); - exit(1); - } - - /* RTAS */ - ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); - if (ret < 0) { - fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); - } - - /* Advertise NUMA via ibm,associativity */ - ret = spapr_fixup_cpu_dt(fdt, spapr); - if (ret < 0) { - fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); - } - - if (!spapr->has_graphics) { - spapr_populate_chosen_stdout(fdt, spapr->vio_bus); - } - - _FDT((fdt_pack(fdt))); - - if (fdt_totalsize(fdt) > FDT_MAX_SIZE) { - hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n", - fdt_totalsize(fdt), FDT_MAX_SIZE); - exit(1); - } - - cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); - - g_free(fdt); -} - -static uint64_t translate_kernel_address(void *opaque, uint64_t addr) -{ - return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; -} - -static void emulate_spapr_hypercall(PowerPCCPU *cpu) -{ - CPUPPCState *env = &cpu->env; - - if (msr_pr) { - hcall_dprintf("Hypercall made with MSR[PR]=1\n"); - env->gpr[3] = H_PRIVILEGE; - } else { - env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]); - } -} - -static void spapr_reset_htab(sPAPREnvironment *spapr) -{ - long shift; - - /* allocate hash page table. For now we always make this 16mb, - * later we should probably make it scale to the size of guest - * RAM */ - - shift = kvmppc_reset_htab(spapr->htab_shift); - - if (shift > 0) { - /* Kernel handles htab, we don't need to allocate one */ - spapr->htab_shift = shift; - } else { - if (!spapr->htab) { - /* Allocate an htab if we don't yet have one */ - spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr)); - } - - /* And clear it */ - memset(spapr->htab, 0, HTAB_SIZE(spapr)); - } - - /* Update the RMA size if necessary */ - if (spapr->vrma_adjust) { - spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); - } -} - -static void ppc_spapr_reset(void) -{ - /* Reset the hash table & recalc the RMA */ - spapr_reset_htab(spapr); - - qemu_devices_reset(); - - /* Load the fdt */ - spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, - spapr->rtas_size); - - /* Set up the entry state */ - first_cpu->gpr[3] = spapr->fdt_addr; - first_cpu->gpr[5] = 0; - first_cpu->halted = 0; - first_cpu->nip = spapr->entry_point; - -} - -static void spapr_cpu_reset(void *opaque) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - - cpu_reset(CPU(cpu)); - - /* All CPUs start halted. CPU0 is unhalted from the machine level - * reset code and the rest are explicitly started up by the guest - * using an RTAS call */ - env->halted = 1; - - env->spr[SPR_HIOR] = 0; - - env->external_htab = spapr->htab; - env->htab_base = -1; - env->htab_mask = HTAB_SIZE(spapr) - 1; - env->spr[SPR_SDR1] = (unsigned long)spapr->htab | - (spapr->htab_shift - 18); -} - -static void spapr_create_nvram(sPAPREnvironment *spapr) -{ - QemuOpts *machine_opts; - DeviceState *dev; - - dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); - - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - const char *drivename; - - drivename = qemu_opt_get(machine_opts, "nvram"); - if (drivename) { - BlockDriverState *bs; - - bs = bdrv_find(drivename); - if (!bs) { - fprintf(stderr, "No such block device \"%s\" for nvram\n", - drivename); - exit(1); - } - qdev_prop_set_drive_nofail(dev, "drive", bs); - } - } - - qdev_init_nofail(dev); - - spapr->nvram = (struct sPAPRNVRAM *)dev; -} - -/* Returns whether we want to use VGA or not */ -static int spapr_vga_init(PCIBus *pci_bus) -{ - switch (vga_interface_type) { - case VGA_NONE: - case VGA_STD: - return pci_vga_init(pci_bus) != NULL; - default: - fprintf(stderr, "This vga model is not supported," - "currently it only supports -vga std\n"); - exit(0); - break; - } -} - -/* pSeries LPAR / sPAPR hardware init */ -static void ppc_spapr_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - PowerPCCPU *cpu; - CPUPPCState *env; - PCIHostState *phb; - int i; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - hwaddr rma_alloc_size; - uint32_t initrd_base = 0; - long kernel_size = 0, initrd_size = 0; - long load_limit, rtas_limit, fw_size; - char *filename; - - msi_supported = true; - - spapr = g_malloc0(sizeof(*spapr)); - QLIST_INIT(&spapr->phbs); - - cpu_ppc_hypercall = emulate_spapr_hypercall; - - /* Allocate RMA if necessary */ - rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem); - - if (rma_alloc_size == -1) { - hw_error("qemu: Unable to create RMA\n"); - exit(1); - } - - if (rma_alloc_size && (rma_alloc_size < ram_size)) { - spapr->rma_size = rma_alloc_size; - } else { - spapr->rma_size = ram_size; - - /* With KVM, we don't actually know whether KVM supports an - * unbounded RMA (PR KVM) or is limited by the hash table size - * (HV KVM using VRMA), so we always assume the latter - * - * In that case, we also limit the initial allocations for RTAS - * etc... to 256M since we have no way to know what the VRMA size - * is going to be as it depends on the size of the hash table - * isn't determined yet. - */ - if (kvm_enabled()) { - spapr->vrma_adjust = 1; - spapr->rma_size = MIN(spapr->rma_size, 0x10000000); - } - } - - /* We place the device tree and RTAS just below either the top of the RMA, - * or just below 2GB, whichever is lowere, so that it can be - * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(spapr->rma_size, 0x80000000); - spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; - spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; - load_limit = spapr->fdt_addr - FW_OVERHEAD; - - /* We aim for a hash table of size 1/128 the size of RAM. The - * normal rule of thumb is 1/64 the size of RAM, but that's much - * more than needed for the Linux guests we support. */ - spapr->htab_shift = 18; /* Minimum architected size */ - while (spapr->htab_shift <= 46) { - if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) { - break; - } - spapr->htab_shift++; - } - - /* init CPUs */ - if (cpu_model == NULL) { - cpu_model = kvm_enabled() ? "host" : "POWER7"; - } - for (i = 0; i < smp_cpus; i++) { - cpu = cpu_ppc_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find PowerPC CPU definition\n"); - exit(1); - } - env = &cpu->env; - - /* Set time-base frequency to 512 MHz */ - cpu_ppc_tb_init(env, TIMEBASE_FREQ); - - /* PAPR always has exception vectors in RAM not ROM */ - env->hreset_excp_prefix = 0; - - /* Tell KVM that we're in PAPR mode */ - if (kvm_enabled()) { - kvmppc_set_papr(cpu); - } - - qemu_register_reset(spapr_cpu_reset, cpu); - } - - /* allocate RAM */ - spapr->ram_limit = ram_size; - if (spapr->ram_limit > rma_alloc_size) { - ram_addr_t nonrma_base = rma_alloc_size; - ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size; - - memory_region_init_ram(ram, "ppc_spapr.ram", nonrma_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(sysmem, nonrma_base, ram); - } - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); - spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, - rtas_limit - spapr->rtas_addr); - if (spapr->rtas_size < 0) { - hw_error("qemu: could not load LPAR rtas '%s'\n", filename); - exit(1); - } - if (spapr->rtas_size > RTAS_MAX_SIZE) { - hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n", - spapr->rtas_size, RTAS_MAX_SIZE); - exit(1); - } - g_free(filename); - - - /* Set up Interrupt Controller */ - spapr->icp = xics_system_init(XICS_IRQS); - spapr->next_irq = XICS_IRQ_BASE; - - /* Set up EPOW events infrastructure */ - spapr_events_init(spapr); - - /* Set up IOMMU */ - spapr_iommu_init(); - - /* Set up VIO bus */ - spapr->vio_bus = spapr_vio_bus_init(); - - for (i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - spapr_vty_create(spapr->vio_bus, serial_hds[i]); - } - } - - /* We always have at least the nvram device on VIO */ - spapr_create_nvram(spapr); - - /* Set up PCI */ - spapr_pci_rtas_init(); - - phb = spapr_create_phb(spapr, 0, "pci"); - - for (i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - - if (!nd->model) { - nd->model = g_strdup("ibmveth"); - } - - if (strcmp(nd->model, "ibmveth") == 0) { - spapr_vlan_create(spapr->vio_bus, nd); - } else { - pci_nic_init_nofail(&nd_table[i], nd->model, NULL); - } - } - - for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) { - spapr_vscsi_create(spapr->vio_bus); - } - - /* Graphics */ - if (spapr_vga_init(phb->bus)) { - spapr->has_graphics = true; - } - - if (usb_enabled(spapr->has_graphics)) { - pci_create_simple(phb->bus, -1, "pci-ohci"); - if (spapr->has_graphics) { - usbdevice_create("keyboard"); - usbdevice_create("mouse"); - } - } - - if (spapr->rma_size < (MIN_RMA_SLOF << 20)) { - fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " - "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); - exit(1); - } - - if (kernel_filename) { - uint64_t lowaddr = 0; - - kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, - NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - load_limit - KERNEL_LOAD_ADDR); - } - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - if (initrd_filename) { - /* Try to locate the initrd in the gap between the kernel - * and the firmware. Add a bit of space just in case - */ - initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - load_limit - initrd_base); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_base = 0; - initrd_size = 0; - } - } - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); - fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); - if (fw_size < 0) { - hw_error("qemu: could not load LPAR rtas '%s'\n", filename); - exit(1); - } - g_free(filename); - - spapr->entry_point = 0x100; - - /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, - initrd_base, initrd_size, - kernel_size, - boot_device, kernel_cmdline, - spapr->epow_irq); - assert(spapr->fdt_skel != NULL); -} - -static QEMUMachine spapr_machine = { - .name = "pseries", - .desc = "pSeries Logical Partition (PAPR compliant)", - .init = ppc_spapr_init, - .reset = ppc_spapr_reset, - .block_default_type = IF_SCSI, - .max_cpus = MAX_CPUS, - .no_parallel = 1, - .boot_order = NULL, -}; - -static void spapr_machine_init(void) -{ - qemu_register_machine(&spapr_machine); -} - -machine_init(spapr_machine_init); diff --git a/hw/sparc/Makefile.objs b/hw/sparc/Makefile.objs index a39a511c52..71bbddf8c3 100644 --- a/hw/sparc/Makefile.objs +++ b/hw/sparc/Makefile.objs @@ -1,8 +1,10 @@ -obj-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o +obj-y = lance.o tcx.o sun4m_iommu.o slavio_intctl.o obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o -obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o +obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o # GRLIB obj-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += sun4m.o leon3.o diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c new file mode 100644 index 0000000000..f58061f8ed --- /dev/null +++ b/hw/sparc/leon3.c @@ -0,0 +1,223 @@ +/* + * QEMU Leon3 System Emulator + * + * Copyright (c) 2010-2011 AdaCore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "qemu/timer.h" +#include "hw/ptimer.h" +#include "char/char.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "trace.h" +#include "exec/address-spaces.h" + +#include "hw/grlib.h" + +/* Default system clock. */ +#define CPU_CLK (40 * 1000 * 1000) + +#define PROM_FILENAME "u-boot.bin" + +#define MAX_PILS 16 + +typedef struct ResetData { + SPARCCPU *cpu; + uint32_t entry; /* save kernel entry in case of reset */ +} ResetData; + +static void main_cpu_reset(void *opaque) +{ + ResetData *s = (ResetData *)opaque; + CPUSPARCState *env = &s->cpu->env; + + cpu_reset(CPU(s->cpu)); + + env->halted = 0; + env->pc = s->entry; + env->npc = s->entry + 4; +} + +void leon3_irq_ack(void *irq_manager, int intno) +{ + grlib_irqmp_ack((DeviceState *)irq_manager, intno); +} + +static void leon3_set_pil_in(void *opaque, uint32_t pil_in) +{ + CPUSPARCState *env = (CPUSPARCState *)opaque; + + assert(env != NULL); + + env->pil_in = pil_in; + + if (env->pil_in && (env->interrupt_index == 0 || + (env->interrupt_index & ~15) == TT_EXTINT)) { + unsigned int i; + + for (i = 15; i > 0; i--) { + if (env->pil_in & (1 << i)) { + int old_interrupt = env->interrupt_index; + + env->interrupt_index = TT_EXTINT | i; + if (old_interrupt != env->interrupt_index) { + trace_leon3_set_irq(i); + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + break; + } + } + } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + trace_leon3_reset_irq(env->interrupt_index & 15); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void leon3_generic_hw_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + SPARCCPU *cpu; + CPUSPARCState *env; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *prom = g_new(MemoryRegion, 1); + int ret; + char *filename; + qemu_irq *cpu_irqs = NULL; + int bios_size; + int prom_size; + ResetData *reset_info; + + /* Init CPU */ + if (!cpu_model) { + cpu_model = "LEON3"; + } + + cpu = cpu_sparc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); + exit(1); + } + env = &cpu->env; + + cpu_sparc_set_id(env, 0); + + /* Reset data */ + reset_info = g_malloc0(sizeof(ResetData)); + reset_info->cpu = cpu; + qemu_register_reset(main_cpu_reset, reset_info); + + /* Allocate IRQ manager */ + grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in); + + env->qemu_irq_ack = leon3_irq_manager; + + /* Allocate RAM */ + if ((uint64_t)ram_size > (1UL << 30)) { + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum 1G\n", + (unsigned int)(ram_size / (1024 * 1024))); + exit(1); + } + + memory_region_init_ram(ram, "leon3.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, 0x40000000, ram); + + /* Allocate BIOS */ + prom_size = 8 * 1024 * 1024; /* 8Mb */ + memory_region_init_ram(prom, "Leon3.bios", prom_size); + vmstate_register_ram_global(prom); + memory_region_set_readonly(prom, true); + memory_region_add_subregion(address_space_mem, 0x00000000, prom); + + /* Load boot prom */ + if (bios_name == NULL) { + bios_name = PROM_FILENAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + + bios_size = get_image_size(filename); + + if (bios_size > prom_size) { + fprintf(stderr, "qemu: could not load prom '%s': file too big\n", + filename); + exit(1); + } + + if (bios_size > 0) { + ret = load_image_targphys(filename, 0x00000000, bios_size); + if (ret < 0 || ret > prom_size) { + fprintf(stderr, "qemu: could not load prom '%s'\n", filename); + exit(1); + } + } else if (kernel_filename == NULL) { + fprintf(stderr, "Can't read bios image %s\n", filename); + exit(1); + } + + /* Can directly load an application. */ + if (kernel_filename != NULL) { + long kernel_size; + uint64_t entry; + + kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, + 1 /* big endian */, ELF_MACHINE, 0); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + if (bios_size <= 0) { + /* If there is no bios/monitor, start the application. */ + env->pc = entry; + env->npc = entry + 4; + reset_info->entry = entry; + } + } + + /* Allocate timers */ + grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6); + + /* Allocate uart */ + if (serial_hds[0]) { + grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]); + } +} + +static QEMUMachine leon3_generic_machine = { + .name = "leon3_generic", + .desc = "Leon-3 generic", + .init = leon3_generic_hw_init, + DEFAULT_MACHINE_OPTIONS, +}; + +static void leon3_machine_init(void) +{ + qemu_register_machine(&leon3_generic_machine); +} + +machine_init(leon3_machine_init); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c new file mode 100644 index 0000000000..37bd04108d --- /dev/null +++ b/hw/sparc/sun4m.c @@ -0,0 +1,1936 @@ +/* + * QEMU Sun4m & Sun4d & Sun4c System Emulator + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "hw/sun4m.h" +#include "hw/nvram.h" +#include "hw/sparc32_dma.h" +#include "hw/fdc.h" +#include "sysemu/sysemu.h" +#include "net/net.h" +#include "hw/boards.h" +#include "hw/firmware_abi.h" +#include "hw/esp.h" +#include "hw/pc.h" +#include "hw/isa.h" +#include "hw/fw_cfg.h" +#include "hw/escc.h" +#include "hw/empty_slot.h" +#include "hw/qdev-addr.h" +#include "hw/loader.h" +#include "elf.h" +#include "sysemu/blockdev.h" +#include "trace.h" + +/* + * Sun4m architecture was used in the following machines: + * + * SPARCserver 6xxMP/xx + * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), + * SPARCclassic X (4/10) + * SPARCstation LX/ZX (4/30) + * SPARCstation Voyager + * SPARCstation 10/xx, SPARCserver 10/xx + * SPARCstation 5, SPARCserver 5 + * SPARCstation 20/xx, SPARCserver 20 + * SPARCstation 4 + * + * Sun4d architecture was used in the following machines: + * + * SPARCcenter 2000 + * SPARCserver 1000 + * + * Sun4c architecture was used in the following machines: + * SPARCstation 1/1+, SPARCserver 1/1+ + * SPARCstation SLC + * SPARCstation IPC + * SPARCstation ELC + * SPARCstation IPX + * + * See for example: http://www.sunhelp.org/faq/sunref1.html + */ + +#define KERNEL_LOAD_ADDR 0x00004000 +#define CMDLINE_ADDR 0x007ff000 +#define INITRD_LOAD_ADDR 0x00800000 +#define PROM_SIZE_MAX (1024 * 1024) +#define PROM_VADDR 0xffd00000 +#define PROM_FILENAME "openbios-sparc32" +#define CFG_ADDR 0xd00000510ULL +#define FW_CFG_SUN4M_DEPTH (FW_CFG_ARCH_LOCAL + 0x00) + +#define MAX_CPUS 16 +#define MAX_PILS 16 +#define MAX_VSIMMS 4 + +#define ESCC_CLOCK 4915200 + +struct sun4m_hwdef { + hwaddr iommu_base, iommu_pad_base, iommu_pad_len, slavio_base; + hwaddr intctl_base, counter_base, nvram_base, ms_kb_base; + hwaddr serial_base, fd_base; + hwaddr afx_base, idreg_base, dma_base, esp_base, le_base; + hwaddr tcx_base, cs_base, apc_base, aux1_base, aux2_base; + hwaddr bpp_base, dbri_base, sx_base; + struct { + hwaddr reg_base, vram_base; + } vsimm[MAX_VSIMMS]; + hwaddr ecc_base; + uint64_t max_mem; + const char * const default_cpu_model; + uint32_t ecc_version; + uint32_t iommu_version; + uint16_t machine_id; + uint8_t nvram_machine_id; +}; + +#define MAX_IOUNITS 5 + +struct sun4d_hwdef { + hwaddr iounit_bases[MAX_IOUNITS], slavio_base; + hwaddr counter_base, nvram_base, ms_kb_base; + hwaddr serial_base; + hwaddr espdma_base, esp_base; + hwaddr ledma_base, le_base; + hwaddr tcx_base; + hwaddr sbi_base; + uint64_t max_mem; + const char * const default_cpu_model; + uint32_t iounit_version; + uint16_t machine_id; + uint8_t nvram_machine_id; +}; + +struct sun4c_hwdef { + hwaddr iommu_base, slavio_base; + hwaddr intctl_base, counter_base, nvram_base, ms_kb_base; + hwaddr serial_base, fd_base; + hwaddr idreg_base, dma_base, esp_base, le_base; + hwaddr tcx_base, aux1_base; + uint64_t max_mem; + const char * const default_cpu_model; + uint32_t iommu_version; + uint16_t machine_id; + uint8_t nvram_machine_id; +}; + +int DMA_get_channel_mode (int nchan) +{ + return 0; +} +int DMA_read_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +int DMA_write_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +void DMA_hold_DREQ (int nchan) {} +void DMA_release_DREQ (int nchan) {} +void DMA_schedule(int nchan) {} + +void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) +{ +} + +void DMA_register_channel (int nchan, + DMA_transfer_handler transfer_handler, + void *opaque) +{ +} + +static int fw_cfg_boot_set(void *opaque, const char *boot_device) +{ + fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); + return 0; +} + +static void nvram_init(M48t59State *nvram, uint8_t *macaddr, + const char *cmdline, const char *boot_devices, + ram_addr_t RAM_size, uint32_t kernel_size, + int width, int height, int depth, + int nvram_machine_id, const char *arch) +{ + unsigned int i; + uint32_t start, end; + uint8_t image[0x1ff0]; + struct OpenBIOS_nvpart_v1 *part_header; + + memset(image, '\0', sizeof(image)); + + start = 0; + + // OpenBIOS nvram variables + // Variable partition + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_SYSTEM; + pstrcpy(part_header->name, sizeof(part_header->name), "system"); + + end = start + sizeof(struct OpenBIOS_nvpart_v1); + for (i = 0; i < nb_prom_envs; i++) + end = OpenBIOS_set_var(image, end, prom_envs[i]); + + // End marker + image[end++] = '\0'; + + end = start + ((end - start + 15) & ~15); + OpenBIOS_finish_partition(part_header, end - start); + + // free partition + start = end; + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_FREE; + pstrcpy(part_header->name, sizeof(part_header->name), "free"); + + end = 0x1fd0; + OpenBIOS_finish_partition(part_header, end - start); + + Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, + nvram_machine_id); + + for (i = 0; i < sizeof(image); i++) + m48t59_write(nvram, i, image[i]); +} + +static DeviceState *slavio_intctl; + +void sun4m_pic_info(Monitor *mon, const QDict *qdict) +{ + if (slavio_intctl) + slavio_pic_info(mon, slavio_intctl); +} + +void sun4m_irq_info(Monitor *mon, const QDict *qdict) +{ + if (slavio_intctl) + slavio_irq_info(mon, slavio_intctl); +} + +void cpu_check_irqs(CPUSPARCState *env) +{ + if (env->pil_in && (env->interrupt_index == 0 || + (env->interrupt_index & ~15) == TT_EXTINT)) { + unsigned int i; + + for (i = 15; i > 0; i--) { + if (env->pil_in & (1 << i)) { + int old_interrupt = env->interrupt_index; + + env->interrupt_index = TT_EXTINT | i; + if (old_interrupt != env->interrupt_index) { + trace_sun4m_cpu_interrupt(i); + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + break; + } + } + } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void cpu_kick_irq(SPARCCPU *cpu) +{ + CPUSPARCState *env = &cpu->env; + + env->halted = 0; + cpu_check_irqs(env); + qemu_cpu_kick(CPU(cpu)); +} + +static void cpu_set_irq(void *opaque, int irq, int level) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + if (level) { + trace_sun4m_cpu_set_irq_raise(irq); + env->pil_in |= 1 << irq; + cpu_kick_irq(cpu); + } else { + trace_sun4m_cpu_set_irq_lower(irq); + env->pil_in &= ~(1 << irq); + cpu_check_irqs(env); + } +} + +static void dummy_cpu_set_irq(void *opaque, int irq, int level) +{ +} + +static void main_cpu_reset(void *opaque) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + env->halted = 0; +} + +static void secondary_cpu_reset(void *opaque) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + env->halted = 1; +} + +static void cpu_halt_signal(void *opaque, int irq, int level) +{ + if (level && cpu_single_env) + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); +} + +static uint64_t translate_kernel_address(void *opaque, uint64_t addr) +{ + return addr - 0xf0000000ULL; +} + +static unsigned long sun4m_load_kernel(const char *kernel_filename, + const char *initrd_filename, + ram_addr_t RAM_size) +{ + int linux_boot; + unsigned int i; + long initrd_size, kernel_size; + uint8_t *ptr; + + linux_boot = (kernel_filename != NULL); + + kernel_size = 0; + if (linux_boot) { + int bswap_needed; + +#ifdef BSWAP_NEEDED + bswap_needed = 1; +#else + bswap_needed = 0; +#endif + kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, + NULL, NULL, NULL, 1, ELF_MACHINE, 0); + if (kernel_size < 0) + kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, + RAM_size - KERNEL_LOAD_ADDR, bswap_needed, + TARGET_PAGE_SIZE); + if (kernel_size < 0) + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + RAM_size - KERNEL_LOAD_ADDR); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image_targphys(initrd_filename, + INITRD_LOAD_ADDR, + RAM_size - INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + if (initrd_size > 0) { + for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { + ptr = rom_ptr(KERNEL_LOAD_ADDR + i); + if (ldl_p(ptr) == 0x48647253) { // HdrS + stl_p(ptr + 16, INITRD_LOAD_ADDR); + stl_p(ptr + 20, initrd_size); + break; + } + } + } + } + return kernel_size; +} + +static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "iommu"); + qdev_prop_set_uint32(dev, "version", version); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, irq); + sysbus_mmio_map(s, 0, addr); + + return s; +} + +static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, + void *iommu, qemu_irq *dev_irq, int is_ledma) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "sparc32_dma"); + qdev_prop_set_ptr(dev, "iommu_opaque", iommu); + qdev_prop_set_uint32(dev, "is_ledma", is_ledma); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, parent_irq); + *dev_irq = qdev_get_gpio_in(dev, 0); + sysbus_mmio_map(s, 0, daddr); + + return s; +} + +static void lance_init(NICInfo *nd, hwaddr leaddr, + void *dma_opaque, qemu_irq irq) +{ + DeviceState *dev; + SysBusDevice *s; + qemu_irq reset; + + qemu_check_nic_model(&nd_table[0], "lance"); + + dev = qdev_create(NULL, "lance"); + qdev_set_nic_properties(dev, nd); + qdev_prop_set_ptr(dev, "dma", dma_opaque); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(s, 0, leaddr); + sysbus_connect_irq(s, 0, irq); + reset = qdev_get_gpio_in(dev, 0); + qdev_connect_gpio_out(dma_opaque, 0, reset); +} + +static DeviceState *slavio_intctl_init(hwaddr addr, + hwaddr addrg, + qemu_irq **parent_irq) +{ + DeviceState *dev; + SysBusDevice *s; + unsigned int i, j; + + dev = qdev_create(NULL, "slavio_intctl"); + qdev_init_nofail(dev); + + s = SYS_BUS_DEVICE(dev); + + for (i = 0; i < MAX_CPUS; i++) { + for (j = 0; j < MAX_PILS; j++) { + sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]); + } + } + sysbus_mmio_map(s, 0, addrg); + for (i = 0; i < MAX_CPUS; i++) { + sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE); + } + + return dev; +} + +#define SYS_TIMER_OFFSET 0x10000ULL +#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu) + +static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq, + qemu_irq *cpu_irqs, unsigned int num_cpus) +{ + DeviceState *dev; + SysBusDevice *s; + unsigned int i; + + dev = qdev_create(NULL, "slavio_timer"); + qdev_prop_set_uint32(dev, "num_cpus", num_cpus); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, master_irq); + sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET); + + for (i = 0; i < MAX_CPUS; i++) { + sysbus_mmio_map(s, i + 1, addr + (hwaddr)CPU_TIMER_OFFSET(i)); + sysbus_connect_irq(s, i + 1, cpu_irqs[i]); + } +} + +static qemu_irq slavio_system_powerdown; + +static void slavio_powerdown_req(Notifier *n, void *opaque) +{ + qemu_irq_raise(slavio_system_powerdown); +} + +static Notifier slavio_system_powerdown_notifier = { + .notify = slavio_powerdown_req +}; + +#define MISC_LEDS 0x01600000 +#define MISC_CFG 0x01800000 +#define MISC_DIAG 0x01a00000 +#define MISC_MDM 0x01b00000 +#define MISC_SYS 0x01f00000 + +static void slavio_misc_init(hwaddr base, + hwaddr aux1_base, + hwaddr aux2_base, qemu_irq irq, + qemu_irq fdc_tc) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "slavio_misc"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + if (base) { + /* 8 bit registers */ + /* Slavio control */ + sysbus_mmio_map(s, 0, base + MISC_CFG); + /* Diagnostics */ + sysbus_mmio_map(s, 1, base + MISC_DIAG); + /* Modem control */ + sysbus_mmio_map(s, 2, base + MISC_MDM); + /* 16 bit registers */ + /* ss600mp diag LEDs */ + sysbus_mmio_map(s, 3, base + MISC_LEDS); + /* 32 bit registers */ + /* System control */ + sysbus_mmio_map(s, 4, base + MISC_SYS); + } + if (aux1_base) { + /* AUX 1 (Misc System Functions) */ + sysbus_mmio_map(s, 5, aux1_base); + } + if (aux2_base) { + /* AUX 2 (Software Powerdown Control) */ + sysbus_mmio_map(s, 6, aux2_base); + } + sysbus_connect_irq(s, 0, irq); + sysbus_connect_irq(s, 1, fdc_tc); + slavio_system_powerdown = qdev_get_gpio_in(dev, 0); + qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier); +} + +static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "eccmemctl"); + qdev_prop_set_uint32(dev, "version", version); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, irq); + sysbus_mmio_map(s, 0, base); + if (version == 0) { // SS-600MP only + sysbus_mmio_map(s, 1, base + 0x1000); + } +} + +static void apc_init(hwaddr power_base, qemu_irq cpu_halt) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "apc"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + /* Power management (APC) XXX: not a Slavio device */ + sysbus_mmio_map(s, 0, power_base); + sysbus_connect_irq(s, 0, cpu_halt); +} + +static void tcx_init(hwaddr addr, int vram_size, int width, + int height, int depth) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "SUNW,tcx"); + qdev_prop_set_taddr(dev, "addr", addr); + qdev_prop_set_uint32(dev, "vram_size", vram_size); + qdev_prop_set_uint16(dev, "width", width); + qdev_prop_set_uint16(dev, "height", height); + qdev_prop_set_uint16(dev, "depth", depth); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + /* 8-bit plane */ + sysbus_mmio_map(s, 0, addr + 0x00800000ULL); + /* DAC */ + sysbus_mmio_map(s, 1, addr + 0x00200000ULL); + /* TEC (dummy) */ + sysbus_mmio_map(s, 2, addr + 0x00700000ULL); + /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */ + sysbus_mmio_map(s, 3, addr + 0x00301000ULL); + if (depth == 24) { + /* 24-bit plane */ + sysbus_mmio_map(s, 4, addr + 0x02000000ULL); + /* Control plane */ + sysbus_mmio_map(s, 5, addr + 0x0a000000ULL); + } else { + /* THC 8 bit (dummy) */ + sysbus_mmio_map(s, 4, addr + 0x00300000ULL); + } +} + +/* NCR89C100/MACIO Internal ID register */ +static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 }; + +static void idreg_init(hwaddr addr) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "macio_idreg"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + + sysbus_mmio_map(s, 0, addr); + cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data)); +} + +typedef struct IDRegState { + SysBusDevice busdev; + MemoryRegion mem; +} IDRegState; + +static int idreg_init1(SysBusDevice *dev) +{ + IDRegState *s = FROM_SYSBUS(IDRegState, dev); + + memory_region_init_ram(&s->mem, "sun4m.idreg", sizeof(idreg_data)); + vmstate_register_ram_global(&s->mem); + memory_region_set_readonly(&s->mem, true); + sysbus_init_mmio(dev, &s->mem); + return 0; +} + +static void idreg_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = idreg_init1; +} + +static const TypeInfo idreg_info = { + .name = "macio_idreg", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IDRegState), + .class_init = idreg_class_init, +}; + +typedef struct AFXState { + SysBusDevice busdev; + MemoryRegion mem; +} AFXState; + +/* SS-5 TCX AFX register */ +static void afx_init(hwaddr addr) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "tcx_afx"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + + sysbus_mmio_map(s, 0, addr); +} + +static int afx_init1(SysBusDevice *dev) +{ + AFXState *s = FROM_SYSBUS(AFXState, dev); + + memory_region_init_ram(&s->mem, "sun4m.afx", 4); + vmstate_register_ram_global(&s->mem); + sysbus_init_mmio(dev, &s->mem); + return 0; +} + +static void afx_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = afx_init1; +} + +static const TypeInfo afx_info = { + .name = "tcx_afx", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AFXState), + .class_init = afx_class_init, +}; + +typedef struct PROMState { + SysBusDevice busdev; + MemoryRegion prom; +} PROMState; + +/* Boot PROM (OpenBIOS) */ +static uint64_t translate_prom_address(void *opaque, uint64_t addr) +{ + hwaddr *base_addr = (hwaddr *)opaque; + return addr + *base_addr - PROM_VADDR; +} + +static void prom_init(hwaddr addr, const char *bios_name) +{ + DeviceState *dev; + SysBusDevice *s; + char *filename; + int ret; + + dev = qdev_create(NULL, "openprom"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + + sysbus_mmio_map(s, 0, addr); + + /* load boot prom */ + if (bios_name == NULL) { + bios_name = PROM_FILENAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + ret = load_elf(filename, translate_prom_address, &addr, NULL, + NULL, NULL, 1, ELF_MACHINE, 0); + if (ret < 0 || ret > PROM_SIZE_MAX) { + ret = load_image_targphys(filename, addr, PROM_SIZE_MAX); + } + g_free(filename); + } else { + ret = -1; + } + if (ret < 0 || ret > PROM_SIZE_MAX) { + fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name); + exit(1); + } +} + +static int prom_init1(SysBusDevice *dev) +{ + PROMState *s = FROM_SYSBUS(PROMState, dev); + + memory_region_init_ram(&s->prom, "sun4m.prom", PROM_SIZE_MAX); + vmstate_register_ram_global(&s->prom); + memory_region_set_readonly(&s->prom, true); + sysbus_init_mmio(dev, &s->prom); + return 0; +} + +static Property prom_properties[] = { + {/* end of property list */}, +}; + +static void prom_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = prom_init1; + dc->props = prom_properties; +} + +static const TypeInfo prom_info = { + .name = "openprom", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PROMState), + .class_init = prom_class_init, +}; + +typedef struct RamDevice +{ + SysBusDevice busdev; + MemoryRegion ram; + uint64_t size; +} RamDevice; + +/* System RAM */ +static int ram_init1(SysBusDevice *dev) +{ + RamDevice *d = FROM_SYSBUS(RamDevice, dev); + + memory_region_init_ram(&d->ram, "sun4m.ram", d->size); + vmstate_register_ram_global(&d->ram); + sysbus_init_mmio(dev, &d->ram); + return 0; +} + +static void ram_init(hwaddr addr, ram_addr_t RAM_size, + uint64_t max_mem) +{ + DeviceState *dev; + SysBusDevice *s; + RamDevice *d; + + /* allocate RAM */ + if ((uint64_t)RAM_size > max_mem) { + fprintf(stderr, + "qemu: Too much memory for this machine: %d, maximum %d\n", + (unsigned int)(RAM_size / (1024 * 1024)), + (unsigned int)(max_mem / (1024 * 1024))); + exit(1); + } + dev = qdev_create(NULL, "memory"); + s = SYS_BUS_DEVICE(dev); + + d = FROM_SYSBUS(RamDevice, s); + d->size = RAM_size; + qdev_init_nofail(dev); + + sysbus_mmio_map(s, 0, addr); +} + +static Property ram_properties[] = { + DEFINE_PROP_UINT64("size", RamDevice, size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ram_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ram_init1; + dc->props = ram_properties; +} + +static const TypeInfo ram_info = { + .name = "memory", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RamDevice), + .class_init = ram_class_init, +}; + +static void cpu_devinit(const char *cpu_model, unsigned int id, + uint64_t prom_addr, qemu_irq **cpu_irqs) +{ + SPARCCPU *cpu; + CPUSPARCState *env; + + cpu = cpu_sparc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); + exit(1); + } + env = &cpu->env; + + cpu_sparc_set_id(env, id); + if (id == 0) { + qemu_register_reset(main_cpu_reset, cpu); + } else { + qemu_register_reset(secondary_cpu_reset, cpu); + env->halted = 1; + } + *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS); + env->prom_addr = prom_addr; +} + +static void dummy_fdc_tc(void *opaque, int irq, int level) +{ +} + +static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + unsigned int i; + void *iommu, *espdma, *ledma, *nvram; + qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS], + espdma_irq, ledma_irq; + qemu_irq esp_reset, dma_enable; + qemu_irq fdc_tc; + qemu_irq *cpu_halt; + unsigned long kernel_size; + DriveInfo *fd[MAX_FD]; + void *fw_cfg; + unsigned int num_vsimms; + + /* init CPUs */ + if (!cpu_model) + cpu_model = hwdef->default_cpu_model; + + for(i = 0; i < smp_cpus; i++) { + cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]); + } + + for (i = smp_cpus; i < MAX_CPUS; i++) + cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); + + + /* set up devices */ + ram_init(0, RAM_size, hwdef->max_mem); + /* models without ECC don't trap when missing ram is accessed */ + if (!hwdef->ecc_base) { + empty_slot_init(RAM_size, hwdef->max_mem - RAM_size); + } + + prom_init(hwdef->slavio_base, bios_name); + + slavio_intctl = slavio_intctl_init(hwdef->intctl_base, + hwdef->intctl_base + 0x10000ULL, + cpu_irqs); + + for (i = 0; i < 32; i++) { + slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i); + } + for (i = 0; i < MAX_CPUS; i++) { + slavio_cpu_irq[i] = qdev_get_gpio_in(slavio_intctl, 32 + i); + } + + if (hwdef->idreg_base) { + idreg_init(hwdef->idreg_base); + } + + if (hwdef->afx_base) { + afx_init(hwdef->afx_base); + } + + iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, + slavio_irq[30]); + + if (hwdef->iommu_pad_base) { + /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased. + Software shouldn't use aliased addresses, neither should it crash + when does. Using empty_slot instead of aliasing can help with + debugging such accesses */ + empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len); + } + + espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18], + iommu, &espdma_irq, 0); + + ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, + slavio_irq[16], iommu, &ledma_irq, 1); + + if (graphic_depth != 8 && graphic_depth != 24) { + fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); + exit (1); + } + num_vsimms = 0; + if (num_vsimms == 0) { + tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, + graphic_depth); + } + + for (i = num_vsimms; i < MAX_VSIMMS; i++) { + /* vsimm registers probed by OBP */ + if (hwdef->vsimm[i].reg_base) { + empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000); + } + } + + if (hwdef->sx_base) { + empty_slot_init(hwdef->sx_base, 0x2000); + } + + lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); + + nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 8); + + slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus); + + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14], + display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); + /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device + Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ + escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15], + serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); + + cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1); + if (hwdef->apc_base) { + apc_init(hwdef->apc_base, cpu_halt[0]); + } + + if (hwdef->fd_base) { + /* there is zero or one floppy drive */ + memset(fd, 0, sizeof(fd)); + fd[0] = drive_get(IF_FLOPPY, 0, 0); + sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd, + &fdc_tc); + } else { + fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1); + } + + slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base, + slavio_irq[30], fdc_tc); + + if (drive_get_max_bus(IF_SCSI) > 0) { + fprintf(stderr, "qemu: too many SCSI bus\n"); + exit(1); + } + + esp_init(hwdef->esp_base, 2, + espdma_memory_read, espdma_memory_write, + espdma, espdma_irq, &esp_reset, &dma_enable); + + qdev_connect_gpio_out(espdma, 0, esp_reset); + qdev_connect_gpio_out(espdma, 1, dma_enable); + + if (hwdef->cs_base) { + sysbus_create_simple("SUNW,CS4231", hwdef->cs_base, + slavio_irq[5]); + } + + if (hwdef->dbri_base) { + /* ISDN chip with attached CS4215 audio codec */ + /* prom space */ + empty_slot_init(hwdef->dbri_base+0x1000, 0x30); + /* reg space */ + empty_slot_init(hwdef->dbri_base+0x10000, 0x100); + } + + if (hwdef->bpp_base) { + /* parallel port */ + empty_slot_init(hwdef->bpp_base, 0x20); + } + + kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, + RAM_size); + + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, + boot_device, RAM_size, kernel_size, graphic_width, + graphic_height, graphic_depth, hwdef->nvram_machine_id, + "Sun4m"); + + if (hwdef->ecc_base) + ecc_init(hwdef->ecc_base, slavio_irq[28], + hwdef->ecc_version); + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + if (kernel_cmdline) { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); + pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, + strlen(kernel_cmdline) + 1); + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); + } + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]); + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); +} + +enum { + ss2_id = 0, + ss5_id = 32, + vger_id, + lx_id, + ss4_id, + scls_id, + sbook_id, + ss10_id = 64, + ss20_id, + ss600mp_id, + ss1000_id = 96, + ss2000_id, +}; + +static const struct sun4m_hwdef sun4m_hwdefs[] = { + /* SS-5 */ + { + .iommu_base = 0x10000000, + .iommu_pad_base = 0x10004000, + .iommu_pad_len = 0x0fffb000, + .tcx_base = 0x50000000, + .cs_base = 0x6c000000, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x6a000000, + .afx_base = 0x6e000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .nvram_machine_id = 0x80, + .machine_id = ss5_id, + .iommu_version = 0x05000000, + .max_mem = 0x10000000, + .default_cpu_model = "Fujitsu MB86904", + }, + /* SS-10 */ + { + .iommu_base = 0xfe0000000ULL, + .tcx_base = 0xe20000000ULL, + .slavio_base = 0xff0000000ULL, + .ms_kb_base = 0xff1000000ULL, + .serial_base = 0xff1100000ULL, + .nvram_base = 0xff1200000ULL, + .fd_base = 0xff1700000ULL, + .counter_base = 0xff1300000ULL, + .intctl_base = 0xff1400000ULL, + .idreg_base = 0xef0000000ULL, + .dma_base = 0xef0400000ULL, + .esp_base = 0xef0800000ULL, + .le_base = 0xef0c00000ULL, + .apc_base = 0xefa000000ULL, // XXX should not exist + .aux1_base = 0xff1800000ULL, + .aux2_base = 0xff1a01000ULL, + .ecc_base = 0xf00000000ULL, + .ecc_version = 0x10000000, // version 0, implementation 1 + .nvram_machine_id = 0x72, + .machine_id = ss10_id, + .iommu_version = 0x03000000, + .max_mem = 0xf00000000ULL, + .default_cpu_model = "TI SuperSparc II", + }, + /* SS-600MP */ + { + .iommu_base = 0xfe0000000ULL, + .tcx_base = 0xe20000000ULL, + .slavio_base = 0xff0000000ULL, + .ms_kb_base = 0xff1000000ULL, + .serial_base = 0xff1100000ULL, + .nvram_base = 0xff1200000ULL, + .counter_base = 0xff1300000ULL, + .intctl_base = 0xff1400000ULL, + .dma_base = 0xef0081000ULL, + .esp_base = 0xef0080000ULL, + .le_base = 0xef0060000ULL, + .apc_base = 0xefa000000ULL, // XXX should not exist + .aux1_base = 0xff1800000ULL, + .aux2_base = 0xff1a01000ULL, // XXX should not exist + .ecc_base = 0xf00000000ULL, + .ecc_version = 0x00000000, // version 0, implementation 0 + .nvram_machine_id = 0x71, + .machine_id = ss600mp_id, + .iommu_version = 0x01000000, + .max_mem = 0xf00000000ULL, + .default_cpu_model = "TI SuperSparc II", + }, + /* SS-20 */ + { + .iommu_base = 0xfe0000000ULL, + .tcx_base = 0xe20000000ULL, + .slavio_base = 0xff0000000ULL, + .ms_kb_base = 0xff1000000ULL, + .serial_base = 0xff1100000ULL, + .nvram_base = 0xff1200000ULL, + .fd_base = 0xff1700000ULL, + .counter_base = 0xff1300000ULL, + .intctl_base = 0xff1400000ULL, + .idreg_base = 0xef0000000ULL, + .dma_base = 0xef0400000ULL, + .esp_base = 0xef0800000ULL, + .le_base = 0xef0c00000ULL, + .bpp_base = 0xef4800000ULL, + .apc_base = 0xefa000000ULL, // XXX should not exist + .aux1_base = 0xff1800000ULL, + .aux2_base = 0xff1a01000ULL, + .dbri_base = 0xee0000000ULL, + .sx_base = 0xf80000000ULL, + .vsimm = { + { + .reg_base = 0x9c000000ULL, + .vram_base = 0xfc000000ULL + }, { + .reg_base = 0x90000000ULL, + .vram_base = 0xf0000000ULL + }, { + .reg_base = 0x94000000ULL + }, { + .reg_base = 0x98000000ULL + } + }, + .ecc_base = 0xf00000000ULL, + .ecc_version = 0x20000000, // version 0, implementation 2 + .nvram_machine_id = 0x72, + .machine_id = ss20_id, + .iommu_version = 0x13000000, + .max_mem = 0xf00000000ULL, + .default_cpu_model = "TI SuperSparc II", + }, + /* Voyager */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x71300000, // pmc + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .nvram_machine_id = 0x80, + .machine_id = vger_id, + .iommu_version = 0x05000000, + .max_mem = 0x10000000, + .default_cpu_model = "Fujitsu MB86904", + }, + /* LX */ + { + .iommu_base = 0x10000000, + .iommu_pad_base = 0x10004000, + .iommu_pad_len = 0x0fffb000, + .tcx_base = 0x50000000, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .nvram_machine_id = 0x80, + .machine_id = lx_id, + .iommu_version = 0x04000000, + .max_mem = 0x10000000, + .default_cpu_model = "TI MicroSparc I", + }, + /* SS-4 */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .cs_base = 0x6c000000, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x6a000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .nvram_machine_id = 0x80, + .machine_id = ss4_id, + .iommu_version = 0x05000000, + .max_mem = 0x10000000, + .default_cpu_model = "Fujitsu MB86904", + }, + /* SPARCClassic */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x6a000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .nvram_machine_id = 0x80, + .machine_id = scls_id, + .iommu_version = 0x05000000, + .max_mem = 0x10000000, + .default_cpu_model = "TI MicroSparc I", + }, + /* SPARCbook */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, // XXX + .slavio_base = 0x70000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .idreg_base = 0x78000000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .apc_base = 0x6a000000, + .aux1_base = 0x71900000, + .aux2_base = 0x71910000, + .nvram_machine_id = 0x80, + .machine_id = sbook_id, + .iommu_version = 0x05000000, + .max_mem = 0x10000000, + .default_cpu_model = "TI MicroSparc I", + }, +}; + +/* SPARCstation 5 hardware initialisation */ +static void ss5_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation 10 hardware initialisation */ +static void ss10_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCserver 600MP hardware initialisation */ +static void ss600mp_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation 20 hardware initialisation */ +static void ss20_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation Voyager hardware initialisation */ +static void vger_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation LX hardware initialisation */ +static void ss_lx_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCstation 4 hardware initialisation */ +static void ss4_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCClassic hardware initialisation */ +static void scls_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCbook hardware initialisation */ +static void sbook_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +static QEMUMachine ss5_machine = { + .name = "SS-5", + .desc = "Sun4m platform, SPARCstation 5", + .init = ss5_init, + .block_default_type = IF_SCSI, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine ss10_machine = { + .name = "SS-10", + .desc = "Sun4m platform, SPARCstation 10", + .init = ss10_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine ss600mp_machine = { + .name = "SS-600MP", + .desc = "Sun4m platform, SPARCserver 600MP", + .init = ss600mp_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine ss20_machine = { + .name = "SS-20", + .desc = "Sun4m platform, SPARCstation 20", + .init = ss20_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine voyager_machine = { + .name = "Voyager", + .desc = "Sun4m platform, SPARCstation Voyager", + .init = vger_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine ss_lx_machine = { + .name = "LX", + .desc = "Sun4m platform, SPARCstation LX", + .init = ss_lx_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine ss4_machine = { + .name = "SS-4", + .desc = "Sun4m platform, SPARCstation 4", + .init = ss4_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine scls_machine = { + .name = "SPARCClassic", + .desc = "Sun4m platform, SPARCClassic", + .init = scls_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine sbook_machine = { + .name = "SPARCbook", + .desc = "Sun4m platform, SPARCbook", + .init = sbook_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static const struct sun4d_hwdef sun4d_hwdefs[] = { + /* SS-1000 */ + { + .iounit_bases = { + 0xfe0200000ULL, + 0xfe1200000ULL, + 0xfe2200000ULL, + 0xfe3200000ULL, + -1, + }, + .tcx_base = 0x820000000ULL, + .slavio_base = 0xf00000000ULL, + .ms_kb_base = 0xf00240000ULL, + .serial_base = 0xf00200000ULL, + .nvram_base = 0xf00280000ULL, + .counter_base = 0xf00300000ULL, + .espdma_base = 0x800081000ULL, + .esp_base = 0x800080000ULL, + .ledma_base = 0x800040000ULL, + .le_base = 0x800060000ULL, + .sbi_base = 0xf02800000ULL, + .nvram_machine_id = 0x80, + .machine_id = ss1000_id, + .iounit_version = 0x03000000, + .max_mem = 0xf00000000ULL, + .default_cpu_model = "TI SuperSparc II", + }, + /* SS-2000 */ + { + .iounit_bases = { + 0xfe0200000ULL, + 0xfe1200000ULL, + 0xfe2200000ULL, + 0xfe3200000ULL, + 0xfe4200000ULL, + }, + .tcx_base = 0x820000000ULL, + .slavio_base = 0xf00000000ULL, + .ms_kb_base = 0xf00240000ULL, + .serial_base = 0xf00200000ULL, + .nvram_base = 0xf00280000ULL, + .counter_base = 0xf00300000ULL, + .espdma_base = 0x800081000ULL, + .esp_base = 0x800080000ULL, + .ledma_base = 0x800040000ULL, + .le_base = 0x800060000ULL, + .sbi_base = 0xf02800000ULL, + .nvram_machine_id = 0x80, + .machine_id = ss2000_id, + .iounit_version = 0x03000000, + .max_mem = 0xf00000000ULL, + .default_cpu_model = "TI SuperSparc II", + }, +}; + +static DeviceState *sbi_init(hwaddr addr, qemu_irq **parent_irq) +{ + DeviceState *dev; + SysBusDevice *s; + unsigned int i; + + dev = qdev_create(NULL, "sbi"); + qdev_init_nofail(dev); + + s = SYS_BUS_DEVICE(dev); + + for (i = 0; i < MAX_CPUS; i++) { + sysbus_connect_irq(s, i, *parent_irq[i]); + } + + sysbus_mmio_map(s, 0, addr); + + return dev; +} + +static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + unsigned int i; + void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram; + qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS], + espdma_irq, ledma_irq; + qemu_irq esp_reset, dma_enable; + unsigned long kernel_size; + void *fw_cfg; + DeviceState *dev; + + /* init CPUs */ + if (!cpu_model) + cpu_model = hwdef->default_cpu_model; + + for(i = 0; i < smp_cpus; i++) { + cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]); + } + + for (i = smp_cpus; i < MAX_CPUS; i++) + cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); + + /* set up devices */ + ram_init(0, RAM_size, hwdef->max_mem); + + prom_init(hwdef->slavio_base, bios_name); + + dev = sbi_init(hwdef->sbi_base, cpu_irqs); + + for (i = 0; i < 32; i++) { + sbi_irq[i] = qdev_get_gpio_in(dev, i); + } + for (i = 0; i < MAX_CPUS; i++) { + sbi_cpu_irq[i] = qdev_get_gpio_in(dev, 32 + i); + } + + for (i = 0; i < MAX_IOUNITS; i++) + if (hwdef->iounit_bases[i] != (hwaddr)-1) + iounits[i] = iommu_init(hwdef->iounit_bases[i], + hwdef->iounit_version, + sbi_irq[0]); + + espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[3], + iounits[0], &espdma_irq, 0); + + /* should be lebuffer instead */ + ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[4], + iounits[0], &ledma_irq, 0); + + if (graphic_depth != 8 && graphic_depth != 24) { + fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); + exit (1); + } + tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, + graphic_depth); + + lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); + + nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0, 0x2000, 8); + + slavio_timer_init_all(hwdef->counter_base, sbi_irq[10], sbi_cpu_irq, smp_cpus); + + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[12], + display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); + /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device + Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ + escc_init(hwdef->serial_base, sbi_irq[12], sbi_irq[12], + serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); + + if (drive_get_max_bus(IF_SCSI) > 0) { + fprintf(stderr, "qemu: too many SCSI bus\n"); + exit(1); + } + + esp_init(hwdef->esp_base, 2, + espdma_memory_read, espdma_memory_write, + espdma, espdma_irq, &esp_reset, &dma_enable); + + qdev_connect_gpio_out(espdma, 0, esp_reset); + qdev_connect_gpio_out(espdma, 1, dma_enable); + + kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, + RAM_size); + + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, + boot_device, RAM_size, kernel_size, graphic_width, + graphic_height, graphic_depth, hwdef->nvram_machine_id, + "Sun4d"); + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + if (kernel_cmdline) { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); + pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); + } + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]); + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); +} + +/* SPARCserver 1000 hardware initialisation */ +static void ss1000_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +/* SPARCcenter 2000 hardware initialisation */ +static void ss2000_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +static QEMUMachine ss1000_machine = { + .name = "SS-1000", + .desc = "Sun4d platform, SPARCserver 1000", + .init = ss1000_init, + .block_default_type = IF_SCSI, + .max_cpus = 8, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine ss2000_machine = { + .name = "SS-2000", + .desc = "Sun4d platform, SPARCcenter 2000", + .init = ss2000_init, + .block_default_type = IF_SCSI, + .max_cpus = 20, + DEFAULT_MACHINE_OPTIONS, +}; + +static const struct sun4c_hwdef sun4c_hwdefs[] = { + /* SS-2 */ + { + .iommu_base = 0xf8000000, + .tcx_base = 0xfe000000, + .slavio_base = 0xf6000000, + .intctl_base = 0xf5000000, + .counter_base = 0xf3000000, + .ms_kb_base = 0xf0000000, + .serial_base = 0xf1000000, + .nvram_base = 0xf2000000, + .fd_base = 0xf7200000, + .dma_base = 0xf8400000, + .esp_base = 0xf8800000, + .le_base = 0xf8c00000, + .aux1_base = 0xf7400003, + .nvram_machine_id = 0x55, + .machine_id = ss2_id, + .max_mem = 0x10000000, + .default_cpu_model = "Cypress CY7C601", + }, +}; + +static DeviceState *sun4c_intctl_init(hwaddr addr, + qemu_irq *parent_irq) +{ + DeviceState *dev; + SysBusDevice *s; + unsigned int i; + + dev = qdev_create(NULL, "sun4c_intctl"); + qdev_init_nofail(dev); + + s = SYS_BUS_DEVICE(dev); + + for (i = 0; i < MAX_PILS; i++) { + sysbus_connect_irq(s, i, parent_irq[i]); + } + sysbus_mmio_map(s, 0, addr); + + return dev; +} + +static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + void *iommu, *espdma, *ledma, *nvram; + qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq; + qemu_irq esp_reset, dma_enable; + qemu_irq fdc_tc; + unsigned long kernel_size; + DriveInfo *fd[MAX_FD]; + void *fw_cfg; + DeviceState *dev; + unsigned int i; + + /* init CPU */ + if (!cpu_model) + cpu_model = hwdef->default_cpu_model; + + cpu_devinit(cpu_model, 0, hwdef->slavio_base, &cpu_irqs); + + /* set up devices */ + ram_init(0, RAM_size, hwdef->max_mem); + + prom_init(hwdef->slavio_base, bios_name); + + dev = sun4c_intctl_init(hwdef->intctl_base, cpu_irqs); + + for (i = 0; i < 8; i++) { + slavio_irq[i] = qdev_get_gpio_in(dev, i); + } + + iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, + slavio_irq[1]); + + espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[2], + iommu, &espdma_irq, 0); + + ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, + slavio_irq[3], iommu, &ledma_irq, 1); + + if (graphic_depth != 8 && graphic_depth != 24) { + fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); + exit (1); + } + tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, + graphic_depth); + + lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); + + nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x800, 2); + + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[1], + display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); + /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device + Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ + escc_init(hwdef->serial_base, slavio_irq[1], + slavio_irq[1], serial_hds[0], serial_hds[1], + ESCC_CLOCK, 1); + + if (hwdef->fd_base != (hwaddr)-1) { + /* there is zero or one floppy drive */ + memset(fd, 0, sizeof(fd)); + fd[0] = drive_get(IF_FLOPPY, 0, 0); + sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd, + &fdc_tc); + } else { + fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1); + } + + slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc); + + if (drive_get_max_bus(IF_SCSI) > 0) { + fprintf(stderr, "qemu: too many SCSI bus\n"); + exit(1); + } + + esp_init(hwdef->esp_base, 2, + espdma_memory_read, espdma_memory_write, + espdma, espdma_irq, &esp_reset, &dma_enable); + + qdev_connect_gpio_out(espdma, 0, esp_reset); + qdev_connect_gpio_out(espdma, 1, dma_enable); + + kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, + RAM_size); + + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, + boot_device, RAM_size, kernel_size, graphic_width, + graphic_height, graphic_depth, hwdef->nvram_machine_id, + "Sun4c"); + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + if (kernel_cmdline) { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); + pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); + } + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]); + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); +} + +/* SPARCstation 2 hardware initialisation */ +static void ss2_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + +static QEMUMachine ss2_machine = { + .name = "SS-2", + .desc = "Sun4c platform, SPARCstation 2", + .init = ss2_init, + .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, +}; + +static void sun4m_register_types(void) +{ + type_register_static(&idreg_info); + type_register_static(&afx_info); + type_register_static(&prom_info); + type_register_static(&ram_info); +} + +static void ss2_machine_init(void) +{ + qemu_register_machine(&ss5_machine); + qemu_register_machine(&ss10_machine); + qemu_register_machine(&ss600mp_machine); + qemu_register_machine(&ss20_machine); + qemu_register_machine(&voyager_machine); + qemu_register_machine(&ss_lx_machine); + qemu_register_machine(&ss4_machine); + qemu_register_machine(&scls_machine); + qemu_register_machine(&sbook_machine); + qemu_register_machine(&ss1000_machine); + qemu_register_machine(&ss2000_machine); + qemu_register_machine(&ss2_machine); +} + +type_init(sun4m_register_types) +machine_init(ss2_machine_init); diff --git a/hw/sparc64/Makefile.objs b/hw/sparc64/Makefile.objs index 8c65fc4215..4df0d90ec2 100644 --- a/hw/sparc64/Makefile.objs +++ b/hw/sparc64/Makefile.objs @@ -1,4 +1,6 @@ -obj-y = sun4u.o apb_pci.o +obj-y = apb_pci.o obj-y += mc146818rtc.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += sun4u.o diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c new file mode 100644 index 0000000000..51ffa1c09b --- /dev/null +++ b/hw/sparc64/sun4u.c @@ -0,0 +1,1014 @@ +/* + * QEMU Sun4u/Sun4v System Emulator + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/apb_pci.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/nvram.h" +#include "hw/fdc.h" +#include "net/net.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/firmware_abi.h" +#include "hw/fw_cfg.h" +#include "hw/sysbus.h" +#include "hw/ide.h" +#include "hw/loader.h" +#include "elf.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" + +//#define DEBUG_IRQ +//#define DEBUG_EBUS +//#define DEBUG_TIMER + +#ifdef DEBUG_IRQ +#define CPUIRQ_DPRINTF(fmt, ...) \ + do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0) +#else +#define CPUIRQ_DPRINTF(fmt, ...) +#endif + +#ifdef DEBUG_EBUS +#define EBUS_DPRINTF(fmt, ...) \ + do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0) +#else +#define EBUS_DPRINTF(fmt, ...) +#endif + +#ifdef DEBUG_TIMER +#define TIMER_DPRINTF(fmt, ...) \ + do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0) +#else +#define TIMER_DPRINTF(fmt, ...) +#endif + +#define KERNEL_LOAD_ADDR 0x00404000 +#define CMDLINE_ADDR 0x003ff000 +#define PROM_SIZE_MAX (4 * 1024 * 1024) +#define PROM_VADDR 0x000ffd00000ULL +#define APB_SPECIAL_BASE 0x1fe00000000ULL +#define APB_MEM_BASE 0x1ff00000000ULL +#define APB_PCI_IO_BASE (APB_SPECIAL_BASE + 0x02000000ULL) +#define PROM_FILENAME "openbios-sparc64" +#define NVRAM_SIZE 0x2000 +#define MAX_IDE_BUS 2 +#define BIOS_CFG_IOPORT 0x510 +#define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) +#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) +#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) + +#define IVEC_MAX 0x30 + +#define TICK_MAX 0x7fffffffffffffffULL + +struct hwdef { + const char * const default_cpu_model; + uint16_t machine_id; + uint64_t prom_addr; + uint64_t console_serial_base; +}; + +typedef struct EbusState { + PCIDevice pci_dev; + MemoryRegion bar0; + MemoryRegion bar1; +} EbusState; + +int DMA_get_channel_mode (int nchan) +{ + return 0; +} +int DMA_read_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +int DMA_write_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +void DMA_hold_DREQ (int nchan) {} +void DMA_release_DREQ (int nchan) {} +void DMA_schedule(int nchan) {} + +void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) +{ +} + +void DMA_register_channel (int nchan, + DMA_transfer_handler transfer_handler, + void *opaque) +{ +} + +static int fw_cfg_boot_set(void *opaque, const char *boot_device) +{ + fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); + return 0; +} + +static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size, + const char *arch, ram_addr_t RAM_size, + const char *boot_devices, + uint32_t kernel_image, uint32_t kernel_size, + const char *cmdline, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image, + int width, int height, int depth, + const uint8_t *macaddr) +{ + unsigned int i; + uint32_t start, end; + uint8_t image[0x1ff0]; + struct OpenBIOS_nvpart_v1 *part_header; + + memset(image, '\0', sizeof(image)); + + start = 0; + + // OpenBIOS nvram variables + // Variable partition + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_SYSTEM; + pstrcpy(part_header->name, sizeof(part_header->name), "system"); + + end = start + sizeof(struct OpenBIOS_nvpart_v1); + for (i = 0; i < nb_prom_envs; i++) + end = OpenBIOS_set_var(image, end, prom_envs[i]); + + // End marker + image[end++] = '\0'; + + end = start + ((end - start + 15) & ~15); + OpenBIOS_finish_partition(part_header, end - start); + + // free partition + start = end; + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_FREE; + pstrcpy(part_header->name, sizeof(part_header->name), "free"); + + end = 0x1fd0; + OpenBIOS_finish_partition(part_header, end - start); + + Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80); + + for (i = 0; i < sizeof(image); i++) + m48t59_write(nvram, i, image[i]); + + return 0; +} + +static uint64_t sun4u_load_kernel(const char *kernel_filename, + const char *initrd_filename, + ram_addr_t RAM_size, uint64_t *initrd_size, + uint64_t *initrd_addr, uint64_t *kernel_addr, + uint64_t *kernel_entry) +{ + int linux_boot; + unsigned int i; + long kernel_size; + uint8_t *ptr; + uint64_t kernel_top; + + linux_boot = (kernel_filename != NULL); + + kernel_size = 0; + if (linux_boot) { + int bswap_needed; + +#ifdef BSWAP_NEEDED + bswap_needed = 1; +#else + bswap_needed = 0; +#endif + kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry, + kernel_addr, &kernel_top, 1, ELF_MACHINE, 0); + if (kernel_size < 0) { + *kernel_addr = KERNEL_LOAD_ADDR; + *kernel_entry = KERNEL_LOAD_ADDR; + kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, + RAM_size - KERNEL_LOAD_ADDR, bswap_needed, + TARGET_PAGE_SIZE); + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + RAM_size - KERNEL_LOAD_ADDR); + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd above kernel */ + *initrd_size = 0; + if (initrd_filename) { + *initrd_addr = TARGET_PAGE_ALIGN(kernel_top); + + *initrd_size = load_image_targphys(initrd_filename, + *initrd_addr, + RAM_size - *initrd_addr); + if ((int)*initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + if (*initrd_size > 0) { + for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { + ptr = rom_ptr(*kernel_addr + i); + if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ + stl_p(ptr + 24, *initrd_addr + *kernel_addr); + stl_p(ptr + 28, *initrd_size); + break; + } + } + } + } + return kernel_size; +} + +void cpu_check_irqs(CPUSPARCState *env) +{ + uint32_t pil = env->pil_in | + (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER)); + + /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */ + if (env->ivec_status & 0x20) { + return; + } + /* check if TM or SM in SOFTINT are set + setting these also causes interrupt 14 */ + if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) { + pil |= 1 << 14; + } + + /* The bit corresponding to psrpil is (1<< psrpil), the next bit + is (2 << psrpil). */ + if (pil < (2 << env->psrpil)){ + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n", + env->interrupt_index); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } + return; + } + + if (cpu_interrupts_enabled(env)) { + + unsigned int i; + + for (i = 15; i > env->psrpil; i--) { + if (pil & (1 << i)) { + int old_interrupt = env->interrupt_index; + int new_interrupt = TT_EXTINT | i; + + if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt + && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) { + CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d " + "current %x >= pending %x\n", + env->tl, cpu_tsptr(env)->tt, new_interrupt); + } else if (old_interrupt != new_interrupt) { + env->interrupt_index = new_interrupt; + CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i, + old_interrupt, new_interrupt); + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + break; + } + } + } else if (env->interrupt_request & CPU_INTERRUPT_HARD) { + CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x " + "current interrupt %x\n", + pil, env->pil_in, env->softint, env->interrupt_index); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void cpu_kick_irq(SPARCCPU *cpu) +{ + CPUSPARCState *env = &cpu->env; + + env->halted = 0; + cpu_check_irqs(env); + qemu_cpu_kick(CPU(cpu)); +} + +static void cpu_set_ivec_irq(void *opaque, int irq, int level) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + if (level) { + if (!(env->ivec_status & 0x20)) { + CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq); + env->halted = 0; + env->interrupt_index = TT_IVEC; + env->ivec_status |= 0x20; + env->ivec_data[0] = (0x1f << 6) | irq; + env->ivec_data[1] = 0; + env->ivec_data[2] = 0; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + } else { + if (env->ivec_status & 0x20) { + CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq); + env->ivec_status &= ~0x20; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } + } +} + +typedef struct ResetData { + SPARCCPU *cpu; + uint64_t prom_addr; +} ResetData; + +void cpu_put_timer(QEMUFile *f, CPUTimer *s) +{ + qemu_put_be32s(f, &s->frequency); + qemu_put_be32s(f, &s->disabled); + qemu_put_be64s(f, &s->disabled_mask); + qemu_put_sbe64s(f, &s->clock_offset); + + qemu_put_timer(f, s->qtimer); +} + +void cpu_get_timer(QEMUFile *f, CPUTimer *s) +{ + qemu_get_be32s(f, &s->frequency); + qemu_get_be32s(f, &s->disabled); + qemu_get_be64s(f, &s->disabled_mask); + qemu_get_sbe64s(f, &s->clock_offset); + + qemu_get_timer(f, s->qtimer); +} + +static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, + QEMUBHFunc *cb, uint32_t frequency, + uint64_t disabled_mask) +{ + CPUTimer *timer = g_malloc0(sizeof (CPUTimer)); + + timer->name = name; + timer->frequency = frequency; + timer->disabled_mask = disabled_mask; + + timer->disabled = 1; + timer->clock_offset = qemu_get_clock_ns(vm_clock); + + timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu); + + return timer; +} + +static void cpu_timer_reset(CPUTimer *timer) +{ + timer->disabled = 1; + timer->clock_offset = qemu_get_clock_ns(vm_clock); + + qemu_del_timer(timer->qtimer); +} + +static void main_cpu_reset(void *opaque) +{ + ResetData *s = (ResetData *)opaque; + CPUSPARCState *env = &s->cpu->env; + static unsigned int nr_resets; + + cpu_reset(CPU(s->cpu)); + + cpu_timer_reset(env->tick); + cpu_timer_reset(env->stick); + cpu_timer_reset(env->hstick); + + env->gregs[1] = 0; // Memory start + env->gregs[2] = ram_size; // Memory size + env->gregs[3] = 0; // Machine description XXX + if (nr_resets++ == 0) { + /* Power on reset */ + env->pc = s->prom_addr + 0x20ULL; + } else { + env->pc = s->prom_addr + 0x40ULL; + } + env->npc = env->pc + 4; +} + +static void tick_irq(void *opaque) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + CPUTimer* timer = env->tick; + + if (timer->disabled) { + CPUIRQ_DPRINTF("tick_irq: softint disabled\n"); + return; + } else { + CPUIRQ_DPRINTF("tick: fire\n"); + } + + env->softint |= SOFTINT_TIMER; + cpu_kick_irq(cpu); +} + +static void stick_irq(void *opaque) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + CPUTimer* timer = env->stick; + + if (timer->disabled) { + CPUIRQ_DPRINTF("stick_irq: softint disabled\n"); + return; + } else { + CPUIRQ_DPRINTF("stick: fire\n"); + } + + env->softint |= SOFTINT_STIMER; + cpu_kick_irq(cpu); +} + +static void hstick_irq(void *opaque) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + CPUTimer* timer = env->hstick; + + if (timer->disabled) { + CPUIRQ_DPRINTF("hstick_irq: softint disabled\n"); + return; + } else { + CPUIRQ_DPRINTF("hstick: fire\n"); + } + + env->softint |= SOFTINT_STIMER; + cpu_kick_irq(cpu); +} + +static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency) +{ + return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency); +} + +static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency) +{ + return muldiv64(timer_ticks, frequency, get_ticks_per_sec()); +} + +void cpu_tick_set_count(CPUTimer *timer, uint64_t count) +{ + uint64_t real_count = count & ~timer->disabled_mask; + uint64_t disabled_bit = count & timer->disabled_mask; + + int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) - + cpu_to_timer_ticks(real_count, timer->frequency); + + TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n", + timer->name, real_count, + timer->disabled?"disabled":"enabled", timer); + + timer->disabled = disabled_bit ? 1 : 0; + timer->clock_offset = vm_clock_offset; +} + +uint64_t cpu_tick_get_count(CPUTimer *timer) +{ + uint64_t real_count = timer_to_cpu_ticks( + qemu_get_clock_ns(vm_clock) - timer->clock_offset, + timer->frequency); + + TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n", + timer->name, real_count, + timer->disabled?"disabled":"enabled", timer); + + if (timer->disabled) + real_count |= timer->disabled_mask; + + return real_count; +} + +void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) +{ + int64_t now = qemu_get_clock_ns(vm_clock); + + uint64_t real_limit = limit & ~timer->disabled_mask; + timer->disabled = (limit & timer->disabled_mask) ? 1 : 0; + + int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) + + timer->clock_offset; + + if (expires < now) { + expires = now + 1; + } + + TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p " + "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n", + timer->name, real_limit, + timer->disabled?"disabled":"enabled", + timer, limit, + timer_to_cpu_ticks(now - timer->clock_offset, + timer->frequency), + timer_to_cpu_ticks(expires - now, timer->frequency)); + + if (!real_limit) { + TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n", + timer->name); + qemu_del_timer(timer->qtimer); + } else if (timer->disabled) { + qemu_del_timer(timer->qtimer); + } else { + qemu_mod_timer(timer->qtimer, expires); + } +} + +static void isa_irq_handler(void *opaque, int n, int level) +{ + static const int isa_irq_to_ivec[16] = { + [1] = 0x29, /* keyboard */ + [4] = 0x2b, /* serial */ + [6] = 0x27, /* floppy */ + [7] = 0x22, /* parallel */ + [12] = 0x2a, /* mouse */ + }; + qemu_irq *irqs = opaque; + int ivec; + + assert(n < 16); + ivec = isa_irq_to_ivec[n]; + EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec); + if (ivec) { + qemu_set_irq(irqs[ivec], level); + } +} + +/* EBUS (Eight bit bus) bridge */ +static ISABus * +pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs) +{ + qemu_irq *isa_irq; + PCIDevice *pci_dev; + ISABus *isa_bus; + + pci_dev = pci_create_simple(bus, devfn, "ebus"); + isa_bus = DO_UPCAST(ISABus, qbus, + qdev_get_child_bus(&pci_dev->qdev, "isa.0")); + isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16); + isa_bus_irqs(isa_bus, isa_irq); + return isa_bus; +} + +static int +pci_ebus_init1(PCIDevice *pci_dev) +{ + EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev); + + isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev)); + + pci_dev->config[0x04] = 0x06; // command = bus master, pci mem + pci_dev->config[0x05] = 0x00; + pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error + pci_dev->config[0x07] = 0x03; // status = medium devsel + pci_dev->config[0x09] = 0x00; // programming i/f + pci_dev->config[0x0D] = 0x0a; // latency_timer + + isa_mmio_setup(&s->bar0, 0x1000000); + pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0); + isa_mmio_setup(&s->bar1, 0x800000); + pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1); + return 0; +} + +static void ebus_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_ebus_init1; + k->vendor_id = PCI_VENDOR_ID_SUN; + k->device_id = PCI_DEVICE_ID_SUN_EBUS; + k->revision = 0x01; + k->class_id = PCI_CLASS_BRIDGE_OTHER; +} + +static const TypeInfo ebus_info = { + .name = "ebus", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EbusState), + .class_init = ebus_class_init, +}; + +typedef struct PROMState { + SysBusDevice busdev; + MemoryRegion prom; +} PROMState; + +static uint64_t translate_prom_address(void *opaque, uint64_t addr) +{ + hwaddr *base_addr = (hwaddr *)opaque; + return addr + *base_addr - PROM_VADDR; +} + +/* Boot PROM (OpenBIOS) */ +static void prom_init(hwaddr addr, const char *bios_name) +{ + DeviceState *dev; + SysBusDevice *s; + char *filename; + int ret; + + dev = qdev_create(NULL, "openprom"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + + sysbus_mmio_map(s, 0, addr); + + /* load boot prom */ + if (bios_name == NULL) { + bios_name = PROM_FILENAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + ret = load_elf(filename, translate_prom_address, &addr, + NULL, NULL, NULL, 1, ELF_MACHINE, 0); + if (ret < 0 || ret > PROM_SIZE_MAX) { + ret = load_image_targphys(filename, addr, PROM_SIZE_MAX); + } + g_free(filename); + } else { + ret = -1; + } + if (ret < 0 || ret > PROM_SIZE_MAX) { + fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name); + exit(1); + } +} + +static int prom_init1(SysBusDevice *dev) +{ + PROMState *s = FROM_SYSBUS(PROMState, dev); + + memory_region_init_ram(&s->prom, "sun4u.prom", PROM_SIZE_MAX); + vmstate_register_ram_global(&s->prom); + memory_region_set_readonly(&s->prom, true); + sysbus_init_mmio(dev, &s->prom); + return 0; +} + +static Property prom_properties[] = { + {/* end of property list */}, +}; + +static void prom_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = prom_init1; + dc->props = prom_properties; +} + +static const TypeInfo prom_info = { + .name = "openprom", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PROMState), + .class_init = prom_class_init, +}; + + +typedef struct RamDevice +{ + SysBusDevice busdev; + MemoryRegion ram; + uint64_t size; +} RamDevice; + +/* System RAM */ +static int ram_init1(SysBusDevice *dev) +{ + RamDevice *d = FROM_SYSBUS(RamDevice, dev); + + memory_region_init_ram(&d->ram, "sun4u.ram", d->size); + vmstate_register_ram_global(&d->ram); + sysbus_init_mmio(dev, &d->ram); + return 0; +} + +static void ram_init(hwaddr addr, ram_addr_t RAM_size) +{ + DeviceState *dev; + SysBusDevice *s; + RamDevice *d; + + /* allocate RAM */ + dev = qdev_create(NULL, "memory"); + s = SYS_BUS_DEVICE(dev); + + d = FROM_SYSBUS(RamDevice, s); + d->size = RAM_size; + qdev_init_nofail(dev); + + sysbus_mmio_map(s, 0, addr); +} + +static Property ram_properties[] = { + DEFINE_PROP_UINT64("size", RamDevice, size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ram_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ram_init1; + dc->props = ram_properties; +} + +static const TypeInfo ram_info = { + .name = "memory", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RamDevice), + .class_init = ram_class_init, +}; + +static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) +{ + SPARCCPU *cpu; + CPUSPARCState *env; + ResetData *reset_info; + + uint32_t tick_frequency = 100*1000000; + uint32_t stick_frequency = 100*1000000; + uint32_t hstick_frequency = 100*1000000; + + if (cpu_model == NULL) { + cpu_model = hwdef->default_cpu_model; + } + cpu = cpu_sparc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find Sparc CPU definition\n"); + exit(1); + } + env = &cpu->env; + + env->tick = cpu_timer_create("tick", cpu, tick_irq, + tick_frequency, TICK_NPT_MASK); + + env->stick = cpu_timer_create("stick", cpu, stick_irq, + stick_frequency, TICK_INT_DIS); + + env->hstick = cpu_timer_create("hstick", cpu, hstick_irq, + hstick_frequency, TICK_INT_DIS); + + reset_info = g_malloc0(sizeof(ResetData)); + reset_info->cpu = cpu; + reset_info->prom_addr = hwdef->prom_addr; + qemu_register_reset(main_cpu_reset, reset_info); + + return cpu; +} + +static void sun4uv_init(MemoryRegion *address_space_mem, + ram_addr_t RAM_size, + const char *boot_devices, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model, + const struct hwdef *hwdef) +{ + SPARCCPU *cpu; + M48t59State *nvram; + unsigned int i; + uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; + PCIBus *pci_bus, *pci_bus2, *pci_bus3; + ISABus *isa_bus; + qemu_irq *ivec_irqs, *pbm_irqs; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + DriveInfo *fd[MAX_FD]; + void *fw_cfg; + + /* init CPUs */ + cpu = cpu_devinit(cpu_model, hwdef); + + /* set up devices */ + ram_init(0, RAM_size); + + prom_init(hwdef->prom_addr, bios_name); + + ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, + &pci_bus3, &pbm_irqs); + pci_vga_init(pci_bus); + + // XXX Should be pci_bus3 + isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs); + + i = 0; + if (hwdef->console_serial_base) { + serial_mm_init(address_space_mem, hwdef->console_serial_base, 0, + NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN); + i++; + } + for(; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_isa_init(isa_bus, i, serial_hds[i]); + } + } + + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_hds[i]) { + parallel_init(isa_bus, i, parallel_hds[i]); + } + } + + for(i = 0; i < nb_nics; i++) + pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); + + ide_drive_get(hd, MAX_IDE_BUS); + + pci_cmd646_ide_init(pci_bus, hd, 1); + + isa_create_simple(isa_bus, "i8042"); + for(i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); + } + fdctrl_init_isa(isa_bus, fd); + nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59); + + initrd_size = 0; + initrd_addr = 0; + kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename, + ram_size, &initrd_size, &initrd_addr, + &kernel_addr, &kernel_entry); + + sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices, + kernel_addr, kernel_size, + kernel_cmdline, + initrd_addr, initrd_size, + /* XXX: need an option to load a NVRAM image */ + 0, + graphic_width, graphic_height, graphic_depth, + (uint8_t *)&nd_table[0].macaddr); + + fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + if (kernel_cmdline) { + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, + strlen(kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); + } + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]); + + fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); + fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height); + fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH, graphic_depth); + + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); +} + +enum { + sun4u_id = 0, + sun4v_id = 64, + niagara_id, +}; + +static const struct hwdef hwdefs[] = { + /* Sun4u generic PC-like machine */ + { + .default_cpu_model = "TI UltraSparc IIi", + .machine_id = sun4u_id, + .prom_addr = 0x1fff0000000ULL, + .console_serial_base = 0, + }, + /* Sun4v generic PC-like machine */ + { + .default_cpu_model = "Sun UltraSparc T1", + .machine_id = sun4v_id, + .prom_addr = 0x1fff0000000ULL, + .console_serial_base = 0, + }, + /* Sun4v generic Niagara machine */ + { + .default_cpu_model = "Sun UltraSparc T1", + .machine_id = niagara_id, + .prom_addr = 0xfff0000000ULL, + .console_serial_base = 0xfff0c2c000ULL, + }, +}; + +/* Sun4u hardware initialisation */ +static void sun4u_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; + sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]); +} + +/* Sun4v hardware initialisation */ +static void sun4v_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; + sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]); +} + +/* Niagara hardware initialisation */ +static void niagara_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; + sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]); +} + +static QEMUMachine sun4u_machine = { + .name = "sun4u", + .desc = "Sun4u platform", + .init = sun4u_init, + .max_cpus = 1, // XXX for now + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine sun4v_machine = { + .name = "sun4v", + .desc = "Sun4v platform", + .init = sun4v_init, + .max_cpus = 1, // XXX for now + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine niagara_machine = { + .name = "Niagara", + .desc = "Sun4v platform, Niagara", + .init = niagara_init, + .max_cpus = 1, // XXX for now + DEFAULT_MACHINE_OPTIONS, +}; + +static void sun4u_register_types(void) +{ + type_register_static(&ebus_info); + type_register_static(&prom_info); + type_register_static(&ram_info); +} + +static void sun4u_machine_init(void) +{ + qemu_register_machine(&sun4u_machine); + qemu_register_machine(&sun4v_machine); + qemu_register_machine(&niagara_machine); +} + +type_init(sun4u_register_types) +machine_init(sun4u_machine_init); diff --git a/hw/spitz.c b/hw/spitz.c deleted file mode 100644 index f5832bea93..0000000000 --- a/hw/spitz.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* - * PXA270-based Clamshell PDA platforms. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "hw/hw.h" -#include "hw/pxa.h" -#include "hw/arm-misc.h" -#include "sysemu/sysemu.h" -#include "hw/pcmcia.h" -#include "hw/i2c.h" -#include "hw/ssi.h" -#include "hw/flash.h" -#include "qemu/timer.h" -#include "hw/devices.h" -#include "hw/sharpsl.h" -#include "ui/console.h" -#include "block/block.h" -#include "audio/audio.h" -#include "hw/boards.h" -#include "sysemu/blockdev.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -#undef REG_FMT -#define REG_FMT "0x%02lx" - -/* Spitz Flash */ -#define FLASH_BASE 0x0c000000 -#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */ -#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */ -#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */ -#define FLASH_ECCCNTR 0x0c /* ECC byte counter */ -#define FLASH_ECCCLRR 0x10 /* Clear ECC */ -#define FLASH_FLASHIO 0x14 /* Flash I/O */ -#define FLASH_FLASHCTL 0x18 /* Flash Control */ - -#define FLASHCTL_CE0 (1 << 0) -#define FLASHCTL_CLE (1 << 1) -#define FLASHCTL_ALE (1 << 2) -#define FLASHCTL_WP (1 << 3) -#define FLASHCTL_CE1 (1 << 4) -#define FLASHCTL_RYBY (1 << 5) -#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1) - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - DeviceState *nand; - uint8_t ctl; - uint8_t manf_id; - uint8_t chip_id; - ECCState ecc; -} SLNANDState; - -static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size) -{ - SLNANDState *s = (SLNANDState *) opaque; - int ryby; - - switch (addr) { -#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to)) - case FLASH_ECCLPLB: - return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) | - BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7); - -#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to)) - case FLASH_ECCLPUB: - return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) | - BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7); - - case FLASH_ECCCP: - return s->ecc.cp; - - case FLASH_ECCCNTR: - return s->ecc.count & 0xff; - - case FLASH_FLASHCTL: - nand_getpins(s->nand, &ryby); - if (ryby) - return s->ctl | FLASHCTL_RYBY; - else - return s->ctl; - - case FLASH_FLASHIO: - if (size == 4) { - return ecc_digest(&s->ecc, nand_getio(s->nand)) | - (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16); - } - return ecc_digest(&s->ecc, nand_getio(s->nand)); - - default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); - } - return 0; -} - -static void sl_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - SLNANDState *s = (SLNANDState *) opaque; - - switch (addr) { - case FLASH_ECCCLRR: - /* Value is ignored. */ - ecc_reset(&s->ecc); - break; - - case FLASH_FLASHCTL: - s->ctl = value & 0xff & ~FLASHCTL_RYBY; - nand_setpins(s->nand, - s->ctl & FLASHCTL_CLE, - s->ctl & FLASHCTL_ALE, - s->ctl & FLASHCTL_NCE, - s->ctl & FLASHCTL_WP, - 0); - break; - - case FLASH_FLASHIO: - nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff)); - break; - - default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); - } -} - -enum { - FLASH_128M, - FLASH_1024M, -}; - -static const MemoryRegionOps sl_ops = { - .read = sl_read, - .write = sl_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void sl_flash_register(PXA2xxState *cpu, int size) -{ - DeviceState *dev; - - dev = qdev_create(NULL, "sl-nand"); - - qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG); - if (size == FLASH_128M) - qdev_prop_set_uint8(dev, "chip_id", 0x73); - else if (size == FLASH_1024M) - qdev_prop_set_uint8(dev, "chip_id", 0xf1); - - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); -} - -static int sl_nand_init(SysBusDevice *dev) { - SLNANDState *s; - DriveInfo *nand; - - s = FROM_SYSBUS(SLNANDState, dev); - - s->ctl = 0; - nand = drive_get(IF_MTD, 0, 0); - s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id); - - memory_region_init_io(&s->iomem, &sl_ops, s, "sl", 0x40); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -/* Spitz Keyboard */ - -#define SPITZ_KEY_STROBE_NUM 11 -#define SPITZ_KEY_SENSE_NUM 7 - -static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = { - 12, 17, 91, 34, 36, 38, 39 -}; - -static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = { - 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114 -}; - -/* Eighth additional row maps the special keys */ -static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = { - { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 }, - { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 }, - { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 }, - { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 }, - { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 }, - { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 }, - { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 }, - { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 }, -}; - -#define SPITZ_GPIO_AK_INT 13 /* Remote control */ -#define SPITZ_GPIO_SYNC 16 /* Sync button */ -#define SPITZ_GPIO_ON_KEY 95 /* Power button */ -#define SPITZ_GPIO_SWA 97 /* Lid */ -#define SPITZ_GPIO_SWB 96 /* Tablet mode */ - -/* The special buttons are mapped to unused keys */ -static const int spitz_gpiomap[5] = { - SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY, - SPITZ_GPIO_SWA, SPITZ_GPIO_SWB, -}; - -typedef struct { - SysBusDevice busdev; - qemu_irq sense[SPITZ_KEY_SENSE_NUM]; - qemu_irq gpiomap[5]; - int keymap[0x80]; - uint16_t keyrow[SPITZ_KEY_SENSE_NUM]; - uint16_t strobe_state; - uint16_t sense_state; - - uint16_t pre_map[0x100]; - uint16_t modifiers; - uint16_t imodifiers; - uint8_t fifo[16]; - int fifopos, fifolen; - QEMUTimer *kbdtimer; -} SpitzKeyboardState; - -static void spitz_keyboard_sense_update(SpitzKeyboardState *s) -{ - int i; - uint16_t strobe, sense = 0; - for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) { - strobe = s->keyrow[i] & s->strobe_state; - if (strobe) { - sense |= 1 << i; - if (!(s->sense_state & (1 << i))) - qemu_irq_raise(s->sense[i]); - } else if (s->sense_state & (1 << i)) - qemu_irq_lower(s->sense[i]); - } - - s->sense_state = sense; -} - -static void spitz_keyboard_strobe(void *opaque, int line, int level) -{ - SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; - - if (level) - s->strobe_state |= 1 << line; - else - s->strobe_state &= ~(1 << line); - spitz_keyboard_sense_update(s); -} - -static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode) -{ - int spitz_keycode = s->keymap[keycode & 0x7f]; - if (spitz_keycode == -1) - return; - - /* Handle the additional keys */ - if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) { - qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80)); - return; - } - - if (keycode & 0x80) - s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf)); - else - s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf); - - spitz_keyboard_sense_update(s); -} - -#define SHIFT (1 << 7) -#define CTRL (1 << 8) -#define FN (1 << 9) - -#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c - -static void spitz_keyboard_handler(void *opaque, int keycode) -{ - SpitzKeyboardState *s = opaque; - uint16_t code; - int mapcode; - switch (keycode) { - case 0x2a: /* Left Shift */ - s->modifiers |= 1; - break; - case 0xaa: - s->modifiers &= ~1; - break; - case 0x36: /* Right Shift */ - s->modifiers |= 2; - break; - case 0xb6: - s->modifiers &= ~2; - break; - case 0x1d: /* Control */ - s->modifiers |= 4; - break; - case 0x9d: - s->modifiers &= ~4; - break; - case 0x38: /* Alt */ - s->modifiers |= 8; - break; - case 0xb8: - s->modifiers &= ~8; - break; - } - - code = s->pre_map[mapcode = ((s->modifiers & 3) ? - (keycode | SHIFT) : - (keycode & ~SHIFT))]; - - if (code != mapcode) { -#if 0 - if ((code & SHIFT) && !(s->modifiers & 1)) - QUEUE_KEY(0x2a | (keycode & 0x80)); - if ((code & CTRL ) && !(s->modifiers & 4)) - QUEUE_KEY(0x1d | (keycode & 0x80)); - if ((code & FN ) && !(s->modifiers & 8)) - QUEUE_KEY(0x38 | (keycode & 0x80)); - if ((code & FN ) && (s->modifiers & 1)) - QUEUE_KEY(0x2a | (~keycode & 0x80)); - if ((code & FN ) && (s->modifiers & 2)) - QUEUE_KEY(0x36 | (~keycode & 0x80)); -#else - if (keycode & 0x80) { - if ((s->imodifiers & 1 ) && !(s->modifiers & 1)) - QUEUE_KEY(0x2a | 0x80); - if ((s->imodifiers & 4 ) && !(s->modifiers & 4)) - QUEUE_KEY(0x1d | 0x80); - if ((s->imodifiers & 8 ) && !(s->modifiers & 8)) - QUEUE_KEY(0x38 | 0x80); - if ((s->imodifiers & 0x10) && (s->modifiers & 1)) - QUEUE_KEY(0x2a); - if ((s->imodifiers & 0x20) && (s->modifiers & 2)) - QUEUE_KEY(0x36); - s->imodifiers = 0; - } else { - if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) { - QUEUE_KEY(0x2a); - s->imodifiers |= 1; - } - if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) { - QUEUE_KEY(0x1d); - s->imodifiers |= 4; - } - if ((code & FN ) && !((s->modifiers | s->imodifiers) & 8)) { - QUEUE_KEY(0x38); - s->imodifiers |= 8; - } - if ((code & FN ) && (s->modifiers & 1) && - !(s->imodifiers & 0x10)) { - QUEUE_KEY(0x2a | 0x80); - s->imodifiers |= 0x10; - } - if ((code & FN ) && (s->modifiers & 2) && - !(s->imodifiers & 0x20)) { - QUEUE_KEY(0x36 | 0x80); - s->imodifiers |= 0x20; - } - } -#endif - } - - QUEUE_KEY((code & 0x7f) | (keycode & 0x80)); -} - -static void spitz_keyboard_tick(void *opaque) -{ - SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; - - if (s->fifolen) { - spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]); - s->fifolen --; - if (s->fifopos >= 16) - s->fifopos = 0; - } - - qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock) + - get_ticks_per_sec() / 32); -} - -static void spitz_keyboard_pre_map(SpitzKeyboardState *s) -{ - int i; - for (i = 0; i < 0x100; i ++) - s->pre_map[i] = i; - s->pre_map[0x02 | SHIFT ] = 0x02 | SHIFT; /* exclam */ - s->pre_map[0x28 | SHIFT ] = 0x03 | SHIFT; /* quotedbl */ - s->pre_map[0x04 | SHIFT ] = 0x04 | SHIFT; /* numbersign */ - s->pre_map[0x05 | SHIFT ] = 0x05 | SHIFT; /* dollar */ - s->pre_map[0x06 | SHIFT ] = 0x06 | SHIFT; /* percent */ - s->pre_map[0x08 | SHIFT ] = 0x07 | SHIFT; /* ampersand */ - s->pre_map[0x28 ] = 0x08 | SHIFT; /* apostrophe */ - s->pre_map[0x0a | SHIFT ] = 0x09 | SHIFT; /* parenleft */ - s->pre_map[0x0b | SHIFT ] = 0x0a | SHIFT; /* parenright */ - s->pre_map[0x29 | SHIFT ] = 0x0b | SHIFT; /* asciitilde */ - s->pre_map[0x03 | SHIFT ] = 0x0c | SHIFT; /* at */ - s->pre_map[0xd3 ] = 0x0e | FN; /* Delete */ - s->pre_map[0x3a ] = 0x0f | FN; /* Caps_Lock */ - s->pre_map[0x07 | SHIFT ] = 0x11 | FN; /* asciicircum */ - s->pre_map[0x0d ] = 0x12 | FN; /* equal */ - s->pre_map[0x0d | SHIFT ] = 0x13 | FN; /* plus */ - s->pre_map[0x1a ] = 0x14 | FN; /* bracketleft */ - s->pre_map[0x1b ] = 0x15 | FN; /* bracketright */ - s->pre_map[0x1a | SHIFT ] = 0x16 | FN; /* braceleft */ - s->pre_map[0x1b | SHIFT ] = 0x17 | FN; /* braceright */ - s->pre_map[0x27 ] = 0x22 | FN; /* semicolon */ - s->pre_map[0x27 | SHIFT ] = 0x23 | FN; /* colon */ - s->pre_map[0x09 | SHIFT ] = 0x24 | FN; /* asterisk */ - s->pre_map[0x2b ] = 0x25 | FN; /* backslash */ - s->pre_map[0x2b | SHIFT ] = 0x26 | FN; /* bar */ - s->pre_map[0x0c | SHIFT ] = 0x30 | FN; /* underscore */ - s->pre_map[0x33 | SHIFT ] = 0x33 | FN; /* less */ - s->pre_map[0x35 ] = 0x33 | SHIFT; /* slash */ - s->pre_map[0x34 | SHIFT ] = 0x34 | FN; /* greater */ - s->pre_map[0x35 | SHIFT ] = 0x34 | SHIFT; /* question */ - s->pre_map[0x49 ] = 0x48 | FN; /* Page_Up */ - s->pre_map[0x51 ] = 0x50 | FN; /* Page_Down */ - - s->modifiers = 0; - s->imodifiers = 0; - s->fifopos = 0; - s->fifolen = 0; -} - -#undef SHIFT -#undef CTRL -#undef FN - -static int spitz_keyboard_post_load(void *opaque, int version_id) -{ - SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; - - /* Release all pressed keys */ - memset(s->keyrow, 0, sizeof(s->keyrow)); - spitz_keyboard_sense_update(s); - s->modifiers = 0; - s->imodifiers = 0; - s->fifopos = 0; - s->fifolen = 0; - - return 0; -} - -static void spitz_keyboard_register(PXA2xxState *cpu) -{ - int i; - DeviceState *dev; - SpitzKeyboardState *s; - - dev = sysbus_create_simple("spitz-keyboard", -1, NULL); - s = FROM_SYSBUS(SpitzKeyboardState, SYS_BUS_DEVICE(dev)); - - for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) - qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i])); - - for (i = 0; i < 5; i ++) - s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]); - - if (!graphic_rotate) - s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]); - - for (i = 0; i < 5; i++) - qemu_set_irq(s->gpiomap[i], 0); - - for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++) - qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i], - qdev_get_gpio_in(dev, i)); - - qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock)); - - qemu_add_kbd_event_handler(spitz_keyboard_handler, s); -} - -static int spitz_keyboard_init(SysBusDevice *dev) -{ - SpitzKeyboardState *s; - int i, j; - - s = FROM_SYSBUS(SpitzKeyboardState, dev); - - for (i = 0; i < 0x80; i ++) - s->keymap[i] = -1; - for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++) - for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++) - if (spitz_keymap[i][j] != -1) - s->keymap[spitz_keymap[i][j]] = (i << 4) | j; - - spitz_keyboard_pre_map(s); - - s->kbdtimer = qemu_new_timer_ns(vm_clock, spitz_keyboard_tick, s); - qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM); - qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM); - - return 0; -} - -/* LCD backlight controller */ - -#define LCDTG_RESCTL 0x00 -#define LCDTG_PHACTRL 0x01 -#define LCDTG_DUTYCTRL 0x02 -#define LCDTG_POWERREG0 0x03 -#define LCDTG_POWERREG1 0x04 -#define LCDTG_GPOR3 0x05 -#define LCDTG_PICTRL 0x06 -#define LCDTG_POLCTRL 0x07 - -typedef struct { - SSISlave ssidev; - uint32_t bl_intensity; - uint32_t bl_power; -} SpitzLCDTG; - -static void spitz_bl_update(SpitzLCDTG *s) -{ - if (s->bl_power && s->bl_intensity) - zaurus_printf("LCD Backlight now at %i/63\n", s->bl_intensity); - else - zaurus_printf("LCD Backlight now off\n"); -} - -/* FIXME: Implement GPIO properly and remove this hack. */ -static SpitzLCDTG *spitz_lcdtg; - -static inline void spitz_bl_bit5(void *opaque, int line, int level) -{ - SpitzLCDTG *s = spitz_lcdtg; - int prev = s->bl_intensity; - - if (level) - s->bl_intensity &= ~0x20; - else - s->bl_intensity |= 0x20; - - if (s->bl_power && prev != s->bl_intensity) - spitz_bl_update(s); -} - -static inline void spitz_bl_power(void *opaque, int line, int level) -{ - SpitzLCDTG *s = spitz_lcdtg; - s->bl_power = !!level; - spitz_bl_update(s); -} - -static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value) -{ - SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); - int addr; - addr = value >> 5; - value &= 0x1f; - - switch (addr) { - case LCDTG_RESCTL: - if (value) - zaurus_printf("LCD in QVGA mode\n"); - else - zaurus_printf("LCD in VGA mode\n"); - break; - - case LCDTG_DUTYCTRL: - s->bl_intensity &= ~0x1f; - s->bl_intensity |= value; - if (s->bl_power) - spitz_bl_update(s); - break; - - case LCDTG_POWERREG0: - /* Set common voltage to M62332FP */ - break; - } - return 0; -} - -static int spitz_lcdtg_init(SSISlave *dev) -{ - SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); - - spitz_lcdtg = s; - s->bl_power = 0; - s->bl_intensity = 0x20; - - return 0; -} - -/* SSP devices */ - -#define CORGI_SSP_PORT 2 - -#define SPITZ_GPIO_LCDCON_CS 53 -#define SPITZ_GPIO_ADS7846_CS 14 -#define SPITZ_GPIO_MAX1111_CS 20 -#define SPITZ_GPIO_TP_INT 11 - -static DeviceState *max1111; - -/* "Demux" the signal based on current chipselect */ -typedef struct { - SSISlave ssidev; - SSIBus *bus[3]; - uint32_t enable[3]; -} CorgiSSPState; - -static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value) -{ - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); - int i; - - for (i = 0; i < 3; i++) { - if (s->enable[i]) { - return ssi_transfer(s->bus[i], value); - } - } - return 0; -} - -static void corgi_ssp_gpio_cs(void *opaque, int line, int level) -{ - CorgiSSPState *s = (CorgiSSPState *)opaque; - assert(line >= 0 && line < 3); - s->enable[line] = !level; -} - -#define MAX1111_BATT_VOLT 1 -#define MAX1111_BATT_TEMP 2 -#define MAX1111_ACIN_VOLT 3 - -#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */ -#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ -#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ - -static void spitz_adc_temp_on(void *opaque, int line, int level) -{ - if (!max1111) - return; - - if (level) - max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP); - else - max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); -} - -static int corgi_ssp_init(SSISlave *dev) -{ - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); - - qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3); - s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); - s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); - s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2"); - - return 0; -} - -static void spitz_ssp_attach(PXA2xxState *cpu) -{ - DeviceState *mux; - DeviceState *dev; - void *bus; - - mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp"); - - bus = qdev_get_child_bus(mux, "ssi0"); - ssi_create_slave(bus, "spitz-lcdtg"); - - bus = qdev_get_child_bus(mux, "ssi1"); - dev = ssi_create_slave(bus, "ads7846"); - qdev_connect_gpio_out(dev, 0, - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT)); - - bus = qdev_get_child_bus(mux, "ssi2"); - max1111 = ssi_create_slave(bus, "max1111"); - max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); - max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); - max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN); - - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS, - qdev_get_gpio_in(mux, 0)); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS, - qdev_get_gpio_in(mux, 1)); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS, - qdev_get_gpio_in(mux, 2)); -} - -/* CF Microdrive */ - -static void spitz_microdrive_attach(PXA2xxState *cpu, int slot) -{ - PCMCIACardState *md; - DriveInfo *dinfo; - - dinfo = drive_get(IF_IDE, 0, 0); - if (!dinfo || dinfo->media_cd) - return; - md = dscm1xxxx_init(dinfo); - pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md); -} - -/* Wm8750 and Max7310 on I2C */ - -#define AKITA_MAX_ADDR 0x18 -#define SPITZ_WM_ADDRL 0x1b -#define SPITZ_WM_ADDRH 0x1a - -#define SPITZ_GPIO_WM 5 - -static void spitz_wm8750_addr(void *opaque, int line, int level) -{ - I2CSlave *wm = (I2CSlave *) opaque; - if (level) - i2c_set_slave_address(wm, SPITZ_WM_ADDRH); - else - i2c_set_slave_address(wm, SPITZ_WM_ADDRL); -} - -static void spitz_i2c_setup(PXA2xxState *cpu) -{ - /* Attach the CPU on one end of our I2C bus. */ - i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); - - DeviceState *wm; - - /* Attach a WM8750 to the bus */ - wm = i2c_create_slave(bus, "wm8750", 0); - - spitz_wm8750_addr(wm, 0, 0); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM, - qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]); - /* .. and to the sound interface. */ - cpu->i2s->opaque = wm; - cpu->i2s->codec_out = wm8750_dac_dat; - cpu->i2s->codec_in = wm8750_adc_dat; - wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s); -} - -static void spitz_akita_i2c_setup(PXA2xxState *cpu) -{ - /* Attach a Max7310 to Akita I2C bus. */ - i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310", - AKITA_MAX_ADDR); -} - -/* Other peripherals */ - -static void spitz_out_switch(void *opaque, int line, int level) -{ - switch (line) { - case 0: - zaurus_printf("Charging %s.\n", level ? "off" : "on"); - break; - case 1: - zaurus_printf("Discharging %s.\n", level ? "on" : "off"); - break; - case 2: - zaurus_printf("Green LED %s.\n", level ? "on" : "off"); - break; - case 3: - zaurus_printf("Orange LED %s.\n", level ? "on" : "off"); - break; - case 4: - spitz_bl_bit5(opaque, line, level); - break; - case 5: - spitz_bl_power(opaque, line, level); - break; - case 6: - spitz_adc_temp_on(opaque, line, level); - break; - } -} - -#define SPITZ_SCP_LED_GREEN 1 -#define SPITZ_SCP_JK_B 2 -#define SPITZ_SCP_CHRG_ON 3 -#define SPITZ_SCP_MUTE_L 4 -#define SPITZ_SCP_MUTE_R 5 -#define SPITZ_SCP_CF_POWER 6 -#define SPITZ_SCP_LED_ORANGE 7 -#define SPITZ_SCP_JK_A 8 -#define SPITZ_SCP_ADC_TEMP_ON 9 -#define SPITZ_SCP2_IR_ON 1 -#define SPITZ_SCP2_AKIN_PULLUP 2 -#define SPITZ_SCP2_BACKLIGHT_CONT 7 -#define SPITZ_SCP2_BACKLIGHT_ON 8 -#define SPITZ_SCP2_MIC_BIAS 9 - -static void spitz_scoop_gpio_setup(PXA2xxState *cpu, - DeviceState *scp0, DeviceState *scp1) -{ - qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8); - - qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]); - - if (scp1) { - qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]); - qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]); - } - - qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); -} - -#define SPITZ_GPIO_HSYNC 22 -#define SPITZ_GPIO_SD_DETECT 9 -#define SPITZ_GPIO_SD_WP 81 -#define SPITZ_GPIO_ON_RESET 89 -#define SPITZ_GPIO_BAT_COVER 90 -#define SPITZ_GPIO_CF1_IRQ 105 -#define SPITZ_GPIO_CF1_CD 94 -#define SPITZ_GPIO_CF2_IRQ 106 -#define SPITZ_GPIO_CF2_CD 93 - -static int spitz_hsync; - -static void spitz_lcd_hsync_handler(void *opaque, int line, int level) -{ - PXA2xxState *cpu = (PXA2xxState *) opaque; - qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync); - spitz_hsync ^= 1; -} - -static void spitz_gpio_setup(PXA2xxState *cpu, int slots) -{ - qemu_irq lcd_hsync; - /* - * Bad hack: We toggle the LCD hsync GPIO on every GPIO status - * read to satisfy broken guests that poll-wait for hsync. - * Simulating a real hsync event would be less practical and - * wouldn't guarantee that a guest ever exits the loop. - */ - spitz_hsync = 0; - lcd_hsync = qemu_allocate_irqs(spitz_lcd_hsync_handler, cpu, 1)[0]; - pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync); - pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync); - - /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP), - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT)); - - /* Battery lock always closed */ - qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER)); - - /* Handle reset */ - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset); - - /* PCMCIA signals: card's IRQ and Card-Detect */ - if (slots >= 1) - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ), - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD)); - if (slots >= 2) - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ), - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD)); -} - -/* Board init. */ -enum spitz_model_e { spitz, akita, borzoi, terrier }; - -#define SPITZ_RAM 0x04000000 -#define SPITZ_ROM 0x00800000 - -static struct arm_boot_info spitz_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = 0x04000000, -}; - -static void spitz_common_init(QEMUMachineInitArgs *args, - enum spitz_model_e model, int arm_id) -{ - PXA2xxState *mpu; - DeviceState *scp0, *scp1 = NULL; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *rom = g_new(MemoryRegion, 1); - const char *cpu_model = args->cpu_model; - - if (!cpu_model) - cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; - - /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model); - - sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); - - memory_region_init_ram(rom, "spitz.rom", SPITZ_ROM); - vmstate_register_ram_global(rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(address_space_mem, 0, rom); - - /* Setup peripherals */ - spitz_keyboard_register(mpu); - - spitz_ssp_attach(mpu); - - scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); - if (model != akita) { - scp1 = sysbus_create_simple("scoop", 0x08800040, NULL); - } - - spitz_scoop_gpio_setup(mpu, scp0, scp1); - - spitz_gpio_setup(mpu, (model == akita) ? 1 : 2); - - spitz_i2c_setup(mpu); - - if (model == akita) - spitz_akita_i2c_setup(mpu); - - if (model == terrier) - /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */ - spitz_microdrive_attach(mpu, 1); - else if (model != akita) - /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ - spitz_microdrive_attach(mpu, 0); - - spitz_binfo.kernel_filename = args->kernel_filename; - spitz_binfo.kernel_cmdline = args->kernel_cmdline; - spitz_binfo.initrd_filename = args->initrd_filename; - spitz_binfo.board_id = arm_id; - arm_load_kernel(mpu->cpu, &spitz_binfo); - sl_bootparam_write(SL_PXA_PARAM_BASE); -} - -static void spitz_init(QEMUMachineInitArgs *args) -{ - spitz_common_init(args, spitz, 0x2c9); -} - -static void borzoi_init(QEMUMachineInitArgs *args) -{ - spitz_common_init(args, borzoi, 0x33f); -} - -static void akita_init(QEMUMachineInitArgs *args) -{ - spitz_common_init(args, akita, 0x2e8); -} - -static void terrier_init(QEMUMachineInitArgs *args) -{ - spitz_common_init(args, terrier, 0x33f); -} - -static QEMUMachine akitapda_machine = { - .name = "akita", - .desc = "Akita PDA (PXA270)", - .init = akita_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine spitzpda_machine = { - .name = "spitz", - .desc = "Spitz PDA (PXA270)", - .init = spitz_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine borzoipda_machine = { - .name = "borzoi", - .desc = "Borzoi PDA (PXA270)", - .init = borzoi_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine terrierpda_machine = { - .name = "terrier", - .desc = "Terrier PDA (PXA270)", - .init = terrier_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void spitz_machine_init(void) -{ - qemu_register_machine(&akitapda_machine); - qemu_register_machine(&spitzpda_machine); - qemu_register_machine(&borzoipda_machine); - qemu_register_machine(&terrierpda_machine); -} - -machine_init(spitz_machine_init); - -static bool is_version_0(void *opaque, int version_id) -{ - return version_id == 0; -} - -static VMStateDescription vmstate_sl_nand_info = { - .name = "sl-nand", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { - VMSTATE_UINT8(ctl, SLNANDState), - VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState), - VMSTATE_END_OF_LIST(), - }, -}; - -static Property sl_nand_properties[] = { - DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG), - DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sl_nand_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = sl_nand_init; - dc->vmsd = &vmstate_sl_nand_info; - dc->props = sl_nand_properties; -} - -static const TypeInfo sl_nand_info = { - .name = "sl-nand", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SLNANDState), - .class_init = sl_nand_class_init, -}; - -static VMStateDescription vmstate_spitz_kbd = { - .name = "spitz-keyboard", - .version_id = 1, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .post_load = spitz_keyboard_post_load, - .fields = (VMStateField []) { - VMSTATE_UINT16(sense_state, SpitzKeyboardState), - VMSTATE_UINT16(strobe_state, SpitzKeyboardState), - VMSTATE_UNUSED_TEST(is_version_0, 5), - VMSTATE_END_OF_LIST(), - }, -}; - -static Property spitz_keyboard_properties[] = { - DEFINE_PROP_END_OF_LIST(), -}; - -static void spitz_keyboard_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = spitz_keyboard_init; - dc->vmsd = &vmstate_spitz_kbd; - dc->props = spitz_keyboard_properties; -} - -static const TypeInfo spitz_keyboard_info = { - .name = "spitz-keyboard", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SpitzKeyboardState), - .class_init = spitz_keyboard_class_init, -}; - -static const VMStateDescription vmstate_corgi_ssp_regs = { - .name = "corgi-ssp", - .version_id = 2, - .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { - VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), - VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), - VMSTATE_END_OF_LIST(), - } -}; - -static void corgi_ssp_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = corgi_ssp_init; - k->transfer = corgi_ssp_transfer; - dc->vmsd = &vmstate_corgi_ssp_regs; -} - -static const TypeInfo corgi_ssp_info = { - .name = "corgi-ssp", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(CorgiSSPState), - .class_init = corgi_ssp_class_init, -}; - -static const VMStateDescription vmstate_spitz_lcdtg_regs = { - .name = "spitz-lcdtg", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), - VMSTATE_UINT32(bl_intensity, SpitzLCDTG), - VMSTATE_UINT32(bl_power, SpitzLCDTG), - VMSTATE_END_OF_LIST(), - } -}; - -static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = spitz_lcdtg_init; - k->transfer = spitz_lcdtg_transfer; - dc->vmsd = &vmstate_spitz_lcdtg_regs; -} - -static const TypeInfo spitz_lcdtg_info = { - .name = "spitz-lcdtg", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(SpitzLCDTG), - .class_init = spitz_lcdtg_class_init, -}; - -static void spitz_register_types(void) -{ - type_register_static(&corgi_ssp_info); - type_register_static(&spitz_lcdtg_info); - type_register_static(&spitz_keyboard_info); - type_register_static(&sl_nand_info); -} - -type_init(spitz_register_types) diff --git a/hw/stellaris.c b/hw/stellaris.c deleted file mode 100644 index f4ce7945f3..0000000000 --- a/hw/stellaris.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* - * Luminary Micro Stellaris peripherals - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "hw/sysbus.h" -#include "hw/ssi.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "qemu/timer.h" -#include "hw/i2c.h" -#include "net/net.h" -#include "hw/boards.h" -#include "exec/address-spaces.h" - -#define GPIO_A 0 -#define GPIO_B 1 -#define GPIO_C 2 -#define GPIO_D 3 -#define GPIO_E 4 -#define GPIO_F 5 -#define GPIO_G 6 - -#define BP_OLED_I2C 0x01 -#define BP_OLED_SSI 0x02 -#define BP_GAMEPAD 0x04 - -typedef const struct { - const char *name; - uint32_t did0; - uint32_t did1; - uint32_t dc0; - uint32_t dc1; - uint32_t dc2; - uint32_t dc3; - uint32_t dc4; - uint32_t peripherals; -} stellaris_board_info; - -/* General purpose timer module. */ - -typedef struct gptm_state { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t config; - uint32_t mode[2]; - uint32_t control; - uint32_t state; - uint32_t mask; - uint32_t load[2]; - uint32_t match[2]; - uint32_t prescale[2]; - uint32_t match_prescale[2]; - uint32_t rtc; - int64_t tick[2]; - struct gptm_state *opaque[2]; - QEMUTimer *timer[2]; - /* The timers have an alternate output used to trigger the ADC. */ - qemu_irq trigger; - qemu_irq irq; -} gptm_state; - -static void gptm_update_irq(gptm_state *s) -{ - int level; - level = (s->state & s->mask) != 0; - qemu_set_irq(s->irq, level); -} - -static void gptm_stop(gptm_state *s, int n) -{ - qemu_del_timer(s->timer[n]); -} - -static void gptm_reload(gptm_state *s, int n, int reset) -{ - int64_t tick; - if (reset) - tick = qemu_get_clock_ns(vm_clock); - else - tick = s->tick[n]; - - if (s->config == 0) { - /* 32-bit CountDown. */ - uint32_t count; - count = s->load[0] | (s->load[1] << 16); - tick += (int64_t)count * system_clock_scale; - } else if (s->config == 1) { - /* 32-bit RTC. 1Hz tick. */ - tick += get_ticks_per_sec(); - } else if (s->mode[n] == 0xa) { - /* PWM mode. Not implemented. */ - } else { - hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); - } - s->tick[n] = tick; - qemu_mod_timer(s->timer[n], tick); -} - -static void gptm_tick(void *opaque) -{ - gptm_state **p = (gptm_state **)opaque; - gptm_state *s; - int n; - - s = *p; - n = p - s->opaque; - if (s->config == 0) { - s->state |= 1; - if ((s->control & 0x20)) { - /* Output trigger. */ - qemu_irq_pulse(s->trigger); - } - if (s->mode[0] & 1) { - /* One-shot. */ - s->control &= ~1; - } else { - /* Periodic. */ - gptm_reload(s, 0, 0); - } - } else if (s->config == 1) { - /* RTC. */ - uint32_t match; - s->rtc++; - match = s->match[0] | (s->match[1] << 16); - if (s->rtc > match) - s->rtc = 0; - if (s->rtc == 0) { - s->state |= 8; - } - gptm_reload(s, 0, 0); - } else if (s->mode[n] == 0xa) { - /* PWM mode. Not implemented. */ - } else { - hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); - } - gptm_update_irq(s); -} - -static uint64_t gptm_read(void *opaque, hwaddr offset, - unsigned size) -{ - gptm_state *s = (gptm_state *)opaque; - - switch (offset) { - case 0x00: /* CFG */ - return s->config; - case 0x04: /* TAMR */ - return s->mode[0]; - case 0x08: /* TBMR */ - return s->mode[1]; - case 0x0c: /* CTL */ - return s->control; - case 0x18: /* IMR */ - return s->mask; - case 0x1c: /* RIS */ - return s->state; - case 0x20: /* MIS */ - return s->state & s->mask; - case 0x24: /* CR */ - return 0; - case 0x28: /* TAILR */ - return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0); - case 0x2c: /* TBILR */ - return s->load[1]; - case 0x30: /* TAMARCHR */ - return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0); - case 0x34: /* TBMATCHR */ - return s->match[1]; - case 0x38: /* TAPR */ - return s->prescale[0]; - case 0x3c: /* TBPR */ - return s->prescale[1]; - case 0x40: /* TAPMR */ - return s->match_prescale[0]; - case 0x44: /* TBPMR */ - return s->match_prescale[1]; - case 0x48: /* TAR */ - if (s->control == 1) - return s->rtc; - case 0x4c: /* TBR */ - hw_error("TODO: Timer value read\n"); - default: - hw_error("gptm_read: Bad offset 0x%x\n", (int)offset); - return 0; - } -} - -static void gptm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - gptm_state *s = (gptm_state *)opaque; - uint32_t oldval; - - /* The timers should be disabled before changing the configuration. - We take advantage of this and defer everything until the timer - is enabled. */ - switch (offset) { - case 0x00: /* CFG */ - s->config = value; - break; - case 0x04: /* TAMR */ - s->mode[0] = value; - break; - case 0x08: /* TBMR */ - s->mode[1] = value; - break; - case 0x0c: /* CTL */ - oldval = s->control; - s->control = value; - /* TODO: Implement pause. */ - if ((oldval ^ value) & 1) { - if (value & 1) { - gptm_reload(s, 0, 1); - } else { - gptm_stop(s, 0); - } - } - if (((oldval ^ value) & 0x100) && s->config >= 4) { - if (value & 0x100) { - gptm_reload(s, 1, 1); - } else { - gptm_stop(s, 1); - } - } - break; - case 0x18: /* IMR */ - s->mask = value & 0x77; - gptm_update_irq(s); - break; - case 0x24: /* CR */ - s->state &= ~value; - break; - case 0x28: /* TAILR */ - s->load[0] = value & 0xffff; - if (s->config < 4) { - s->load[1] = value >> 16; - } - break; - case 0x2c: /* TBILR */ - s->load[1] = value & 0xffff; - break; - case 0x30: /* TAMARCHR */ - s->match[0] = value & 0xffff; - if (s->config < 4) { - s->match[1] = value >> 16; - } - break; - case 0x34: /* TBMATCHR */ - s->match[1] = value >> 16; - break; - case 0x38: /* TAPR */ - s->prescale[0] = value; - break; - case 0x3c: /* TBPR */ - s->prescale[1] = value; - break; - case 0x40: /* TAPMR */ - s->match_prescale[0] = value; - break; - case 0x44: /* TBPMR */ - s->match_prescale[0] = value; - break; - default: - hw_error("gptm_write: Bad offset 0x%x\n", (int)offset); - } - gptm_update_irq(s); -} - -static const MemoryRegionOps gptm_ops = { - .read = gptm_read, - .write = gptm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_stellaris_gptm = { - .name = "stellaris_gptm", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(config, gptm_state), - VMSTATE_UINT32_ARRAY(mode, gptm_state, 2), - VMSTATE_UINT32(control, gptm_state), - VMSTATE_UINT32(state, gptm_state), - VMSTATE_UINT32(mask, gptm_state), - VMSTATE_UNUSED(8), - VMSTATE_UINT32_ARRAY(load, gptm_state, 2), - VMSTATE_UINT32_ARRAY(match, gptm_state, 2), - VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2), - VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2), - VMSTATE_UINT32(rtc, gptm_state), - VMSTATE_INT64_ARRAY(tick, gptm_state, 2), - VMSTATE_TIMER_ARRAY(timer, gptm_state, 2), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_gptm_init(SysBusDevice *dev) -{ - gptm_state *s = FROM_SYSBUS(gptm_state, dev); - - sysbus_init_irq(dev, &s->irq); - qdev_init_gpio_out(&dev->qdev, &s->trigger, 1); - - memory_region_init_io(&s->iomem, &gptm_ops, s, - "gptm", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - - s->opaque[0] = s->opaque[1] = s; - s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]); - s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]); - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s); - return 0; -} - - -/* System controller. */ - -typedef struct { - MemoryRegion iomem; - uint32_t pborctl; - uint32_t ldopctl; - uint32_t int_status; - uint32_t int_mask; - uint32_t resc; - uint32_t rcc; - uint32_t rcc2; - uint32_t rcgc[3]; - uint32_t scgc[3]; - uint32_t dcgc[3]; - uint32_t clkvclr; - uint32_t ldoarst; - uint32_t user0; - uint32_t user1; - qemu_irq irq; - stellaris_board_info *board; -} ssys_state; - -static void ssys_update(ssys_state *s) -{ - qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0); -} - -static uint32_t pllcfg_sandstorm[16] = { - 0x31c0, /* 1 Mhz */ - 0x1ae0, /* 1.8432 Mhz */ - 0x18c0, /* 2 Mhz */ - 0xd573, /* 2.4576 Mhz */ - 0x37a6, /* 3.57954 Mhz */ - 0x1ae2, /* 3.6864 Mhz */ - 0x0c40, /* 4 Mhz */ - 0x98bc, /* 4.906 Mhz */ - 0x935b, /* 4.9152 Mhz */ - 0x09c0, /* 5 Mhz */ - 0x4dee, /* 5.12 Mhz */ - 0x0c41, /* 6 Mhz */ - 0x75db, /* 6.144 Mhz */ - 0x1ae6, /* 7.3728 Mhz */ - 0x0600, /* 8 Mhz */ - 0x585b /* 8.192 Mhz */ -}; - -static uint32_t pllcfg_fury[16] = { - 0x3200, /* 1 Mhz */ - 0x1b20, /* 1.8432 Mhz */ - 0x1900, /* 2 Mhz */ - 0xf42b, /* 2.4576 Mhz */ - 0x37e3, /* 3.57954 Mhz */ - 0x1b21, /* 3.6864 Mhz */ - 0x0c80, /* 4 Mhz */ - 0x98ee, /* 4.906 Mhz */ - 0xd5b4, /* 4.9152 Mhz */ - 0x0a00, /* 5 Mhz */ - 0x4e27, /* 5.12 Mhz */ - 0x1902, /* 6 Mhz */ - 0xec1c, /* 6.144 Mhz */ - 0x1b23, /* 7.3728 Mhz */ - 0x0640, /* 8 Mhz */ - 0xb11c /* 8.192 Mhz */ -}; - -#define DID0_VER_MASK 0x70000000 -#define DID0_VER_0 0x00000000 -#define DID0_VER_1 0x10000000 - -#define DID0_CLASS_MASK 0x00FF0000 -#define DID0_CLASS_SANDSTORM 0x00000000 -#define DID0_CLASS_FURY 0x00010000 - -static int ssys_board_class(const ssys_state *s) -{ - uint32_t did0 = s->board->did0; - switch (did0 & DID0_VER_MASK) { - case DID0_VER_0: - return DID0_CLASS_SANDSTORM; - case DID0_VER_1: - switch (did0 & DID0_CLASS_MASK) { - case DID0_CLASS_SANDSTORM: - case DID0_CLASS_FURY: - return did0 & DID0_CLASS_MASK; - } - /* for unknown classes, fall through */ - default: - hw_error("ssys_board_class: Unknown class 0x%08x\n", did0); - } -} - -static uint64_t ssys_read(void *opaque, hwaddr offset, - unsigned size) -{ - ssys_state *s = (ssys_state *)opaque; - - switch (offset) { - case 0x000: /* DID0 */ - return s->board->did0; - case 0x004: /* DID1 */ - return s->board->did1; - case 0x008: /* DC0 */ - return s->board->dc0; - case 0x010: /* DC1 */ - return s->board->dc1; - case 0x014: /* DC2 */ - return s->board->dc2; - case 0x018: /* DC3 */ - return s->board->dc3; - case 0x01c: /* DC4 */ - return s->board->dc4; - case 0x030: /* PBORCTL */ - return s->pborctl; - case 0x034: /* LDOPCTL */ - return s->ldopctl; - case 0x040: /* SRCR0 */ - return 0; - case 0x044: /* SRCR1 */ - return 0; - case 0x048: /* SRCR2 */ - return 0; - case 0x050: /* RIS */ - return s->int_status; - case 0x054: /* IMC */ - return s->int_mask; - case 0x058: /* MISC */ - return s->int_status & s->int_mask; - case 0x05c: /* RESC */ - return s->resc; - case 0x060: /* RCC */ - return s->rcc; - case 0x064: /* PLLCFG */ - { - int xtal; - xtal = (s->rcc >> 6) & 0xf; - switch (ssys_board_class(s)) { - case DID0_CLASS_FURY: - return pllcfg_fury[xtal]; - case DID0_CLASS_SANDSTORM: - return pllcfg_sandstorm[xtal]; - default: - hw_error("ssys_read: Unhandled class for PLLCFG read.\n"); - return 0; - } - } - case 0x070: /* RCC2 */ - return s->rcc2; - case 0x100: /* RCGC0 */ - return s->rcgc[0]; - case 0x104: /* RCGC1 */ - return s->rcgc[1]; - case 0x108: /* RCGC2 */ - return s->rcgc[2]; - case 0x110: /* SCGC0 */ - return s->scgc[0]; - case 0x114: /* SCGC1 */ - return s->scgc[1]; - case 0x118: /* SCGC2 */ - return s->scgc[2]; - case 0x120: /* DCGC0 */ - return s->dcgc[0]; - case 0x124: /* DCGC1 */ - return s->dcgc[1]; - case 0x128: /* DCGC2 */ - return s->dcgc[2]; - case 0x150: /* CLKVCLR */ - return s->clkvclr; - case 0x160: /* LDOARST */ - return s->ldoarst; - case 0x1e0: /* USER0 */ - return s->user0; - case 0x1e4: /* USER1 */ - return s->user1; - default: - hw_error("ssys_read: Bad offset 0x%x\n", (int)offset); - return 0; - } -} - -static bool ssys_use_rcc2(ssys_state *s) -{ - return (s->rcc2 >> 31) & 0x1; -} - -/* - * Caculate the sys. clock period in ms. - */ -static void ssys_calculate_system_clock(ssys_state *s) -{ - if (ssys_use_rcc2(s)) { - system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1); - } else { - system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); - } -} - -static void ssys_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - ssys_state *s = (ssys_state *)opaque; - - switch (offset) { - case 0x030: /* PBORCTL */ - s->pborctl = value & 0xffff; - break; - case 0x034: /* LDOPCTL */ - s->ldopctl = value & 0x1f; - break; - case 0x040: /* SRCR0 */ - case 0x044: /* SRCR1 */ - case 0x048: /* SRCR2 */ - fprintf(stderr, "Peripheral reset not implemented\n"); - break; - case 0x054: /* IMC */ - s->int_mask = value & 0x7f; - break; - case 0x058: /* MISC */ - s->int_status &= ~value; - break; - case 0x05c: /* RESC */ - s->resc = value & 0x3f; - break; - case 0x060: /* RCC */ - if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { - /* PLL enable. */ - s->int_status |= (1 << 6); - } - s->rcc = value; - ssys_calculate_system_clock(s); - break; - case 0x070: /* RCC2 */ - if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) { - break; - } - - if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { - /* PLL enable. */ - s->int_status |= (1 << 6); - } - s->rcc2 = value; - ssys_calculate_system_clock(s); - break; - case 0x100: /* RCGC0 */ - s->rcgc[0] = value; - break; - case 0x104: /* RCGC1 */ - s->rcgc[1] = value; - break; - case 0x108: /* RCGC2 */ - s->rcgc[2] = value; - break; - case 0x110: /* SCGC0 */ - s->scgc[0] = value; - break; - case 0x114: /* SCGC1 */ - s->scgc[1] = value; - break; - case 0x118: /* SCGC2 */ - s->scgc[2] = value; - break; - case 0x120: /* DCGC0 */ - s->dcgc[0] = value; - break; - case 0x124: /* DCGC1 */ - s->dcgc[1] = value; - break; - case 0x128: /* DCGC2 */ - s->dcgc[2] = value; - break; - case 0x150: /* CLKVCLR */ - s->clkvclr = value; - break; - case 0x160: /* LDOARST */ - s->ldoarst = value; - break; - default: - hw_error("ssys_write: Bad offset 0x%x\n", (int)offset); - } - ssys_update(s); -} - -static const MemoryRegionOps ssys_ops = { - .read = ssys_read, - .write = ssys_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ssys_reset(void *opaque) -{ - ssys_state *s = (ssys_state *)opaque; - - s->pborctl = 0x7ffd; - s->rcc = 0x078e3ac0; - - if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) { - s->rcc2 = 0; - } else { - s->rcc2 = 0x07802810; - } - s->rcgc[0] = 1; - s->scgc[0] = 1; - s->dcgc[0] = 1; - ssys_calculate_system_clock(s); -} - -static int stellaris_sys_post_load(void *opaque, int version_id) -{ - ssys_state *s = opaque; - - ssys_calculate_system_clock(s); - - return 0; -} - -static const VMStateDescription vmstate_stellaris_sys = { - .name = "stellaris_sys", - .version_id = 2, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .post_load = stellaris_sys_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(pborctl, ssys_state), - VMSTATE_UINT32(ldopctl, ssys_state), - VMSTATE_UINT32(int_mask, ssys_state), - VMSTATE_UINT32(int_status, ssys_state), - VMSTATE_UINT32(resc, ssys_state), - VMSTATE_UINT32(rcc, ssys_state), - VMSTATE_UINT32_V(rcc2, ssys_state, 2), - VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3), - VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3), - VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3), - VMSTATE_UINT32(clkvclr, ssys_state), - VMSTATE_UINT32(ldoarst, ssys_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_sys_init(uint32_t base, qemu_irq irq, - stellaris_board_info * board, - uint8_t *macaddr) -{ - ssys_state *s; - - s = (ssys_state *)g_malloc0(sizeof(ssys_state)); - s->irq = irq; - s->board = board; - /* Most devices come preprogrammed with a MAC address in the user data. */ - s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16); - s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16); - - memory_region_init_io(&s->iomem, &ssys_ops, s, "ssys", 0x00001000); - memory_region_add_subregion(get_system_memory(), base, &s->iomem); - ssys_reset(s); - vmstate_register(NULL, -1, &vmstate_stellaris_sys, s); - return 0; -} - - -/* I2C controller. */ - -typedef struct { - SysBusDevice busdev; - i2c_bus *bus; - qemu_irq irq; - MemoryRegion iomem; - uint32_t msa; - uint32_t mcs; - uint32_t mdr; - uint32_t mtpr; - uint32_t mimr; - uint32_t mris; - uint32_t mcr; -} stellaris_i2c_state; - -#define STELLARIS_I2C_MCS_BUSY 0x01 -#define STELLARIS_I2C_MCS_ERROR 0x02 -#define STELLARIS_I2C_MCS_ADRACK 0x04 -#define STELLARIS_I2C_MCS_DATACK 0x08 -#define STELLARIS_I2C_MCS_ARBLST 0x10 -#define STELLARIS_I2C_MCS_IDLE 0x20 -#define STELLARIS_I2C_MCS_BUSBSY 0x40 - -static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset, - unsigned size) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - switch (offset) { - case 0x00: /* MSA */ - return s->msa; - case 0x04: /* MCS */ - /* We don't emulate timing, so the controller is never busy. */ - return s->mcs | STELLARIS_I2C_MCS_IDLE; - case 0x08: /* MDR */ - return s->mdr; - case 0x0c: /* MTPR */ - return s->mtpr; - case 0x10: /* MIMR */ - return s->mimr; - case 0x14: /* MRIS */ - return s->mris; - case 0x18: /* MMIS */ - return s->mris & s->mimr; - case 0x20: /* MCR */ - return s->mcr; - default: - hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset); - return 0; - } -} - -static void stellaris_i2c_update(stellaris_i2c_state *s) -{ - int level; - - level = (s->mris & s->mimr) != 0; - qemu_set_irq(s->irq, level); -} - -static void stellaris_i2c_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - switch (offset) { - case 0x00: /* MSA */ - s->msa = value & 0xff; - break; - case 0x04: /* MCS */ - if ((s->mcr & 0x10) == 0) { - /* Disabled. Do nothing. */ - break; - } - /* Grab the bus if this is starting a transfer. */ - if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { - if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) { - s->mcs |= STELLARIS_I2C_MCS_ARBLST; - } else { - s->mcs &= ~STELLARIS_I2C_MCS_ARBLST; - s->mcs |= STELLARIS_I2C_MCS_BUSBSY; - } - } - /* If we don't have the bus then indicate an error. */ - if (!i2c_bus_busy(s->bus) - || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { - s->mcs |= STELLARIS_I2C_MCS_ERROR; - break; - } - s->mcs &= ~STELLARIS_I2C_MCS_ERROR; - if (value & 1) { - /* Transfer a byte. */ - /* TODO: Handle errors. */ - if (s->msa & 1) { - /* Recv */ - s->mdr = i2c_recv(s->bus) & 0xff; - } else { - /* Send */ - i2c_send(s->bus, s->mdr); - } - /* Raise an interrupt. */ - s->mris |= 1; - } - if (value & 4) { - /* Finish transfer. */ - i2c_end_transfer(s->bus); - s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY; - } - break; - case 0x08: /* MDR */ - s->mdr = value & 0xff; - break; - case 0x0c: /* MTPR */ - s->mtpr = value & 0xff; - break; - case 0x10: /* MIMR */ - s->mimr = 1; - break; - case 0x1c: /* MICR */ - s->mris &= ~value; - break; - case 0x20: /* MCR */ - if (value & 1) - hw_error( - "stellaris_i2c_write: Loopback not implemented\n"); - if (value & 0x20) - hw_error( - "stellaris_i2c_write: Slave mode not implemented\n"); - s->mcr = value & 0x31; - break; - default: - hw_error("stellaris_i2c_write: Bad offset 0x%x\n", - (int)offset); - } - stellaris_i2c_update(s); -} - -static void stellaris_i2c_reset(stellaris_i2c_state *s) -{ - if (s->mcs & STELLARIS_I2C_MCS_BUSBSY) - i2c_end_transfer(s->bus); - - s->msa = 0; - s->mcs = 0; - s->mdr = 0; - s->mtpr = 1; - s->mimr = 0; - s->mris = 0; - s->mcr = 0; - stellaris_i2c_update(s); -} - -static const MemoryRegionOps stellaris_i2c_ops = { - .read = stellaris_i2c_read, - .write = stellaris_i2c_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_stellaris_i2c = { - .name = "stellaris_i2c", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(msa, stellaris_i2c_state), - VMSTATE_UINT32(mcs, stellaris_i2c_state), - VMSTATE_UINT32(mdr, stellaris_i2c_state), - VMSTATE_UINT32(mtpr, stellaris_i2c_state), - VMSTATE_UINT32(mimr, stellaris_i2c_state), - VMSTATE_UINT32(mris, stellaris_i2c_state), - VMSTATE_UINT32(mcr, stellaris_i2c_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_i2c_init(SysBusDevice * dev) -{ - stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev); - i2c_bus *bus; - - sysbus_init_irq(dev, &s->irq); - bus = i2c_init_bus(&dev->qdev, "i2c"); - s->bus = bus; - - memory_region_init_io(&s->iomem, &stellaris_i2c_ops, s, - "i2c", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - /* ??? For now we only implement the master interface. */ - stellaris_i2c_reset(s); - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s); - return 0; -} - -/* Analogue to Digital Converter. This is only partially implemented, - enough for applications that use a combined ADC and timer tick. */ - -#define STELLARIS_ADC_EM_CONTROLLER 0 -#define STELLARIS_ADC_EM_COMP 1 -#define STELLARIS_ADC_EM_EXTERNAL 4 -#define STELLARIS_ADC_EM_TIMER 5 -#define STELLARIS_ADC_EM_PWM0 6 -#define STELLARIS_ADC_EM_PWM1 7 -#define STELLARIS_ADC_EM_PWM2 8 - -#define STELLARIS_ADC_FIFO_EMPTY 0x0100 -#define STELLARIS_ADC_FIFO_FULL 0x1000 - -typedef struct -{ - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t actss; - uint32_t ris; - uint32_t im; - uint32_t emux; - uint32_t ostat; - uint32_t ustat; - uint32_t sspri; - uint32_t sac; - struct { - uint32_t state; - uint32_t data[16]; - } fifo[4]; - uint32_t ssmux[4]; - uint32_t ssctl[4]; - uint32_t noise; - qemu_irq irq[4]; -} stellaris_adc_state; - -static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) -{ - int tail; - - tail = s->fifo[n].state & 0xf; - if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) { - s->ustat |= 1 << n; - } else { - s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf); - s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL; - if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf)) - s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY; - } - return s->fifo[n].data[tail]; -} - -static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, - uint32_t value) -{ - int head; - - /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry - FIFO fir each sequencer. */ - head = (s->fifo[n].state >> 4) & 0xf; - if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) { - s->ostat |= 1 << n; - return; - } - s->fifo[n].data[head] = value; - head = (head + 1) & 0xf; - s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY; - s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4); - if ((s->fifo[n].state & 0xf) == head) - s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL; -} - -static void stellaris_adc_update(stellaris_adc_state *s) -{ - int level; - int n; - - for (n = 0; n < 4; n++) { - level = (s->ris & s->im & (1 << n)) != 0; - qemu_set_irq(s->irq[n], level); - } -} - -static void stellaris_adc_trigger(void *opaque, int irq, int level) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - int n; - - for (n = 0; n < 4; n++) { - if ((s->actss & (1 << n)) == 0) { - continue; - } - - if (((s->emux >> (n * 4)) & 0xff) != 5) { - continue; - } - - /* Some applications use the ADC as a random number source, so introduce - some variation into the signal. */ - s->noise = s->noise * 314159 + 1; - /* ??? actual inputs not implemented. Return an arbitrary value. */ - stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7)); - s->ris |= (1 << n); - stellaris_adc_update(s); - } -} - -static void stellaris_adc_reset(stellaris_adc_state *s) -{ - int n; - - for (n = 0; n < 4; n++) { - s->ssmux[n] = 0; - s->ssctl[n] = 0; - s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY; - } -} - -static uint64_t stellaris_adc_read(void *opaque, hwaddr offset, - unsigned size) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - - /* TODO: Implement this. */ - if (offset >= 0x40 && offset < 0xc0) { - int n; - n = (offset - 0x40) >> 5; - switch (offset & 0x1f) { - case 0x00: /* SSMUX */ - return s->ssmux[n]; - case 0x04: /* SSCTL */ - return s->ssctl[n]; - case 0x08: /* SSFIFO */ - return stellaris_adc_fifo_read(s, n); - case 0x0c: /* SSFSTAT */ - return s->fifo[n].state; - default: - break; - } - } - switch (offset) { - case 0x00: /* ACTSS */ - return s->actss; - case 0x04: /* RIS */ - return s->ris; - case 0x08: /* IM */ - return s->im; - case 0x0c: /* ISC */ - return s->ris & s->im; - case 0x10: /* OSTAT */ - return s->ostat; - case 0x14: /* EMUX */ - return s->emux; - case 0x18: /* USTAT */ - return s->ustat; - case 0x20: /* SSPRI */ - return s->sspri; - case 0x30: /* SAC */ - return s->sac; - default: - hw_error("strllaris_adc_read: Bad offset 0x%x\n", - (int)offset); - return 0; - } -} - -static void stellaris_adc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - - /* TODO: Implement this. */ - if (offset >= 0x40 && offset < 0xc0) { - int n; - n = (offset - 0x40) >> 5; - switch (offset & 0x1f) { - case 0x00: /* SSMUX */ - s->ssmux[n] = value & 0x33333333; - return; - case 0x04: /* SSCTL */ - if (value != 6) { - hw_error("ADC: Unimplemented sequence %" PRIx64 "\n", - value); - } - s->ssctl[n] = value; - return; - default: - break; - } - } - switch (offset) { - case 0x00: /* ACTSS */ - s->actss = value & 0xf; - break; - case 0x08: /* IM */ - s->im = value; - break; - case 0x0c: /* ISC */ - s->ris &= ~value; - break; - case 0x10: /* OSTAT */ - s->ostat &= ~value; - break; - case 0x14: /* EMUX */ - s->emux = value; - break; - case 0x18: /* USTAT */ - s->ustat &= ~value; - break; - case 0x20: /* SSPRI */ - s->sspri = value; - break; - case 0x28: /* PSSI */ - hw_error("Not implemented: ADC sample initiate\n"); - break; - case 0x30: /* SAC */ - s->sac = value; - break; - default: - hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset); - } - stellaris_adc_update(s); -} - -static const MemoryRegionOps stellaris_adc_ops = { - .read = stellaris_adc_read, - .write = stellaris_adc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_stellaris_adc = { - .name = "stellaris_adc", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(actss, stellaris_adc_state), - VMSTATE_UINT32(ris, stellaris_adc_state), - VMSTATE_UINT32(im, stellaris_adc_state), - VMSTATE_UINT32(emux, stellaris_adc_state), - VMSTATE_UINT32(ostat, stellaris_adc_state), - VMSTATE_UINT32(ustat, stellaris_adc_state), - VMSTATE_UINT32(sspri, stellaris_adc_state), - VMSTATE_UINT32(sac, stellaris_adc_state), - VMSTATE_UINT32(fifo[0].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[0], stellaris_adc_state), - VMSTATE_UINT32(ssctl[0], stellaris_adc_state), - VMSTATE_UINT32(fifo[1].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[1], stellaris_adc_state), - VMSTATE_UINT32(ssctl[1], stellaris_adc_state), - VMSTATE_UINT32(fifo[2].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[2], stellaris_adc_state), - VMSTATE_UINT32(ssctl[2], stellaris_adc_state), - VMSTATE_UINT32(fifo[3].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[3], stellaris_adc_state), - VMSTATE_UINT32(ssctl[3], stellaris_adc_state), - VMSTATE_UINT32(noise, stellaris_adc_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_adc_init(SysBusDevice *dev) -{ - stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev); - int n; - - for (n = 0; n < 4; n++) { - sysbus_init_irq(dev, &s->irq[n]); - } - - memory_region_init_io(&s->iomem, &stellaris_adc_ops, s, - "adc", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - stellaris_adc_reset(s); - qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1); - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s); - return 0; -} - -/* Board init. */ -static stellaris_board_info stellaris_boards[] = { - { "LM3S811EVB", - 0, - 0x0032000e, - 0x001f001f, /* dc0 */ - 0x001132bf, - 0x01071013, - 0x3f0f01ff, - 0x0000001f, - BP_OLED_I2C - }, - { "LM3S6965EVB", - 0x10010002, - 0x1073402e, - 0x00ff007f, /* dc0 */ - 0x001133ff, - 0x030f5317, - 0x0f0f87ff, - 0x5000007f, - BP_OLED_SSI | BP_GAMEPAD - } -}; - -static void stellaris_init(const char *kernel_filename, const char *cpu_model, - stellaris_board_info *board) -{ - static const int uart_irq[] = {5, 6, 33, 34}; - static const int timer_irq[] = {19, 21, 23, 35}; - static const uint32_t gpio_addr[7] = - { 0x40004000, 0x40005000, 0x40006000, 0x40007000, - 0x40024000, 0x40025000, 0x40026000}; - static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; - - MemoryRegion *address_space_mem = get_system_memory(); - qemu_irq *pic; - DeviceState *gpio_dev[7]; - qemu_irq gpio_in[7][8]; - qemu_irq gpio_out[7][8]; - qemu_irq adc; - int sram_size; - int flash_size; - i2c_bus *i2c; - DeviceState *dev; - int i; - int j; - - flash_size = ((board->dc0 & 0xffff) + 1) << 1; - sram_size = (board->dc0 >> 18) + 1; - pic = armv7m_init(address_space_mem, - flash_size, sram_size, kernel_filename, cpu_model); - - if (board->dc1 & (1 << 16)) { - dev = sysbus_create_varargs("stellaris-adc", 0x40038000, - pic[14], pic[15], pic[16], pic[17], NULL); - adc = qdev_get_gpio_in(dev, 0); - } else { - adc = NULL; - } - for (i = 0; i < 4; i++) { - if (board->dc2 & (0x10000 << i)) { - dev = sysbus_create_simple("stellaris-gptm", - 0x40030000 + i * 0x1000, - pic[timer_irq[i]]); - /* TODO: This is incorrect, but we get away with it because - the ADC output is only ever pulsed. */ - qdev_connect_gpio_out(dev, 0, adc); - } - } - - stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a); - - for (i = 0; i < 7; i++) { - if (board->dc4 & (1 << i)) { - gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i], - pic[gpio_irq[i]]); - for (j = 0; j < 8; j++) { - gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j); - gpio_out[i][j] = NULL; - } - } - } - - if (board->dc2 & (1 << 12)) { - dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]); - i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); - if (board->peripherals & BP_OLED_I2C) { - i2c_create_slave(i2c, "ssd0303", 0x3d); - } - } - - for (i = 0; i < 4; i++) { - if (board->dc2 & (1 << i)) { - sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000, - pic[uart_irq[i]]); - } - } - if (board->dc2 & (1 << 4)) { - dev = sysbus_create_simple("pl022", 0x40008000, pic[7]); - if (board->peripherals & BP_OLED_SSI) { - void *bus; - DeviceState *sddev; - DeviceState *ssddev; - - /* Some boards have both an OLED controller and SD card connected to - * the same SSI port, with the SD card chip select connected to a - * GPIO pin. Technically the OLED chip select is connected to the - * SSI Fss pin. We do not bother emulating that as both devices - * should never be selected simultaneously, and our OLED controller - * ignores stray 0xff commands that occur when deselecting the SD - * card. - */ - bus = qdev_get_child_bus(dev, "ssi"); - - sddev = ssi_create_slave(bus, "ssi-sd"); - ssddev = ssi_create_slave(bus, "ssd0323"); - gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0), - qdev_get_gpio_in(ssddev, 0)); - gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1); - - /* Make sure the select pin is high. */ - qemu_irq_raise(gpio_out[GPIO_D][0]); - } - } - if (board->dc4 & (1 << 28)) { - DeviceState *enet; - - qemu_check_nic_model(&nd_table[0], "stellaris"); - - enet = qdev_create(NULL, "stellaris_enet"); - qdev_set_nic_properties(enet, &nd_table[0]); - qdev_init_nofail(enet); - sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000); - sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, pic[42]); - } - if (board->peripherals & BP_GAMEPAD) { - qemu_irq gpad_irq[5]; - static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; - - gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */ - gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */ - gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */ - gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */ - gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */ - - stellaris_gamepad_init(5, gpad_irq, gpad_keycode); - } - for (i = 0; i < 7; i++) { - if (board->dc4 & (1 << i)) { - for (j = 0; j < 8; j++) { - if (gpio_out[i][j]) { - qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]); - } - } - } - } -} - -/* FIXME: Figure out how to generate these from stellaris_boards. */ -static void lm3s811evb_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]); -} - -static void lm3s6965evb_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); -} - -static QEMUMachine lm3s811evb_machine = { - .name = "lm3s811evb", - .desc = "Stellaris LM3S811EVB", - .init = lm3s811evb_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine lm3s6965evb_machine = { - .name = "lm3s6965evb", - .desc = "Stellaris LM3S6965EVB", - .init = lm3s6965evb_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void stellaris_machine_init(void) -{ - qemu_register_machine(&lm3s811evb_machine); - qemu_register_machine(&lm3s6965evb_machine); -} - -machine_init(stellaris_machine_init); - -static void stellaris_i2c_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = stellaris_i2c_init; -} - -static const TypeInfo stellaris_i2c_info = { - .name = "stellaris-i2c", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(stellaris_i2c_state), - .class_init = stellaris_i2c_class_init, -}; - -static void stellaris_gptm_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = stellaris_gptm_init; -} - -static const TypeInfo stellaris_gptm_info = { - .name = "stellaris-gptm", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(gptm_state), - .class_init = stellaris_gptm_class_init, -}; - -static void stellaris_adc_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = stellaris_adc_init; -} - -static const TypeInfo stellaris_adc_info = { - .name = "stellaris-adc", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(stellaris_adc_state), - .class_init = stellaris_adc_class_init, -}; - -static void stellaris_register_types(void) -{ - type_register_static(&stellaris_i2c_info); - type_register_static(&stellaris_gptm_info); - type_register_static(&stellaris_adc_info); -} - -type_init(stellaris_register_types) diff --git a/hw/sun4m.c b/hw/sun4m.c deleted file mode 100644 index 37bd04108d..0000000000 --- a/hw/sun4m.c +++ /dev/null @@ -1,1936 +0,0 @@ -/* - * QEMU Sun4m & Sun4d & Sun4c System Emulator - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "hw/sun4m.h" -#include "hw/nvram.h" -#include "hw/sparc32_dma.h" -#include "hw/fdc.h" -#include "sysemu/sysemu.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/firmware_abi.h" -#include "hw/esp.h" -#include "hw/pc.h" -#include "hw/isa.h" -#include "hw/fw_cfg.h" -#include "hw/escc.h" -#include "hw/empty_slot.h" -#include "hw/qdev-addr.h" -#include "hw/loader.h" -#include "elf.h" -#include "sysemu/blockdev.h" -#include "trace.h" - -/* - * Sun4m architecture was used in the following machines: - * - * SPARCserver 6xxMP/xx - * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), - * SPARCclassic X (4/10) - * SPARCstation LX/ZX (4/30) - * SPARCstation Voyager - * SPARCstation 10/xx, SPARCserver 10/xx - * SPARCstation 5, SPARCserver 5 - * SPARCstation 20/xx, SPARCserver 20 - * SPARCstation 4 - * - * Sun4d architecture was used in the following machines: - * - * SPARCcenter 2000 - * SPARCserver 1000 - * - * Sun4c architecture was used in the following machines: - * SPARCstation 1/1+, SPARCserver 1/1+ - * SPARCstation SLC - * SPARCstation IPC - * SPARCstation ELC - * SPARCstation IPX - * - * See for example: http://www.sunhelp.org/faq/sunref1.html - */ - -#define KERNEL_LOAD_ADDR 0x00004000 -#define CMDLINE_ADDR 0x007ff000 -#define INITRD_LOAD_ADDR 0x00800000 -#define PROM_SIZE_MAX (1024 * 1024) -#define PROM_VADDR 0xffd00000 -#define PROM_FILENAME "openbios-sparc32" -#define CFG_ADDR 0xd00000510ULL -#define FW_CFG_SUN4M_DEPTH (FW_CFG_ARCH_LOCAL + 0x00) - -#define MAX_CPUS 16 -#define MAX_PILS 16 -#define MAX_VSIMMS 4 - -#define ESCC_CLOCK 4915200 - -struct sun4m_hwdef { - hwaddr iommu_base, iommu_pad_base, iommu_pad_len, slavio_base; - hwaddr intctl_base, counter_base, nvram_base, ms_kb_base; - hwaddr serial_base, fd_base; - hwaddr afx_base, idreg_base, dma_base, esp_base, le_base; - hwaddr tcx_base, cs_base, apc_base, aux1_base, aux2_base; - hwaddr bpp_base, dbri_base, sx_base; - struct { - hwaddr reg_base, vram_base; - } vsimm[MAX_VSIMMS]; - hwaddr ecc_base; - uint64_t max_mem; - const char * const default_cpu_model; - uint32_t ecc_version; - uint32_t iommu_version; - uint16_t machine_id; - uint8_t nvram_machine_id; -}; - -#define MAX_IOUNITS 5 - -struct sun4d_hwdef { - hwaddr iounit_bases[MAX_IOUNITS], slavio_base; - hwaddr counter_base, nvram_base, ms_kb_base; - hwaddr serial_base; - hwaddr espdma_base, esp_base; - hwaddr ledma_base, le_base; - hwaddr tcx_base; - hwaddr sbi_base; - uint64_t max_mem; - const char * const default_cpu_model; - uint32_t iounit_version; - uint16_t machine_id; - uint8_t nvram_machine_id; -}; - -struct sun4c_hwdef { - hwaddr iommu_base, slavio_base; - hwaddr intctl_base, counter_base, nvram_base, ms_kb_base; - hwaddr serial_base, fd_base; - hwaddr idreg_base, dma_base, esp_base, le_base; - hwaddr tcx_base, aux1_base; - uint64_t max_mem; - const char * const default_cpu_model; - uint32_t iommu_version; - uint16_t machine_id; - uint8_t nvram_machine_id; -}; - -int DMA_get_channel_mode (int nchan) -{ - return 0; -} -int DMA_read_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -int DMA_write_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -void DMA_hold_DREQ (int nchan) {} -void DMA_release_DREQ (int nchan) {} -void DMA_schedule(int nchan) {} - -void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) -{ -} - -void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, - void *opaque) -{ -} - -static int fw_cfg_boot_set(void *opaque, const char *boot_device) -{ - fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); - return 0; -} - -static void nvram_init(M48t59State *nvram, uint8_t *macaddr, - const char *cmdline, const char *boot_devices, - ram_addr_t RAM_size, uint32_t kernel_size, - int width, int height, int depth, - int nvram_machine_id, const char *arch) -{ - unsigned int i; - uint32_t start, end; - uint8_t image[0x1ff0]; - struct OpenBIOS_nvpart_v1 *part_header; - - memset(image, '\0', sizeof(image)); - - start = 0; - - // OpenBIOS nvram variables - // Variable partition - part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; - part_header->signature = OPENBIOS_PART_SYSTEM; - pstrcpy(part_header->name, sizeof(part_header->name), "system"); - - end = start + sizeof(struct OpenBIOS_nvpart_v1); - for (i = 0; i < nb_prom_envs; i++) - end = OpenBIOS_set_var(image, end, prom_envs[i]); - - // End marker - image[end++] = '\0'; - - end = start + ((end - start + 15) & ~15); - OpenBIOS_finish_partition(part_header, end - start); - - // free partition - start = end; - part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; - part_header->signature = OPENBIOS_PART_FREE; - pstrcpy(part_header->name, sizeof(part_header->name), "free"); - - end = 0x1fd0; - OpenBIOS_finish_partition(part_header, end - start); - - Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, - nvram_machine_id); - - for (i = 0; i < sizeof(image); i++) - m48t59_write(nvram, i, image[i]); -} - -static DeviceState *slavio_intctl; - -void sun4m_pic_info(Monitor *mon, const QDict *qdict) -{ - if (slavio_intctl) - slavio_pic_info(mon, slavio_intctl); -} - -void sun4m_irq_info(Monitor *mon, const QDict *qdict) -{ - if (slavio_intctl) - slavio_irq_info(mon, slavio_intctl); -} - -void cpu_check_irqs(CPUSPARCState *env) -{ - if (env->pil_in && (env->interrupt_index == 0 || - (env->interrupt_index & ~15) == TT_EXTINT)) { - unsigned int i; - - for (i = 15; i > 0; i--) { - if (env->pil_in & (1 << i)) { - int old_interrupt = env->interrupt_index; - - env->interrupt_index = TT_EXTINT | i; - if (old_interrupt != env->interrupt_index) { - trace_sun4m_cpu_interrupt(i); - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - break; - } - } - } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { - trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15); - env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -static void cpu_kick_irq(SPARCCPU *cpu) -{ - CPUSPARCState *env = &cpu->env; - - env->halted = 0; - cpu_check_irqs(env); - qemu_cpu_kick(CPU(cpu)); -} - -static void cpu_set_irq(void *opaque, int irq, int level) -{ - SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; - - if (level) { - trace_sun4m_cpu_set_irq_raise(irq); - env->pil_in |= 1 << irq; - cpu_kick_irq(cpu); - } else { - trace_sun4m_cpu_set_irq_lower(irq); - env->pil_in &= ~(1 << irq); - cpu_check_irqs(env); - } -} - -static void dummy_cpu_set_irq(void *opaque, int irq, int level) -{ -} - -static void main_cpu_reset(void *opaque) -{ - SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; - - cpu_reset(CPU(cpu)); - env->halted = 0; -} - -static void secondary_cpu_reset(void *opaque) -{ - SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; - - cpu_reset(CPU(cpu)); - env->halted = 1; -} - -static void cpu_halt_signal(void *opaque, int irq, int level) -{ - if (level && cpu_single_env) - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); -} - -static uint64_t translate_kernel_address(void *opaque, uint64_t addr) -{ - return addr - 0xf0000000ULL; -} - -static unsigned long sun4m_load_kernel(const char *kernel_filename, - const char *initrd_filename, - ram_addr_t RAM_size) -{ - int linux_boot; - unsigned int i; - long initrd_size, kernel_size; - uint8_t *ptr; - - linux_boot = (kernel_filename != NULL); - - kernel_size = 0; - if (linux_boot) { - int bswap_needed; - -#ifdef BSWAP_NEEDED - bswap_needed = 1; -#else - bswap_needed = 0; -#endif - kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, - NULL, NULL, NULL, 1, ELF_MACHINE, 0); - if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, - RAM_size - KERNEL_LOAD_ADDR, bswap_needed, - TARGET_PAGE_SIZE); - if (kernel_size < 0) - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - RAM_size - KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - if (initrd_filename) { - initrd_size = load_image_targphys(initrd_filename, - INITRD_LOAD_ADDR, - RAM_size - INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (initrd_size > 0) { - for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - ptr = rom_ptr(KERNEL_LOAD_ADDR + i); - if (ldl_p(ptr) == 0x48647253) { // HdrS - stl_p(ptr + 16, INITRD_LOAD_ADDR); - stl_p(ptr + 20, initrd_size); - break; - } - } - } - } - return kernel_size; -} - -static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "iommu"); - qdev_prop_set_uint32(dev, "version", version); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, irq); - sysbus_mmio_map(s, 0, addr); - - return s; -} - -static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, - void *iommu, qemu_irq *dev_irq, int is_ledma) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "sparc32_dma"); - qdev_prop_set_ptr(dev, "iommu_opaque", iommu); - qdev_prop_set_uint32(dev, "is_ledma", is_ledma); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, parent_irq); - *dev_irq = qdev_get_gpio_in(dev, 0); - sysbus_mmio_map(s, 0, daddr); - - return s; -} - -static void lance_init(NICInfo *nd, hwaddr leaddr, - void *dma_opaque, qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *s; - qemu_irq reset; - - qemu_check_nic_model(&nd_table[0], "lance"); - - dev = qdev_create(NULL, "lance"); - qdev_set_nic_properties(dev, nd); - qdev_prop_set_ptr(dev, "dma", dma_opaque); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, leaddr); - sysbus_connect_irq(s, 0, irq); - reset = qdev_get_gpio_in(dev, 0); - qdev_connect_gpio_out(dma_opaque, 0, reset); -} - -static DeviceState *slavio_intctl_init(hwaddr addr, - hwaddr addrg, - qemu_irq **parent_irq) -{ - DeviceState *dev; - SysBusDevice *s; - unsigned int i, j; - - dev = qdev_create(NULL, "slavio_intctl"); - qdev_init_nofail(dev); - - s = SYS_BUS_DEVICE(dev); - - for (i = 0; i < MAX_CPUS; i++) { - for (j = 0; j < MAX_PILS; j++) { - sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]); - } - } - sysbus_mmio_map(s, 0, addrg); - for (i = 0; i < MAX_CPUS; i++) { - sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE); - } - - return dev; -} - -#define SYS_TIMER_OFFSET 0x10000ULL -#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu) - -static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq, - qemu_irq *cpu_irqs, unsigned int num_cpus) -{ - DeviceState *dev; - SysBusDevice *s; - unsigned int i; - - dev = qdev_create(NULL, "slavio_timer"); - qdev_prop_set_uint32(dev, "num_cpus", num_cpus); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, master_irq); - sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET); - - for (i = 0; i < MAX_CPUS; i++) { - sysbus_mmio_map(s, i + 1, addr + (hwaddr)CPU_TIMER_OFFSET(i)); - sysbus_connect_irq(s, i + 1, cpu_irqs[i]); - } -} - -static qemu_irq slavio_system_powerdown; - -static void slavio_powerdown_req(Notifier *n, void *opaque) -{ - qemu_irq_raise(slavio_system_powerdown); -} - -static Notifier slavio_system_powerdown_notifier = { - .notify = slavio_powerdown_req -}; - -#define MISC_LEDS 0x01600000 -#define MISC_CFG 0x01800000 -#define MISC_DIAG 0x01a00000 -#define MISC_MDM 0x01b00000 -#define MISC_SYS 0x01f00000 - -static void slavio_misc_init(hwaddr base, - hwaddr aux1_base, - hwaddr aux2_base, qemu_irq irq, - qemu_irq fdc_tc) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "slavio_misc"); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - if (base) { - /* 8 bit registers */ - /* Slavio control */ - sysbus_mmio_map(s, 0, base + MISC_CFG); - /* Diagnostics */ - sysbus_mmio_map(s, 1, base + MISC_DIAG); - /* Modem control */ - sysbus_mmio_map(s, 2, base + MISC_MDM); - /* 16 bit registers */ - /* ss600mp diag LEDs */ - sysbus_mmio_map(s, 3, base + MISC_LEDS); - /* 32 bit registers */ - /* System control */ - sysbus_mmio_map(s, 4, base + MISC_SYS); - } - if (aux1_base) { - /* AUX 1 (Misc System Functions) */ - sysbus_mmio_map(s, 5, aux1_base); - } - if (aux2_base) { - /* AUX 2 (Software Powerdown Control) */ - sysbus_mmio_map(s, 6, aux2_base); - } - sysbus_connect_irq(s, 0, irq); - sysbus_connect_irq(s, 1, fdc_tc); - slavio_system_powerdown = qdev_get_gpio_in(dev, 0); - qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier); -} - -static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "eccmemctl"); - qdev_prop_set_uint32(dev, "version", version); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, irq); - sysbus_mmio_map(s, 0, base); - if (version == 0) { // SS-600MP only - sysbus_mmio_map(s, 1, base + 0x1000); - } -} - -static void apc_init(hwaddr power_base, qemu_irq cpu_halt) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "apc"); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - /* Power management (APC) XXX: not a Slavio device */ - sysbus_mmio_map(s, 0, power_base); - sysbus_connect_irq(s, 0, cpu_halt); -} - -static void tcx_init(hwaddr addr, int vram_size, int width, - int height, int depth) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "SUNW,tcx"); - qdev_prop_set_taddr(dev, "addr", addr); - qdev_prop_set_uint32(dev, "vram_size", vram_size); - qdev_prop_set_uint16(dev, "width", width); - qdev_prop_set_uint16(dev, "height", height); - qdev_prop_set_uint16(dev, "depth", depth); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - /* 8-bit plane */ - sysbus_mmio_map(s, 0, addr + 0x00800000ULL); - /* DAC */ - sysbus_mmio_map(s, 1, addr + 0x00200000ULL); - /* TEC (dummy) */ - sysbus_mmio_map(s, 2, addr + 0x00700000ULL); - /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */ - sysbus_mmio_map(s, 3, addr + 0x00301000ULL); - if (depth == 24) { - /* 24-bit plane */ - sysbus_mmio_map(s, 4, addr + 0x02000000ULL); - /* Control plane */ - sysbus_mmio_map(s, 5, addr + 0x0a000000ULL); - } else { - /* THC 8 bit (dummy) */ - sysbus_mmio_map(s, 4, addr + 0x00300000ULL); - } -} - -/* NCR89C100/MACIO Internal ID register */ -static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 }; - -static void idreg_init(hwaddr addr) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "macio_idreg"); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - - sysbus_mmio_map(s, 0, addr); - cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data)); -} - -typedef struct IDRegState { - SysBusDevice busdev; - MemoryRegion mem; -} IDRegState; - -static int idreg_init1(SysBusDevice *dev) -{ - IDRegState *s = FROM_SYSBUS(IDRegState, dev); - - memory_region_init_ram(&s->mem, "sun4m.idreg", sizeof(idreg_data)); - vmstate_register_ram_global(&s->mem); - memory_region_set_readonly(&s->mem, true); - sysbus_init_mmio(dev, &s->mem); - return 0; -} - -static void idreg_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = idreg_init1; -} - -static const TypeInfo idreg_info = { - .name = "macio_idreg", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IDRegState), - .class_init = idreg_class_init, -}; - -typedef struct AFXState { - SysBusDevice busdev; - MemoryRegion mem; -} AFXState; - -/* SS-5 TCX AFX register */ -static void afx_init(hwaddr addr) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "tcx_afx"); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - - sysbus_mmio_map(s, 0, addr); -} - -static int afx_init1(SysBusDevice *dev) -{ - AFXState *s = FROM_SYSBUS(AFXState, dev); - - memory_region_init_ram(&s->mem, "sun4m.afx", 4); - vmstate_register_ram_global(&s->mem); - sysbus_init_mmio(dev, &s->mem); - return 0; -} - -static void afx_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = afx_init1; -} - -static const TypeInfo afx_info = { - .name = "tcx_afx", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AFXState), - .class_init = afx_class_init, -}; - -typedef struct PROMState { - SysBusDevice busdev; - MemoryRegion prom; -} PROMState; - -/* Boot PROM (OpenBIOS) */ -static uint64_t translate_prom_address(void *opaque, uint64_t addr) -{ - hwaddr *base_addr = (hwaddr *)opaque; - return addr + *base_addr - PROM_VADDR; -} - -static void prom_init(hwaddr addr, const char *bios_name) -{ - DeviceState *dev; - SysBusDevice *s; - char *filename; - int ret; - - dev = qdev_create(NULL, "openprom"); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - - sysbus_mmio_map(s, 0, addr); - - /* load boot prom */ - if (bios_name == NULL) { - bios_name = PROM_FILENAME; - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - ret = load_elf(filename, translate_prom_address, &addr, NULL, - NULL, NULL, 1, ELF_MACHINE, 0); - if (ret < 0 || ret > PROM_SIZE_MAX) { - ret = load_image_targphys(filename, addr, PROM_SIZE_MAX); - } - g_free(filename); - } else { - ret = -1; - } - if (ret < 0 || ret > PROM_SIZE_MAX) { - fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name); - exit(1); - } -} - -static int prom_init1(SysBusDevice *dev) -{ - PROMState *s = FROM_SYSBUS(PROMState, dev); - - memory_region_init_ram(&s->prom, "sun4m.prom", PROM_SIZE_MAX); - vmstate_register_ram_global(&s->prom); - memory_region_set_readonly(&s->prom, true); - sysbus_init_mmio(dev, &s->prom); - return 0; -} - -static Property prom_properties[] = { - {/* end of property list */}, -}; - -static void prom_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = prom_init1; - dc->props = prom_properties; -} - -static const TypeInfo prom_info = { - .name = "openprom", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PROMState), - .class_init = prom_class_init, -}; - -typedef struct RamDevice -{ - SysBusDevice busdev; - MemoryRegion ram; - uint64_t size; -} RamDevice; - -/* System RAM */ -static int ram_init1(SysBusDevice *dev) -{ - RamDevice *d = FROM_SYSBUS(RamDevice, dev); - - memory_region_init_ram(&d->ram, "sun4m.ram", d->size); - vmstate_register_ram_global(&d->ram); - sysbus_init_mmio(dev, &d->ram); - return 0; -} - -static void ram_init(hwaddr addr, ram_addr_t RAM_size, - uint64_t max_mem) -{ - DeviceState *dev; - SysBusDevice *s; - RamDevice *d; - - /* allocate RAM */ - if ((uint64_t)RAM_size > max_mem) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d, maximum %d\n", - (unsigned int)(RAM_size / (1024 * 1024)), - (unsigned int)(max_mem / (1024 * 1024))); - exit(1); - } - dev = qdev_create(NULL, "memory"); - s = SYS_BUS_DEVICE(dev); - - d = FROM_SYSBUS(RamDevice, s); - d->size = RAM_size; - qdev_init_nofail(dev); - - sysbus_mmio_map(s, 0, addr); -} - -static Property ram_properties[] = { - DEFINE_PROP_UINT64("size", RamDevice, size, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void ram_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = ram_init1; - dc->props = ram_properties; -} - -static const TypeInfo ram_info = { - .name = "memory", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(RamDevice), - .class_init = ram_class_init, -}; - -static void cpu_devinit(const char *cpu_model, unsigned int id, - uint64_t prom_addr, qemu_irq **cpu_irqs) -{ - SPARCCPU *cpu; - CPUSPARCState *env; - - cpu = cpu_sparc_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); - exit(1); - } - env = &cpu->env; - - cpu_sparc_set_id(env, id); - if (id == 0) { - qemu_register_reset(main_cpu_reset, cpu); - } else { - qemu_register_reset(secondary_cpu_reset, cpu); - env->halted = 1; - } - *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS); - env->prom_addr = prom_addr; -} - -static void dummy_fdc_tc(void *opaque, int irq, int level) -{ -} - -static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - unsigned int i; - void *iommu, *espdma, *ledma, *nvram; - qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS], - espdma_irq, ledma_irq; - qemu_irq esp_reset, dma_enable; - qemu_irq fdc_tc; - qemu_irq *cpu_halt; - unsigned long kernel_size; - DriveInfo *fd[MAX_FD]; - void *fw_cfg; - unsigned int num_vsimms; - - /* init CPUs */ - if (!cpu_model) - cpu_model = hwdef->default_cpu_model; - - for(i = 0; i < smp_cpus; i++) { - cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]); - } - - for (i = smp_cpus; i < MAX_CPUS; i++) - cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); - - - /* set up devices */ - ram_init(0, RAM_size, hwdef->max_mem); - /* models without ECC don't trap when missing ram is accessed */ - if (!hwdef->ecc_base) { - empty_slot_init(RAM_size, hwdef->max_mem - RAM_size); - } - - prom_init(hwdef->slavio_base, bios_name); - - slavio_intctl = slavio_intctl_init(hwdef->intctl_base, - hwdef->intctl_base + 0x10000ULL, - cpu_irqs); - - for (i = 0; i < 32; i++) { - slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i); - } - for (i = 0; i < MAX_CPUS; i++) { - slavio_cpu_irq[i] = qdev_get_gpio_in(slavio_intctl, 32 + i); - } - - if (hwdef->idreg_base) { - idreg_init(hwdef->idreg_base); - } - - if (hwdef->afx_base) { - afx_init(hwdef->afx_base); - } - - iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, - slavio_irq[30]); - - if (hwdef->iommu_pad_base) { - /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased. - Software shouldn't use aliased addresses, neither should it crash - when does. Using empty_slot instead of aliasing can help with - debugging such accesses */ - empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len); - } - - espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18], - iommu, &espdma_irq, 0); - - ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, - slavio_irq[16], iommu, &ledma_irq, 1); - - if (graphic_depth != 8 && graphic_depth != 24) { - fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); - exit (1); - } - num_vsimms = 0; - if (num_vsimms == 0) { - tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, - graphic_depth); - } - - for (i = num_vsimms; i < MAX_VSIMMS; i++) { - /* vsimm registers probed by OBP */ - if (hwdef->vsimm[i].reg_base) { - empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000); - } - } - - if (hwdef->sx_base) { - empty_slot_init(hwdef->sx_base, 0x2000); - } - - lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); - - nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 8); - - slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus); - - slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14], - display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); - /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device - Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ - escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15], - serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); - - cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1); - if (hwdef->apc_base) { - apc_init(hwdef->apc_base, cpu_halt[0]); - } - - if (hwdef->fd_base) { - /* there is zero or one floppy drive */ - memset(fd, 0, sizeof(fd)); - fd[0] = drive_get(IF_FLOPPY, 0, 0); - sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd, - &fdc_tc); - } else { - fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1); - } - - slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base, - slavio_irq[30], fdc_tc); - - if (drive_get_max_bus(IF_SCSI) > 0) { - fprintf(stderr, "qemu: too many SCSI bus\n"); - exit(1); - } - - esp_init(hwdef->esp_base, 2, - espdma_memory_read, espdma_memory_write, - espdma, espdma_irq, &esp_reset, &dma_enable); - - qdev_connect_gpio_out(espdma, 0, esp_reset); - qdev_connect_gpio_out(espdma, 1, dma_enable); - - if (hwdef->cs_base) { - sysbus_create_simple("SUNW,CS4231", hwdef->cs_base, - slavio_irq[5]); - } - - if (hwdef->dbri_base) { - /* ISDN chip with attached CS4215 audio codec */ - /* prom space */ - empty_slot_init(hwdef->dbri_base+0x1000, 0x30); - /* reg space */ - empty_slot_init(hwdef->dbri_base+0x10000, 0x100); - } - - if (hwdef->bpp_base) { - /* parallel port */ - empty_slot_init(hwdef->bpp_base, 0x20); - } - - kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, - RAM_size); - - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, - boot_device, RAM_size, kernel_size, graphic_width, - graphic_height, graphic_depth, hwdef->nvram_machine_id, - "Sun4m"); - - if (hwdef->ecc_base) - ecc_init(hwdef->ecc_base, slavio_irq[28], - hwdef->ecc_version); - - fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); - fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); - fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); - fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); - fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(kernel_cmdline) + 1); - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); - } - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]); - qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); -} - -enum { - ss2_id = 0, - ss5_id = 32, - vger_id, - lx_id, - ss4_id, - scls_id, - sbook_id, - ss10_id = 64, - ss20_id, - ss600mp_id, - ss1000_id = 96, - ss2000_id, -}; - -static const struct sun4m_hwdef sun4m_hwdefs[] = { - /* SS-5 */ - { - .iommu_base = 0x10000000, - .iommu_pad_base = 0x10004000, - .iommu_pad_len = 0x0fffb000, - .tcx_base = 0x50000000, - .cs_base = 0x6c000000, - .slavio_base = 0x70000000, - .ms_kb_base = 0x71000000, - .serial_base = 0x71100000, - .nvram_base = 0x71200000, - .fd_base = 0x71400000, - .counter_base = 0x71d00000, - .intctl_base = 0x71e00000, - .idreg_base = 0x78000000, - .dma_base = 0x78400000, - .esp_base = 0x78800000, - .le_base = 0x78c00000, - .apc_base = 0x6a000000, - .afx_base = 0x6e000000, - .aux1_base = 0x71900000, - .aux2_base = 0x71910000, - .nvram_machine_id = 0x80, - .machine_id = ss5_id, - .iommu_version = 0x05000000, - .max_mem = 0x10000000, - .default_cpu_model = "Fujitsu MB86904", - }, - /* SS-10 */ - { - .iommu_base = 0xfe0000000ULL, - .tcx_base = 0xe20000000ULL, - .slavio_base = 0xff0000000ULL, - .ms_kb_base = 0xff1000000ULL, - .serial_base = 0xff1100000ULL, - .nvram_base = 0xff1200000ULL, - .fd_base = 0xff1700000ULL, - .counter_base = 0xff1300000ULL, - .intctl_base = 0xff1400000ULL, - .idreg_base = 0xef0000000ULL, - .dma_base = 0xef0400000ULL, - .esp_base = 0xef0800000ULL, - .le_base = 0xef0c00000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist - .aux1_base = 0xff1800000ULL, - .aux2_base = 0xff1a01000ULL, - .ecc_base = 0xf00000000ULL, - .ecc_version = 0x10000000, // version 0, implementation 1 - .nvram_machine_id = 0x72, - .machine_id = ss10_id, - .iommu_version = 0x03000000, - .max_mem = 0xf00000000ULL, - .default_cpu_model = "TI SuperSparc II", - }, - /* SS-600MP */ - { - .iommu_base = 0xfe0000000ULL, - .tcx_base = 0xe20000000ULL, - .slavio_base = 0xff0000000ULL, - .ms_kb_base = 0xff1000000ULL, - .serial_base = 0xff1100000ULL, - .nvram_base = 0xff1200000ULL, - .counter_base = 0xff1300000ULL, - .intctl_base = 0xff1400000ULL, - .dma_base = 0xef0081000ULL, - .esp_base = 0xef0080000ULL, - .le_base = 0xef0060000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist - .aux1_base = 0xff1800000ULL, - .aux2_base = 0xff1a01000ULL, // XXX should not exist - .ecc_base = 0xf00000000ULL, - .ecc_version = 0x00000000, // version 0, implementation 0 - .nvram_machine_id = 0x71, - .machine_id = ss600mp_id, - .iommu_version = 0x01000000, - .max_mem = 0xf00000000ULL, - .default_cpu_model = "TI SuperSparc II", - }, - /* SS-20 */ - { - .iommu_base = 0xfe0000000ULL, - .tcx_base = 0xe20000000ULL, - .slavio_base = 0xff0000000ULL, - .ms_kb_base = 0xff1000000ULL, - .serial_base = 0xff1100000ULL, - .nvram_base = 0xff1200000ULL, - .fd_base = 0xff1700000ULL, - .counter_base = 0xff1300000ULL, - .intctl_base = 0xff1400000ULL, - .idreg_base = 0xef0000000ULL, - .dma_base = 0xef0400000ULL, - .esp_base = 0xef0800000ULL, - .le_base = 0xef0c00000ULL, - .bpp_base = 0xef4800000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist - .aux1_base = 0xff1800000ULL, - .aux2_base = 0xff1a01000ULL, - .dbri_base = 0xee0000000ULL, - .sx_base = 0xf80000000ULL, - .vsimm = { - { - .reg_base = 0x9c000000ULL, - .vram_base = 0xfc000000ULL - }, { - .reg_base = 0x90000000ULL, - .vram_base = 0xf0000000ULL - }, { - .reg_base = 0x94000000ULL - }, { - .reg_base = 0x98000000ULL - } - }, - .ecc_base = 0xf00000000ULL, - .ecc_version = 0x20000000, // version 0, implementation 2 - .nvram_machine_id = 0x72, - .machine_id = ss20_id, - .iommu_version = 0x13000000, - .max_mem = 0xf00000000ULL, - .default_cpu_model = "TI SuperSparc II", - }, - /* Voyager */ - { - .iommu_base = 0x10000000, - .tcx_base = 0x50000000, - .slavio_base = 0x70000000, - .ms_kb_base = 0x71000000, - .serial_base = 0x71100000, - .nvram_base = 0x71200000, - .fd_base = 0x71400000, - .counter_base = 0x71d00000, - .intctl_base = 0x71e00000, - .idreg_base = 0x78000000, - .dma_base = 0x78400000, - .esp_base = 0x78800000, - .le_base = 0x78c00000, - .apc_base = 0x71300000, // pmc - .aux1_base = 0x71900000, - .aux2_base = 0x71910000, - .nvram_machine_id = 0x80, - .machine_id = vger_id, - .iommu_version = 0x05000000, - .max_mem = 0x10000000, - .default_cpu_model = "Fujitsu MB86904", - }, - /* LX */ - { - .iommu_base = 0x10000000, - .iommu_pad_base = 0x10004000, - .iommu_pad_len = 0x0fffb000, - .tcx_base = 0x50000000, - .slavio_base = 0x70000000, - .ms_kb_base = 0x71000000, - .serial_base = 0x71100000, - .nvram_base = 0x71200000, - .fd_base = 0x71400000, - .counter_base = 0x71d00000, - .intctl_base = 0x71e00000, - .idreg_base = 0x78000000, - .dma_base = 0x78400000, - .esp_base = 0x78800000, - .le_base = 0x78c00000, - .aux1_base = 0x71900000, - .aux2_base = 0x71910000, - .nvram_machine_id = 0x80, - .machine_id = lx_id, - .iommu_version = 0x04000000, - .max_mem = 0x10000000, - .default_cpu_model = "TI MicroSparc I", - }, - /* SS-4 */ - { - .iommu_base = 0x10000000, - .tcx_base = 0x50000000, - .cs_base = 0x6c000000, - .slavio_base = 0x70000000, - .ms_kb_base = 0x71000000, - .serial_base = 0x71100000, - .nvram_base = 0x71200000, - .fd_base = 0x71400000, - .counter_base = 0x71d00000, - .intctl_base = 0x71e00000, - .idreg_base = 0x78000000, - .dma_base = 0x78400000, - .esp_base = 0x78800000, - .le_base = 0x78c00000, - .apc_base = 0x6a000000, - .aux1_base = 0x71900000, - .aux2_base = 0x71910000, - .nvram_machine_id = 0x80, - .machine_id = ss4_id, - .iommu_version = 0x05000000, - .max_mem = 0x10000000, - .default_cpu_model = "Fujitsu MB86904", - }, - /* SPARCClassic */ - { - .iommu_base = 0x10000000, - .tcx_base = 0x50000000, - .slavio_base = 0x70000000, - .ms_kb_base = 0x71000000, - .serial_base = 0x71100000, - .nvram_base = 0x71200000, - .fd_base = 0x71400000, - .counter_base = 0x71d00000, - .intctl_base = 0x71e00000, - .idreg_base = 0x78000000, - .dma_base = 0x78400000, - .esp_base = 0x78800000, - .le_base = 0x78c00000, - .apc_base = 0x6a000000, - .aux1_base = 0x71900000, - .aux2_base = 0x71910000, - .nvram_machine_id = 0x80, - .machine_id = scls_id, - .iommu_version = 0x05000000, - .max_mem = 0x10000000, - .default_cpu_model = "TI MicroSparc I", - }, - /* SPARCbook */ - { - .iommu_base = 0x10000000, - .tcx_base = 0x50000000, // XXX - .slavio_base = 0x70000000, - .ms_kb_base = 0x71000000, - .serial_base = 0x71100000, - .nvram_base = 0x71200000, - .fd_base = 0x71400000, - .counter_base = 0x71d00000, - .intctl_base = 0x71e00000, - .idreg_base = 0x78000000, - .dma_base = 0x78400000, - .esp_base = 0x78800000, - .le_base = 0x78c00000, - .apc_base = 0x6a000000, - .aux1_base = 0x71900000, - .aux2_base = 0x71910000, - .nvram_machine_id = 0x80, - .machine_id = sbook_id, - .iommu_version = 0x05000000, - .max_mem = 0x10000000, - .default_cpu_model = "TI MicroSparc I", - }, -}; - -/* SPARCstation 5 hardware initialisation */ -static void ss5_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation 10 hardware initialisation */ -static void ss10_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation 20 hardware initialisation */ -static void ss20_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation Voyager hardware initialisation */ -static void vger_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation LX hardware initialisation */ -static void ss_lx_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCstation 4 hardware initialisation */ -static void ss4_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCClassic hardware initialisation */ -static void scls_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCbook hardware initialisation */ -static void sbook_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -static QEMUMachine ss5_machine = { - .name = "SS-5", - .desc = "Sun4m platform, SPARCstation 5", - .init = ss5_init, - .block_default_type = IF_SCSI, - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine ss10_machine = { - .name = "SS-10", - .desc = "Sun4m platform, SPARCstation 10", - .init = ss10_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine ss600mp_machine = { - .name = "SS-600MP", - .desc = "Sun4m platform, SPARCserver 600MP", - .init = ss600mp_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine ss20_machine = { - .name = "SS-20", - .desc = "Sun4m platform, SPARCstation 20", - .init = ss20_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine voyager_machine = { - .name = "Voyager", - .desc = "Sun4m platform, SPARCstation Voyager", - .init = vger_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine ss_lx_machine = { - .name = "LX", - .desc = "Sun4m platform, SPARCstation LX", - .init = ss_lx_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine ss4_machine = { - .name = "SS-4", - .desc = "Sun4m platform, SPARCstation 4", - .init = ss4_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine scls_machine = { - .name = "SPARCClassic", - .desc = "Sun4m platform, SPARCClassic", - .init = scls_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine sbook_machine = { - .name = "SPARCbook", - .desc = "Sun4m platform, SPARCbook", - .init = sbook_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static const struct sun4d_hwdef sun4d_hwdefs[] = { - /* SS-1000 */ - { - .iounit_bases = { - 0xfe0200000ULL, - 0xfe1200000ULL, - 0xfe2200000ULL, - 0xfe3200000ULL, - -1, - }, - .tcx_base = 0x820000000ULL, - .slavio_base = 0xf00000000ULL, - .ms_kb_base = 0xf00240000ULL, - .serial_base = 0xf00200000ULL, - .nvram_base = 0xf00280000ULL, - .counter_base = 0xf00300000ULL, - .espdma_base = 0x800081000ULL, - .esp_base = 0x800080000ULL, - .ledma_base = 0x800040000ULL, - .le_base = 0x800060000ULL, - .sbi_base = 0xf02800000ULL, - .nvram_machine_id = 0x80, - .machine_id = ss1000_id, - .iounit_version = 0x03000000, - .max_mem = 0xf00000000ULL, - .default_cpu_model = "TI SuperSparc II", - }, - /* SS-2000 */ - { - .iounit_bases = { - 0xfe0200000ULL, - 0xfe1200000ULL, - 0xfe2200000ULL, - 0xfe3200000ULL, - 0xfe4200000ULL, - }, - .tcx_base = 0x820000000ULL, - .slavio_base = 0xf00000000ULL, - .ms_kb_base = 0xf00240000ULL, - .serial_base = 0xf00200000ULL, - .nvram_base = 0xf00280000ULL, - .counter_base = 0xf00300000ULL, - .espdma_base = 0x800081000ULL, - .esp_base = 0x800080000ULL, - .ledma_base = 0x800040000ULL, - .le_base = 0x800060000ULL, - .sbi_base = 0xf02800000ULL, - .nvram_machine_id = 0x80, - .machine_id = ss2000_id, - .iounit_version = 0x03000000, - .max_mem = 0xf00000000ULL, - .default_cpu_model = "TI SuperSparc II", - }, -}; - -static DeviceState *sbi_init(hwaddr addr, qemu_irq **parent_irq) -{ - DeviceState *dev; - SysBusDevice *s; - unsigned int i; - - dev = qdev_create(NULL, "sbi"); - qdev_init_nofail(dev); - - s = SYS_BUS_DEVICE(dev); - - for (i = 0; i < MAX_CPUS; i++) { - sysbus_connect_irq(s, i, *parent_irq[i]); - } - - sysbus_mmio_map(s, 0, addr); - - return dev; -} - -static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - unsigned int i; - void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram; - qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS], - espdma_irq, ledma_irq; - qemu_irq esp_reset, dma_enable; - unsigned long kernel_size; - void *fw_cfg; - DeviceState *dev; - - /* init CPUs */ - if (!cpu_model) - cpu_model = hwdef->default_cpu_model; - - for(i = 0; i < smp_cpus; i++) { - cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]); - } - - for (i = smp_cpus; i < MAX_CPUS; i++) - cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); - - /* set up devices */ - ram_init(0, RAM_size, hwdef->max_mem); - - prom_init(hwdef->slavio_base, bios_name); - - dev = sbi_init(hwdef->sbi_base, cpu_irqs); - - for (i = 0; i < 32; i++) { - sbi_irq[i] = qdev_get_gpio_in(dev, i); - } - for (i = 0; i < MAX_CPUS; i++) { - sbi_cpu_irq[i] = qdev_get_gpio_in(dev, 32 + i); - } - - for (i = 0; i < MAX_IOUNITS; i++) - if (hwdef->iounit_bases[i] != (hwaddr)-1) - iounits[i] = iommu_init(hwdef->iounit_bases[i], - hwdef->iounit_version, - sbi_irq[0]); - - espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[3], - iounits[0], &espdma_irq, 0); - - /* should be lebuffer instead */ - ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[4], - iounits[0], &ledma_irq, 0); - - if (graphic_depth != 8 && graphic_depth != 24) { - fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); - exit (1); - } - tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, - graphic_depth); - - lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); - - nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0, 0x2000, 8); - - slavio_timer_init_all(hwdef->counter_base, sbi_irq[10], sbi_cpu_irq, smp_cpus); - - slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[12], - display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); - /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device - Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ - escc_init(hwdef->serial_base, sbi_irq[12], sbi_irq[12], - serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); - - if (drive_get_max_bus(IF_SCSI) > 0) { - fprintf(stderr, "qemu: too many SCSI bus\n"); - exit(1); - } - - esp_init(hwdef->esp_base, 2, - espdma_memory_read, espdma_memory_write, - espdma, espdma_irq, &esp_reset, &dma_enable); - - qdev_connect_gpio_out(espdma, 0, esp_reset); - qdev_connect_gpio_out(espdma, 1, dma_enable); - - kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, - RAM_size); - - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, - boot_device, RAM_size, kernel_size, graphic_width, - graphic_height, graphic_depth, hwdef->nvram_machine_id, - "Sun4d"); - - fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); - fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); - fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); - fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); - fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); - } - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]); - qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); -} - -/* SPARCserver 1000 hardware initialisation */ -static void ss1000_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -/* SPARCcenter 2000 hardware initialisation */ -static void ss2000_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -static QEMUMachine ss1000_machine = { - .name = "SS-1000", - .desc = "Sun4d platform, SPARCserver 1000", - .init = ss1000_init, - .block_default_type = IF_SCSI, - .max_cpus = 8, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine ss2000_machine = { - .name = "SS-2000", - .desc = "Sun4d platform, SPARCcenter 2000", - .init = ss2000_init, - .block_default_type = IF_SCSI, - .max_cpus = 20, - DEFAULT_MACHINE_OPTIONS, -}; - -static const struct sun4c_hwdef sun4c_hwdefs[] = { - /* SS-2 */ - { - .iommu_base = 0xf8000000, - .tcx_base = 0xfe000000, - .slavio_base = 0xf6000000, - .intctl_base = 0xf5000000, - .counter_base = 0xf3000000, - .ms_kb_base = 0xf0000000, - .serial_base = 0xf1000000, - .nvram_base = 0xf2000000, - .fd_base = 0xf7200000, - .dma_base = 0xf8400000, - .esp_base = 0xf8800000, - .le_base = 0xf8c00000, - .aux1_base = 0xf7400003, - .nvram_machine_id = 0x55, - .machine_id = ss2_id, - .max_mem = 0x10000000, - .default_cpu_model = "Cypress CY7C601", - }, -}; - -static DeviceState *sun4c_intctl_init(hwaddr addr, - qemu_irq *parent_irq) -{ - DeviceState *dev; - SysBusDevice *s; - unsigned int i; - - dev = qdev_create(NULL, "sun4c_intctl"); - qdev_init_nofail(dev); - - s = SYS_BUS_DEVICE(dev); - - for (i = 0; i < MAX_PILS; i++) { - sysbus_connect_irq(s, i, parent_irq[i]); - } - sysbus_mmio_map(s, 0, addr); - - return dev; -} - -static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - void *iommu, *espdma, *ledma, *nvram; - qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq; - qemu_irq esp_reset, dma_enable; - qemu_irq fdc_tc; - unsigned long kernel_size; - DriveInfo *fd[MAX_FD]; - void *fw_cfg; - DeviceState *dev; - unsigned int i; - - /* init CPU */ - if (!cpu_model) - cpu_model = hwdef->default_cpu_model; - - cpu_devinit(cpu_model, 0, hwdef->slavio_base, &cpu_irqs); - - /* set up devices */ - ram_init(0, RAM_size, hwdef->max_mem); - - prom_init(hwdef->slavio_base, bios_name); - - dev = sun4c_intctl_init(hwdef->intctl_base, cpu_irqs); - - for (i = 0; i < 8; i++) { - slavio_irq[i] = qdev_get_gpio_in(dev, i); - } - - iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, - slavio_irq[1]); - - espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[2], - iommu, &espdma_irq, 0); - - ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, - slavio_irq[3], iommu, &ledma_irq, 1); - - if (graphic_depth != 8 && graphic_depth != 24) { - fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); - exit (1); - } - tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, - graphic_depth); - - lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); - - nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x800, 2); - - slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[1], - display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); - /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device - Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ - escc_init(hwdef->serial_base, slavio_irq[1], - slavio_irq[1], serial_hds[0], serial_hds[1], - ESCC_CLOCK, 1); - - if (hwdef->fd_base != (hwaddr)-1) { - /* there is zero or one floppy drive */ - memset(fd, 0, sizeof(fd)); - fd[0] = drive_get(IF_FLOPPY, 0, 0); - sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd, - &fdc_tc); - } else { - fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1); - } - - slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc); - - if (drive_get_max_bus(IF_SCSI) > 0) { - fprintf(stderr, "qemu: too many SCSI bus\n"); - exit(1); - } - - esp_init(hwdef->esp_base, 2, - espdma_memory_read, espdma_memory_write, - espdma, espdma_irq, &esp_reset, &dma_enable); - - qdev_connect_gpio_out(espdma, 0, esp_reset); - qdev_connect_gpio_out(espdma, 1, dma_enable); - - kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename, - RAM_size); - - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, - boot_device, RAM_size, kernel_size, graphic_width, - graphic_height, graphic_depth, hwdef->nvram_machine_id, - "Sun4c"); - - fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); - fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); - fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); - fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); - fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); - } - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]); - qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); -} - -/* SPARCstation 2 hardware initialisation */ -static void ss2_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); -} - -static QEMUMachine ss2_machine = { - .name = "SS-2", - .desc = "Sun4c platform, SPARCstation 2", - .init = ss2_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static void sun4m_register_types(void) -{ - type_register_static(&idreg_info); - type_register_static(&afx_info); - type_register_static(&prom_info); - type_register_static(&ram_info); -} - -static void ss2_machine_init(void) -{ - qemu_register_machine(&ss5_machine); - qemu_register_machine(&ss10_machine); - qemu_register_machine(&ss600mp_machine); - qemu_register_machine(&ss20_machine); - qemu_register_machine(&voyager_machine); - qemu_register_machine(&ss_lx_machine); - qemu_register_machine(&ss4_machine); - qemu_register_machine(&scls_machine); - qemu_register_machine(&sbook_machine); - qemu_register_machine(&ss1000_machine); - qemu_register_machine(&ss2000_machine); - qemu_register_machine(&ss2_machine); -} - -type_init(sun4m_register_types) -machine_init(ss2_machine_init); diff --git a/hw/sun4u.c b/hw/sun4u.c deleted file mode 100644 index 51ffa1c09b..0000000000 --- a/hw/sun4u.c +++ /dev/null @@ -1,1014 +0,0 @@ -/* - * QEMU Sun4u/Sun4v System Emulator - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/pci/pci.h" -#include "hw/apb_pci.h" -#include "hw/pc.h" -#include "hw/serial.h" -#include "hw/nvram.h" -#include "hw/fdc.h" -#include "net/net.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/firmware_abi.h" -#include "hw/fw_cfg.h" -#include "hw/sysbus.h" -#include "hw/ide.h" -#include "hw/loader.h" -#include "elf.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" - -//#define DEBUG_IRQ -//#define DEBUG_EBUS -//#define DEBUG_TIMER - -#ifdef DEBUG_IRQ -#define CPUIRQ_DPRINTF(fmt, ...) \ - do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0) -#else -#define CPUIRQ_DPRINTF(fmt, ...) -#endif - -#ifdef DEBUG_EBUS -#define EBUS_DPRINTF(fmt, ...) \ - do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0) -#else -#define EBUS_DPRINTF(fmt, ...) -#endif - -#ifdef DEBUG_TIMER -#define TIMER_DPRINTF(fmt, ...) \ - do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0) -#else -#define TIMER_DPRINTF(fmt, ...) -#endif - -#define KERNEL_LOAD_ADDR 0x00404000 -#define CMDLINE_ADDR 0x003ff000 -#define PROM_SIZE_MAX (4 * 1024 * 1024) -#define PROM_VADDR 0x000ffd00000ULL -#define APB_SPECIAL_BASE 0x1fe00000000ULL -#define APB_MEM_BASE 0x1ff00000000ULL -#define APB_PCI_IO_BASE (APB_SPECIAL_BASE + 0x02000000ULL) -#define PROM_FILENAME "openbios-sparc64" -#define NVRAM_SIZE 0x2000 -#define MAX_IDE_BUS 2 -#define BIOS_CFG_IOPORT 0x510 -#define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) -#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) -#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) - -#define IVEC_MAX 0x30 - -#define TICK_MAX 0x7fffffffffffffffULL - -struct hwdef { - const char * const default_cpu_model; - uint16_t machine_id; - uint64_t prom_addr; - uint64_t console_serial_base; -}; - -typedef struct EbusState { - PCIDevice pci_dev; - MemoryRegion bar0; - MemoryRegion bar1; -} EbusState; - -int DMA_get_channel_mode (int nchan) -{ - return 0; -} -int DMA_read_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -int DMA_write_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -void DMA_hold_DREQ (int nchan) {} -void DMA_release_DREQ (int nchan) {} -void DMA_schedule(int nchan) {} - -void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) -{ -} - -void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, - void *opaque) -{ -} - -static int fw_cfg_boot_set(void *opaque, const char *boot_device) -{ - fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); - return 0; -} - -static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size, - const char *arch, ram_addr_t RAM_size, - const char *boot_devices, - uint32_t kernel_image, uint32_t kernel_size, - const char *cmdline, - uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image, - int width, int height, int depth, - const uint8_t *macaddr) -{ - unsigned int i; - uint32_t start, end; - uint8_t image[0x1ff0]; - struct OpenBIOS_nvpart_v1 *part_header; - - memset(image, '\0', sizeof(image)); - - start = 0; - - // OpenBIOS nvram variables - // Variable partition - part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; - part_header->signature = OPENBIOS_PART_SYSTEM; - pstrcpy(part_header->name, sizeof(part_header->name), "system"); - - end = start + sizeof(struct OpenBIOS_nvpart_v1); - for (i = 0; i < nb_prom_envs; i++) - end = OpenBIOS_set_var(image, end, prom_envs[i]); - - // End marker - image[end++] = '\0'; - - end = start + ((end - start + 15) & ~15); - OpenBIOS_finish_partition(part_header, end - start); - - // free partition - start = end; - part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; - part_header->signature = OPENBIOS_PART_FREE; - pstrcpy(part_header->name, sizeof(part_header->name), "free"); - - end = 0x1fd0; - OpenBIOS_finish_partition(part_header, end - start); - - Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80); - - for (i = 0; i < sizeof(image); i++) - m48t59_write(nvram, i, image[i]); - - return 0; -} - -static uint64_t sun4u_load_kernel(const char *kernel_filename, - const char *initrd_filename, - ram_addr_t RAM_size, uint64_t *initrd_size, - uint64_t *initrd_addr, uint64_t *kernel_addr, - uint64_t *kernel_entry) -{ - int linux_boot; - unsigned int i; - long kernel_size; - uint8_t *ptr; - uint64_t kernel_top; - - linux_boot = (kernel_filename != NULL); - - kernel_size = 0; - if (linux_boot) { - int bswap_needed; - -#ifdef BSWAP_NEEDED - bswap_needed = 1; -#else - bswap_needed = 0; -#endif - kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry, - kernel_addr, &kernel_top, 1, ELF_MACHINE, 0); - if (kernel_size < 0) { - *kernel_addr = KERNEL_LOAD_ADDR; - *kernel_entry = KERNEL_LOAD_ADDR; - kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, - RAM_size - KERNEL_LOAD_ADDR, bswap_needed, - TARGET_PAGE_SIZE); - } - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - RAM_size - KERNEL_LOAD_ADDR); - } - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - /* load initrd above kernel */ - *initrd_size = 0; - if (initrd_filename) { - *initrd_addr = TARGET_PAGE_ALIGN(kernel_top); - - *initrd_size = load_image_targphys(initrd_filename, - *initrd_addr, - RAM_size - *initrd_addr); - if ((int)*initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (*initrd_size > 0) { - for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - ptr = rom_ptr(*kernel_addr + i); - if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ - stl_p(ptr + 24, *initrd_addr + *kernel_addr); - stl_p(ptr + 28, *initrd_size); - break; - } - } - } - } - return kernel_size; -} - -void cpu_check_irqs(CPUSPARCState *env) -{ - uint32_t pil = env->pil_in | - (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER)); - - /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */ - if (env->ivec_status & 0x20) { - return; - } - /* check if TM or SM in SOFTINT are set - setting these also causes interrupt 14 */ - if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) { - pil |= 1 << 14; - } - - /* The bit corresponding to psrpil is (1<< psrpil), the next bit - is (2 << psrpil). */ - if (pil < (2 << env->psrpil)){ - if (env->interrupt_request & CPU_INTERRUPT_HARD) { - CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n", - env->interrupt_index); - env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } - return; - } - - if (cpu_interrupts_enabled(env)) { - - unsigned int i; - - for (i = 15; i > env->psrpil; i--) { - if (pil & (1 << i)) { - int old_interrupt = env->interrupt_index; - int new_interrupt = TT_EXTINT | i; - - if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt - && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) { - CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d " - "current %x >= pending %x\n", - env->tl, cpu_tsptr(env)->tt, new_interrupt); - } else if (old_interrupt != new_interrupt) { - env->interrupt_index = new_interrupt; - CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i, - old_interrupt, new_interrupt); - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - break; - } - } - } else if (env->interrupt_request & CPU_INTERRUPT_HARD) { - CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x " - "current interrupt %x\n", - pil, env->pil_in, env->softint, env->interrupt_index); - env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -static void cpu_kick_irq(SPARCCPU *cpu) -{ - CPUSPARCState *env = &cpu->env; - - env->halted = 0; - cpu_check_irqs(env); - qemu_cpu_kick(CPU(cpu)); -} - -static void cpu_set_ivec_irq(void *opaque, int irq, int level) -{ - SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; - - if (level) { - if (!(env->ivec_status & 0x20)) { - CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq); - env->halted = 0; - env->interrupt_index = TT_IVEC; - env->ivec_status |= 0x20; - env->ivec_data[0] = (0x1f << 6) | irq; - env->ivec_data[1] = 0; - env->ivec_data[2] = 0; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - } else { - if (env->ivec_status & 0x20) { - CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq); - env->ivec_status &= ~0x20; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } - } -} - -typedef struct ResetData { - SPARCCPU *cpu; - uint64_t prom_addr; -} ResetData; - -void cpu_put_timer(QEMUFile *f, CPUTimer *s) -{ - qemu_put_be32s(f, &s->frequency); - qemu_put_be32s(f, &s->disabled); - qemu_put_be64s(f, &s->disabled_mask); - qemu_put_sbe64s(f, &s->clock_offset); - - qemu_put_timer(f, s->qtimer); -} - -void cpu_get_timer(QEMUFile *f, CPUTimer *s) -{ - qemu_get_be32s(f, &s->frequency); - qemu_get_be32s(f, &s->disabled); - qemu_get_be64s(f, &s->disabled_mask); - qemu_get_sbe64s(f, &s->clock_offset); - - qemu_get_timer(f, s->qtimer); -} - -static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, - QEMUBHFunc *cb, uint32_t frequency, - uint64_t disabled_mask) -{ - CPUTimer *timer = g_malloc0(sizeof (CPUTimer)); - - timer->name = name; - timer->frequency = frequency; - timer->disabled_mask = disabled_mask; - - timer->disabled = 1; - timer->clock_offset = qemu_get_clock_ns(vm_clock); - - timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu); - - return timer; -} - -static void cpu_timer_reset(CPUTimer *timer) -{ - timer->disabled = 1; - timer->clock_offset = qemu_get_clock_ns(vm_clock); - - qemu_del_timer(timer->qtimer); -} - -static void main_cpu_reset(void *opaque) -{ - ResetData *s = (ResetData *)opaque; - CPUSPARCState *env = &s->cpu->env; - static unsigned int nr_resets; - - cpu_reset(CPU(s->cpu)); - - cpu_timer_reset(env->tick); - cpu_timer_reset(env->stick); - cpu_timer_reset(env->hstick); - - env->gregs[1] = 0; // Memory start - env->gregs[2] = ram_size; // Memory size - env->gregs[3] = 0; // Machine description XXX - if (nr_resets++ == 0) { - /* Power on reset */ - env->pc = s->prom_addr + 0x20ULL; - } else { - env->pc = s->prom_addr + 0x40ULL; - } - env->npc = env->pc + 4; -} - -static void tick_irq(void *opaque) -{ - SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; - - CPUTimer* timer = env->tick; - - if (timer->disabled) { - CPUIRQ_DPRINTF("tick_irq: softint disabled\n"); - return; - } else { - CPUIRQ_DPRINTF("tick: fire\n"); - } - - env->softint |= SOFTINT_TIMER; - cpu_kick_irq(cpu); -} - -static void stick_irq(void *opaque) -{ - SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; - - CPUTimer* timer = env->stick; - - if (timer->disabled) { - CPUIRQ_DPRINTF("stick_irq: softint disabled\n"); - return; - } else { - CPUIRQ_DPRINTF("stick: fire\n"); - } - - env->softint |= SOFTINT_STIMER; - cpu_kick_irq(cpu); -} - -static void hstick_irq(void *opaque) -{ - SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; - - CPUTimer* timer = env->hstick; - - if (timer->disabled) { - CPUIRQ_DPRINTF("hstick_irq: softint disabled\n"); - return; - } else { - CPUIRQ_DPRINTF("hstick: fire\n"); - } - - env->softint |= SOFTINT_STIMER; - cpu_kick_irq(cpu); -} - -static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency) -{ - return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency); -} - -static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency) -{ - return muldiv64(timer_ticks, frequency, get_ticks_per_sec()); -} - -void cpu_tick_set_count(CPUTimer *timer, uint64_t count) -{ - uint64_t real_count = count & ~timer->disabled_mask; - uint64_t disabled_bit = count & timer->disabled_mask; - - int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) - - cpu_to_timer_ticks(real_count, timer->frequency); - - TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n", - timer->name, real_count, - timer->disabled?"disabled":"enabled", timer); - - timer->disabled = disabled_bit ? 1 : 0; - timer->clock_offset = vm_clock_offset; -} - -uint64_t cpu_tick_get_count(CPUTimer *timer) -{ - uint64_t real_count = timer_to_cpu_ticks( - qemu_get_clock_ns(vm_clock) - timer->clock_offset, - timer->frequency); - - TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n", - timer->name, real_count, - timer->disabled?"disabled":"enabled", timer); - - if (timer->disabled) - real_count |= timer->disabled_mask; - - return real_count; -} - -void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) -{ - int64_t now = qemu_get_clock_ns(vm_clock); - - uint64_t real_limit = limit & ~timer->disabled_mask; - timer->disabled = (limit & timer->disabled_mask) ? 1 : 0; - - int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) + - timer->clock_offset; - - if (expires < now) { - expires = now + 1; - } - - TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p " - "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n", - timer->name, real_limit, - timer->disabled?"disabled":"enabled", - timer, limit, - timer_to_cpu_ticks(now - timer->clock_offset, - timer->frequency), - timer_to_cpu_ticks(expires - now, timer->frequency)); - - if (!real_limit) { - TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n", - timer->name); - qemu_del_timer(timer->qtimer); - } else if (timer->disabled) { - qemu_del_timer(timer->qtimer); - } else { - qemu_mod_timer(timer->qtimer, expires); - } -} - -static void isa_irq_handler(void *opaque, int n, int level) -{ - static const int isa_irq_to_ivec[16] = { - [1] = 0x29, /* keyboard */ - [4] = 0x2b, /* serial */ - [6] = 0x27, /* floppy */ - [7] = 0x22, /* parallel */ - [12] = 0x2a, /* mouse */ - }; - qemu_irq *irqs = opaque; - int ivec; - - assert(n < 16); - ivec = isa_irq_to_ivec[n]; - EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec); - if (ivec) { - qemu_set_irq(irqs[ivec], level); - } -} - -/* EBUS (Eight bit bus) bridge */ -static ISABus * -pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs) -{ - qemu_irq *isa_irq; - PCIDevice *pci_dev; - ISABus *isa_bus; - - pci_dev = pci_create_simple(bus, devfn, "ebus"); - isa_bus = DO_UPCAST(ISABus, qbus, - qdev_get_child_bus(&pci_dev->qdev, "isa.0")); - isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16); - isa_bus_irqs(isa_bus, isa_irq); - return isa_bus; -} - -static int -pci_ebus_init1(PCIDevice *pci_dev) -{ - EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev); - - isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev)); - - pci_dev->config[0x04] = 0x06; // command = bus master, pci mem - pci_dev->config[0x05] = 0x00; - pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error - pci_dev->config[0x07] = 0x03; // status = medium devsel - pci_dev->config[0x09] = 0x00; // programming i/f - pci_dev->config[0x0D] = 0x0a; // latency_timer - - isa_mmio_setup(&s->bar0, 0x1000000); - pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0); - isa_mmio_setup(&s->bar1, 0x800000); - pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1); - return 0; -} - -static void ebus_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = pci_ebus_init1; - k->vendor_id = PCI_VENDOR_ID_SUN; - k->device_id = PCI_DEVICE_ID_SUN_EBUS; - k->revision = 0x01; - k->class_id = PCI_CLASS_BRIDGE_OTHER; -} - -static const TypeInfo ebus_info = { - .name = "ebus", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EbusState), - .class_init = ebus_class_init, -}; - -typedef struct PROMState { - SysBusDevice busdev; - MemoryRegion prom; -} PROMState; - -static uint64_t translate_prom_address(void *opaque, uint64_t addr) -{ - hwaddr *base_addr = (hwaddr *)opaque; - return addr + *base_addr - PROM_VADDR; -} - -/* Boot PROM (OpenBIOS) */ -static void prom_init(hwaddr addr, const char *bios_name) -{ - DeviceState *dev; - SysBusDevice *s; - char *filename; - int ret; - - dev = qdev_create(NULL, "openprom"); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - - sysbus_mmio_map(s, 0, addr); - - /* load boot prom */ - if (bios_name == NULL) { - bios_name = PROM_FILENAME; - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - ret = load_elf(filename, translate_prom_address, &addr, - NULL, NULL, NULL, 1, ELF_MACHINE, 0); - if (ret < 0 || ret > PROM_SIZE_MAX) { - ret = load_image_targphys(filename, addr, PROM_SIZE_MAX); - } - g_free(filename); - } else { - ret = -1; - } - if (ret < 0 || ret > PROM_SIZE_MAX) { - fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name); - exit(1); - } -} - -static int prom_init1(SysBusDevice *dev) -{ - PROMState *s = FROM_SYSBUS(PROMState, dev); - - memory_region_init_ram(&s->prom, "sun4u.prom", PROM_SIZE_MAX); - vmstate_register_ram_global(&s->prom); - memory_region_set_readonly(&s->prom, true); - sysbus_init_mmio(dev, &s->prom); - return 0; -} - -static Property prom_properties[] = { - {/* end of property list */}, -}; - -static void prom_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = prom_init1; - dc->props = prom_properties; -} - -static const TypeInfo prom_info = { - .name = "openprom", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PROMState), - .class_init = prom_class_init, -}; - - -typedef struct RamDevice -{ - SysBusDevice busdev; - MemoryRegion ram; - uint64_t size; -} RamDevice; - -/* System RAM */ -static int ram_init1(SysBusDevice *dev) -{ - RamDevice *d = FROM_SYSBUS(RamDevice, dev); - - memory_region_init_ram(&d->ram, "sun4u.ram", d->size); - vmstate_register_ram_global(&d->ram); - sysbus_init_mmio(dev, &d->ram); - return 0; -} - -static void ram_init(hwaddr addr, ram_addr_t RAM_size) -{ - DeviceState *dev; - SysBusDevice *s; - RamDevice *d; - - /* allocate RAM */ - dev = qdev_create(NULL, "memory"); - s = SYS_BUS_DEVICE(dev); - - d = FROM_SYSBUS(RamDevice, s); - d->size = RAM_size; - qdev_init_nofail(dev); - - sysbus_mmio_map(s, 0, addr); -} - -static Property ram_properties[] = { - DEFINE_PROP_UINT64("size", RamDevice, size, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void ram_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = ram_init1; - dc->props = ram_properties; -} - -static const TypeInfo ram_info = { - .name = "memory", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(RamDevice), - .class_init = ram_class_init, -}; - -static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) -{ - SPARCCPU *cpu; - CPUSPARCState *env; - ResetData *reset_info; - - uint32_t tick_frequency = 100*1000000; - uint32_t stick_frequency = 100*1000000; - uint32_t hstick_frequency = 100*1000000; - - if (cpu_model == NULL) { - cpu_model = hwdef->default_cpu_model; - } - cpu = cpu_sparc_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find Sparc CPU definition\n"); - exit(1); - } - env = &cpu->env; - - env->tick = cpu_timer_create("tick", cpu, tick_irq, - tick_frequency, TICK_NPT_MASK); - - env->stick = cpu_timer_create("stick", cpu, stick_irq, - stick_frequency, TICK_INT_DIS); - - env->hstick = cpu_timer_create("hstick", cpu, hstick_irq, - hstick_frequency, TICK_INT_DIS); - - reset_info = g_malloc0(sizeof(ResetData)); - reset_info->cpu = cpu; - reset_info->prom_addr = hwdef->prom_addr; - qemu_register_reset(main_cpu_reset, reset_info); - - return cpu; -} - -static void sun4uv_init(MemoryRegion *address_space_mem, - ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model, - const struct hwdef *hwdef) -{ - SPARCCPU *cpu; - M48t59State *nvram; - unsigned int i; - uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; - PCIBus *pci_bus, *pci_bus2, *pci_bus3; - ISABus *isa_bus; - qemu_irq *ivec_irqs, *pbm_irqs; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DriveInfo *fd[MAX_FD]; - void *fw_cfg; - - /* init CPUs */ - cpu = cpu_devinit(cpu_model, hwdef); - - /* set up devices */ - ram_init(0, RAM_size); - - prom_init(hwdef->prom_addr, bios_name); - - ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX); - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, - &pci_bus3, &pbm_irqs); - pci_vga_init(pci_bus); - - // XXX Should be pci_bus3 - isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs); - - i = 0; - if (hwdef->console_serial_base) { - serial_mm_init(address_space_mem, hwdef->console_serial_base, 0, - NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN); - i++; - } - for(; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_hds[i]) { - parallel_init(isa_bus, i, parallel_hds[i]); - } - } - - for(i = 0; i < nb_nics; i++) - pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); - - ide_drive_get(hd, MAX_IDE_BUS); - - pci_cmd646_ide_init(pci_bus, hd, 1); - - isa_create_simple(isa_bus, "i8042"); - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - } - fdctrl_init_isa(isa_bus, fd); - nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59); - - initrd_size = 0; - initrd_addr = 0; - kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename, - ram_size, &initrd_size, &initrd_addr, - &kernel_addr, &kernel_entry); - - sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices, - kernel_addr, kernel_size, - kernel_cmdline, - initrd_addr, initrd_size, - /* XXX: need an option to load a NVRAM image */ - 0, - graphic_width, graphic_height, graphic_depth, - (uint8_t *)&nd_table[0].macaddr); - - fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); - fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); - fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); - fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); - fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); - fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(kernel_cmdline) + 1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); - } - fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); - fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]); - - fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); - fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height); - fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH, graphic_depth); - - qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); -} - -enum { - sun4u_id = 0, - sun4v_id = 64, - niagara_id, -}; - -static const struct hwdef hwdefs[] = { - /* Sun4u generic PC-like machine */ - { - .default_cpu_model = "TI UltraSparc IIi", - .machine_id = sun4u_id, - .prom_addr = 0x1fff0000000ULL, - .console_serial_base = 0, - }, - /* Sun4v generic PC-like machine */ - { - .default_cpu_model = "Sun UltraSparc T1", - .machine_id = sun4v_id, - .prom_addr = 0x1fff0000000ULL, - .console_serial_base = 0, - }, - /* Sun4v generic Niagara machine */ - { - .default_cpu_model = "Sun UltraSparc T1", - .machine_id = niagara_id, - .prom_addr = 0xfff0000000ULL, - .console_serial_base = 0xfff0c2c000ULL, - }, -}; - -/* Sun4u hardware initialisation */ -static void sun4u_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_devices = args->boot_device; - sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]); -} - -/* Sun4v hardware initialisation */ -static void sun4v_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_devices = args->boot_device; - sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]); -} - -/* Niagara hardware initialisation */ -static void niagara_init(QEMUMachineInitArgs *args) -{ - ram_addr_t RAM_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_devices = args->boot_device; - sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]); -} - -static QEMUMachine sun4u_machine = { - .name = "sun4u", - .desc = "Sun4u platform", - .init = sun4u_init, - .max_cpus = 1, // XXX for now - .is_default = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine sun4v_machine = { - .name = "sun4v", - .desc = "Sun4v platform", - .init = sun4v_init, - .max_cpus = 1, // XXX for now - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine niagara_machine = { - .name = "Niagara", - .desc = "Sun4v platform, Niagara", - .init = niagara_init, - .max_cpus = 1, // XXX for now - DEFAULT_MACHINE_OPTIONS, -}; - -static void sun4u_register_types(void) -{ - type_register_static(&ebus_info); - type_register_static(&prom_info); - type_register_static(&ram_info); -} - -static void sun4u_machine_init(void) -{ - qemu_register_machine(&sun4u_machine); - qemu_register_machine(&sun4v_machine); - qemu_register_machine(&niagara_machine); -} - -type_init(sun4u_register_types) -machine_init(sun4u_machine_init); diff --git a/hw/tosa.c b/hw/tosa.c deleted file mode 100644 index 747888c64e..0000000000 --- a/hw/tosa.c +++ /dev/null @@ -1,302 +0,0 @@ -/* vim:set shiftwidth=4 ts=4 et: */ -/* - * PXA255 Sharp Zaurus SL-6000 PDA platform - * - * Copyright (c) 2008 Dmitry Baryshkov - * - * Code based on spitz platform by Andrzej Zaborowski - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "hw/hw.h" -#include "hw/pxa.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "hw/sharpsl.h" -#include "hw/pcmcia.h" -#include "block/block.h" -#include "hw/boards.h" -#include "hw/i2c.h" -#include "hw/ssi.h" -#include "sysemu/blockdev.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -#define TOSA_RAM 0x04000000 -#define TOSA_ROM 0x00800000 - -#define TOSA_GPIO_USB_IN (5) -#define TOSA_GPIO_nSD_DETECT (9) -#define TOSA_GPIO_ON_RESET (19) -#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */ -#define TOSA_GPIO_CF_CD (13) -#define TOSA_GPIO_TC6393XB_INT (15) -#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */ - -#define TOSA_SCOOP_GPIO_BASE 1 -#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2) -#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3) -#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4) - -#define TOSA_SCOOP_JC_GPIO_BASE 1 -#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0) -#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1) -#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2) -#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5) -#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7) - -#define DAC_BASE 0x4e -#define DAC_CH1 0 -#define DAC_CH2 1 - -static void tosa_microdrive_attach(PXA2xxState *cpu) -{ - PCMCIACardState *md; - DriveInfo *dinfo; - - dinfo = drive_get(IF_IDE, 0, 0); - if (!dinfo || dinfo->media_cd) - return; - md = dscm1xxxx_init(dinfo); - pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); -} - -static void tosa_out_switch(void *opaque, int line, int level) -{ - switch (line) { - case 0: - fprintf(stderr, "blue LED %s.\n", level ? "on" : "off"); - break; - case 1: - fprintf(stderr, "green LED %s.\n", level ? "on" : "off"); - break; - case 2: - fprintf(stderr, "amber LED %s.\n", level ? "on" : "off"); - break; - case 3: - fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off"); - break; - default: - fprintf(stderr, "Uhandled out event: %d = %d\n", line, level); - break; - } -} - - -static void tosa_gpio_setup(PXA2xxState *cpu, - DeviceState *scp0, - DeviceState *scp1, - TC6393xbState *tmio) -{ - qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4); - /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, - qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP), - qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT))); - - /* Handle reset */ - qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset); - - /* PCMCIA signals: card's IRQ and Card-Detect */ - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ), - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD)); - - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ), - NULL); - - qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]); - - qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio)); - - /* UDC Vbus */ - qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN)); -} - -static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value) -{ - fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f); - return 0; -} - -static int tosa_ssp_init(SSISlave *dev) -{ - /* Nothing to do. */ - return 0; -} - -typedef struct { - I2CSlave i2c; - int len; - char buf[3]; -} TosaDACState; - -static int tosa_dac_send(I2CSlave *i2c, uint8_t data) -{ - TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c); - s->buf[s->len] = data; - if (s->len ++ > 2) { -#ifdef VERBOSE - fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len); -#endif - return 1; - } - - if (s->len == 2) { - fprintf(stderr, "dac: channel %d value 0x%02x\n", - s->buf[0], s->buf[1]); - } - - return 0; -} - -static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) -{ - TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c); - s->len = 0; - switch (event) { - case I2C_START_SEND: - break; - case I2C_START_RECV: - printf("%s: recv not supported!!!\n", __FUNCTION__); - break; - case I2C_FINISH: -#ifdef VERBOSE - if (s->len < 2) - printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len); - if (s->len > 2) - printf("%s: message too long\n", __FUNCTION__); -#endif - break; - default: - break; - } -} - -static int tosa_dac_recv(I2CSlave *s) -{ - printf("%s: recv not supported!!!\n", __FUNCTION__); - return -1; -} - -static int tosa_dac_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - -static void tosa_tg_init(PXA2xxState *cpu) -{ - i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); - i2c_create_slave(bus, "tosa_dac", DAC_BASE); - ssi_create_slave(cpu->ssp[1], "tosa-ssp"); -} - - -static struct arm_boot_info tosa_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = 0x04000000, -}; - -static void tosa_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *rom = g_new(MemoryRegion, 1); - PXA2xxState *mpu; - TC6393xbState *tmio; - DeviceState *scp0, *scp1; - - if (!cpu_model) - cpu_model = "pxa255"; - - mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); - - memory_region_init_ram(rom, "tosa.rom", TOSA_ROM); - vmstate_register_ram_global(rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(address_space_mem, 0, rom); - - tmio = tc6393xb_init(address_space_mem, 0x10000000, - qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT)); - - scp0 = sysbus_create_simple("scoop", 0x08800000, NULL); - scp1 = sysbus_create_simple("scoop", 0x14800040, NULL); - - tosa_gpio_setup(mpu, scp0, scp1, tmio); - - tosa_microdrive_attach(mpu); - - tosa_tg_init(mpu); - - tosa_binfo.kernel_filename = kernel_filename; - tosa_binfo.kernel_cmdline = kernel_cmdline; - tosa_binfo.initrd_filename = initrd_filename; - tosa_binfo.board_id = 0x208; - arm_load_kernel(mpu->cpu, &tosa_binfo); - sl_bootparam_write(SL_PXA_PARAM_BASE); -} - -static QEMUMachine tosapda_machine = { - .name = "tosa", - .desc = "Tosa PDA (PXA255)", - .init = tosa_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void tosapda_machine_init(void) -{ - qemu_register_machine(&tosapda_machine); -} - -machine_init(tosapda_machine_init); - -static void tosa_dac_class_init(ObjectClass *klass, void *data) -{ - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = tosa_dac_init; - k->event = tosa_dac_event; - k->recv = tosa_dac_recv; - k->send = tosa_dac_send; -} - -static const TypeInfo tosa_dac_info = { - .name = "tosa_dac", - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(TosaDACState), - .class_init = tosa_dac_class_init, -}; - -static void tosa_ssp_class_init(ObjectClass *klass, void *data) -{ - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = tosa_ssp_init; - k->transfer = tosa_ssp_tansfer; -} - -static const TypeInfo tosa_ssp_info = { - .name = "tosa-ssp", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(SSISlave), - .class_init = tosa_ssp_class_init, -}; - -static void tosa_register_types(void) -{ - type_register_static(&tosa_dac_info); - type_register_static(&tosa_ssp_info); -} - -type_init(tosa_register_types) diff --git a/hw/unicore32/Makefile.objs b/hw/unicore32/Makefile.objs index 0725ce3ca7..e0fd628523 100644 --- a/hw/unicore32/Makefile.objs +++ b/hw/unicore32/Makefile.objs @@ -2,5 +2,3 @@ # PKUnity-v3 SoC and board information obj-${CONFIG_PUV3} += puv3.o - -obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c new file mode 100644 index 0000000000..f9d0c2bab1 --- /dev/null +++ b/hw/unicore32/puv3.c @@ -0,0 +1,135 @@ +/* + * Generic PKUnity SoC machine and board descriptor + * + * Copyright (C) 2010-2012 Guan Xuetao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation, or any later version. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-common.h" +#include "ui/console.h" +#include "elf.h" +#include "exec/address-spaces.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/pc.h" + +#undef DEBUG_PUV3 +#include "hw/puv3.h" + +#define KERNEL_LOAD_ADDR 0x03000000 +#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ + +static void puv3_intc_cpu_handler(void *opaque, int irq, int level) +{ + CPUUniCore32State *env = opaque; + + assert(irq == 0); + if (level) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void puv3_soc_init(CPUUniCore32State *env) +{ + qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR]; + DeviceState *dev; + MemoryRegion *i8042 = g_new(MemoryRegion, 1); + int i; + + /* Initialize interrupt controller */ + cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1); + dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc); + for (i = 0; i < PUV3_IRQS_NR; i++) { + irqs[i] = qdev_get_gpio_in(dev, i); + } + + /* Initialize minimal necessary devices for kernel booting */ + sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL); + sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL); + sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]); + sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE, + irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1], + irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3], + irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5], + irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7], + irqs[PUV3_IRQS_GPIOHIGH], NULL); + + /* Keyboard (i8042), mouse disabled for nographic */ + i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4); + memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042); +} + +static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size) +{ + MemoryRegion *ram_memory = g_new(MemoryRegion, 1); + + /* SDRAM at address zero. */ + memory_region_init_ram(ram_memory, "puv3.ram", ram_size); + vmstate_register_ram_global(ram_memory); + memory_region_add_subregion(get_system_memory(), 0, ram_memory); +} + +static void puv3_load_kernel(const char *kernel_filename) +{ + int size; + + assert(kernel_filename != NULL); + + /* only zImage format supported */ + size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, + KERNEL_MAX_SIZE); + if (size < 0) { + hw_error("Load kernel error: '%s'\n", kernel_filename); + } + + /* cheat curses that we have a graphic console, only under ocd console */ + graphic_console_init(NULL, NULL, NULL, NULL, NULL); +} + +static void puv3_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *initrd_filename = args->initrd_filename; + CPUUniCore32State *env; + + if (initrd_filename) { + hw_error("Please use kernel built-in initramdisk.\n"); + } + + if (!cpu_model) { + cpu_model = "UniCore-II"; + } + + env = cpu_init(cpu_model); + if (!env) { + hw_error("Unable to find CPU definition\n"); + } + + puv3_soc_init(env); + puv3_board_init(env, ram_size); + puv3_load_kernel(kernel_filename); +} + +static QEMUMachine puv3_machine = { + .name = "puv3", + .desc = "PKUnity Version-3 based on UniCore32", + .init = puv3_init, + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, +}; + +static void puv3_machine_init(void) +{ + qemu_register_machine(&puv3_machine); +} + +machine_init(puv3_machine_init) diff --git a/hw/versatilepb.c b/hw/versatilepb.c deleted file mode 100644 index baaa265888..0000000000 --- a/hw/versatilepb.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * ARM Versatile Platform/Application Baseboard System emulation. - * - * Copyright (c) 2005-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/pci/pci.h" -#include "hw/i2c.h" -#include "hw/boards.h" -#include "sysemu/blockdev.h" -#include "exec/address-spaces.h" -#include "hw/flash.h" - -#define VERSATILE_FLASH_ADDR 0x34000000 -#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) -#define VERSATILE_FLASH_SECT_SIZE (256 * 1024) - -/* Primary interrupt controller. */ - -typedef struct vpb_sic_state -{ - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t level; - uint32_t mask; - uint32_t pic_enable; - qemu_irq parent[32]; - int irq; -} vpb_sic_state; - -static const VMStateDescription vmstate_vpb_sic = { - .name = "versatilepb_sic", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(level, vpb_sic_state), - VMSTATE_UINT32(mask, vpb_sic_state), - VMSTATE_UINT32(pic_enable, vpb_sic_state), - VMSTATE_END_OF_LIST() - } -}; - -static void vpb_sic_update(vpb_sic_state *s) -{ - uint32_t flags; - - flags = s->level & s->mask; - qemu_set_irq(s->parent[s->irq], flags != 0); -} - -static void vpb_sic_update_pic(vpb_sic_state *s) -{ - int i; - uint32_t mask; - - for (i = 21; i <= 30; i++) { - mask = 1u << i; - if (!(s->pic_enable & mask)) - continue; - qemu_set_irq(s->parent[i], (s->level & mask) != 0); - } -} - -static void vpb_sic_set_irq(void *opaque, int irq, int level) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - if (level) - s->level |= 1u << irq; - else - s->level &= ~(1u << irq); - if (s->pic_enable & (1u << irq)) - qemu_set_irq(s->parent[irq], level); - vpb_sic_update(s); -} - -static uint64_t vpb_sic_read(void *opaque, hwaddr offset, - unsigned size) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - - switch (offset >> 2) { - case 0: /* STATUS */ - return s->level & s->mask; - case 1: /* RAWSTAT */ - return s->level; - case 2: /* ENABLE */ - return s->mask; - case 4: /* SOFTINT */ - return s->level & 1; - case 8: /* PICENABLE */ - return s->pic_enable; - default: - printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset); - return 0; - } -} - -static void vpb_sic_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - - switch (offset >> 2) { - case 2: /* ENSET */ - s->mask |= value; - break; - case 3: /* ENCLR */ - s->mask &= ~value; - break; - case 4: /* SOFTINTSET */ - if (value) - s->mask |= 1; - break; - case 5: /* SOFTINTCLR */ - if (value) - s->mask &= ~1u; - break; - case 8: /* PICENSET */ - s->pic_enable |= (value & 0x7fe00000); - vpb_sic_update_pic(s); - break; - case 9: /* PICENCLR */ - s->pic_enable &= ~value; - vpb_sic_update_pic(s); - break; - default: - printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset); - return; - } - vpb_sic_update(s); -} - -static const MemoryRegionOps vpb_sic_ops = { - .read = vpb_sic_read, - .write = vpb_sic_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int vpb_sic_init(SysBusDevice *dev) -{ - vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev); - int i; - - qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32); - for (i = 0; i < 32; i++) { - sysbus_init_irq(dev, &s->parent[i]); - } - s->irq = 31; - memory_region_init_io(&s->iomem, &vpb_sic_ops, s, "vpb-sic", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -/* Board init. */ - -/* The AB and PB boards both use the same core, just with different - peripherals and expansion busses. For now we emulate a subset of the - PB peripherals and just change the board ID. */ - -static struct arm_boot_info versatile_binfo; - -static void versatile_init(QEMUMachineInitArgs *args, int board_id) -{ - ARMCPU *cpu; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - qemu_irq *cpu_pic; - qemu_irq pic[32]; - qemu_irq sic[32]; - DeviceState *dev, *sysctl; - SysBusDevice *busdev; - DeviceState *pl041; - PCIBus *pci_bus; - NICInfo *nd; - i2c_bus *i2c; - int n; - int done_smc = 0; - DriveInfo *dinfo; - - if (!args->cpu_model) { - args->cpu_model = "arm926"; - } - cpu = cpu_arm_init(args->cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - memory_region_init_ram(ram, "versatile.ram", args->ram_size); - vmstate_register_ram_global(ram); - /* ??? RAM should repeat to fill physical memory space. */ - /* SDRAM at address zero. */ - memory_region_add_subregion(sysmem, 0, ram); - - sysctl = qdev_create(NULL, "realview_sysctl"); - qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004); - qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000); - qdev_init_nofail(sysctl); - sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); - - cpu_pic = arm_pic_init_cpu(cpu); - dev = sysbus_create_varargs("pl190", 0x10140000, - cpu_pic[ARM_PIC_CPU_IRQ], - cpu_pic[ARM_PIC_CPU_FIQ], NULL); - for (n = 0; n < 32; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL); - for (n = 0; n < 32; n++) { - sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]); - sic[n] = qdev_get_gpio_in(dev, n); - } - - sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]); - sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]); - - dev = qdev_create(NULL, "versatile_pci"); - busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); - sysbus_mmio_map(busdev, 0, 0x41000000); /* PCI self-config */ - sysbus_mmio_map(busdev, 1, 0x42000000); /* PCI config */ - sysbus_connect_irq(busdev, 0, sic[27]); - sysbus_connect_irq(busdev, 1, sic[28]); - sysbus_connect_irq(busdev, 2, sic[29]); - sysbus_connect_irq(busdev, 3, sic[30]); - pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); - - /* The Versatile PCI bridge does not provide access to PCI IO space, - so many of the qemu PCI devices are not useable. */ - for(n = 0; n < nb_nics; n++) { - nd = &nd_table[n]; - - if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) { - smc91c111_init(nd, 0x10010000, sic[25]); - done_smc = 1; - } else { - pci_nic_init_nofail(nd, "rtl8139", NULL); - } - } - if (usb_enabled(false)) { - pci_create_simple(pci_bus, -1, "pci-ohci"); - } - n = drive_get_max_bus(IF_SCSI); - while (n >= 0) { - pci_create_simple(pci_bus, -1, "lsi53c895a"); - n--; - } - - sysbus_create_simple("pl011", 0x101f1000, pic[12]); - sysbus_create_simple("pl011", 0x101f2000, pic[13]); - sysbus_create_simple("pl011", 0x101f3000, pic[14]); - sysbus_create_simple("pl011", 0x10009000, sic[6]); - - sysbus_create_simple("pl080", 0x10130000, pic[17]); - sysbus_create_simple("sp804", 0x101e2000, pic[4]); - sysbus_create_simple("sp804", 0x101e3000, pic[5]); - - sysbus_create_simple("pl061", 0x101e4000, pic[6]); - sysbus_create_simple("pl061", 0x101e5000, pic[7]); - sysbus_create_simple("pl061", 0x101e6000, pic[8]); - sysbus_create_simple("pl061", 0x101e7000, pic[9]); - - /* The versatile/PB actually has a modified Color LCD controller - that includes hardware cursor support from the PL111. */ - dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]); - /* Wire up the mux control signals from the SYS_CLCD register */ - qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0)); - - sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL); - sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL); - - /* Add PL031 Real Time Clock. */ - sysbus_create_simple("pl031", 0x101e8000, pic[10]); - - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); - i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "ds1338", 0x68); - - /* Add PL041 AACI Interface to the LM4549 codec */ - pl041 = qdev_create(NULL, "pl041"); - qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); - sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); - sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]); - - /* Memory map for Versatile/PB: */ - /* 0x10000000 System registers. */ - /* 0x10001000 PCI controller config registers. */ - /* 0x10002000 Serial bus interface. */ - /* 0x10003000 Secondary interrupt controller. */ - /* 0x10004000 AACI (audio). */ - /* 0x10005000 MMCI0. */ - /* 0x10006000 KMI0 (keyboard). */ - /* 0x10007000 KMI1 (mouse). */ - /* 0x10008000 Character LCD Interface. */ - /* 0x10009000 UART3. */ - /* 0x1000a000 Smart card 1. */ - /* 0x1000b000 MMCI1. */ - /* 0x10010000 Ethernet. */ - /* 0x10020000 USB. */ - /* 0x10100000 SSMC. */ - /* 0x10110000 MPMC. */ - /* 0x10120000 CLCD Controller. */ - /* 0x10130000 DMA Controller. */ - /* 0x10140000 Vectored interrupt controller. */ - /* 0x101d0000 AHB Monitor Interface. */ - /* 0x101e0000 System Controller. */ - /* 0x101e1000 Watchdog Interface. */ - /* 0x101e2000 Timer 0/1. */ - /* 0x101e3000 Timer 2/3. */ - /* 0x101e4000 GPIO port 0. */ - /* 0x101e5000 GPIO port 1. */ - /* 0x101e6000 GPIO port 2. */ - /* 0x101e7000 GPIO port 3. */ - /* 0x101e8000 RTC. */ - /* 0x101f0000 Smart card 0. */ - /* 0x101f1000 UART0. */ - /* 0x101f2000 UART1. */ - /* 0x101f3000 UART2. */ - /* 0x101f4000 SSPI. */ - /* 0x34000000 NOR Flash */ - - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash", - VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, - VERSATILE_FLASH_SECT_SIZE, - VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE, - 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - } - - versatile_binfo.ram_size = args->ram_size; - versatile_binfo.kernel_filename = args->kernel_filename; - versatile_binfo.kernel_cmdline = args->kernel_cmdline; - versatile_binfo.initrd_filename = args->initrd_filename; - versatile_binfo.board_id = board_id; - arm_load_kernel(cpu, &versatile_binfo); -} - -static void vpb_init(QEMUMachineInitArgs *args) -{ - versatile_init(args, 0x183); -} - -static void vab_init(QEMUMachineInitArgs *args) -{ - versatile_init(args, 0x25e); -} - -static QEMUMachine versatilepb_machine = { - .name = "versatilepb", - .desc = "ARM Versatile/PB (ARM926EJ-S)", - .init = vpb_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine versatileab_machine = { - .name = "versatileab", - .desc = "ARM Versatile/AB (ARM926EJ-S)", - .init = vab_init, - .block_default_type = IF_SCSI, - DEFAULT_MACHINE_OPTIONS, -}; - -static void versatile_machine_init(void) -{ - qemu_register_machine(&versatilepb_machine); - qemu_register_machine(&versatileab_machine); -} - -machine_init(versatile_machine_init); - -static void vpb_sic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = vpb_sic_init; - dc->no_user = 1; - dc->vmsd = &vmstate_vpb_sic; -} - -static const TypeInfo vpb_sic_info = { - .name = "versatilepb_sic", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(vpb_sic_state), - .class_init = vpb_sic_class_init, -}; - -static void versatilepb_register_types(void) -{ - type_register_static(&vpb_sic_info); -} - -type_init(versatilepb_register_types) diff --git a/hw/vexpress.c b/hw/vexpress.c deleted file mode 100644 index 02922c38b3..0000000000 --- a/hw/vexpress.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * ARM Versatile Express emulation. - * - * Copyright (c) 2010 - 2011 B Labs Ltd. - * Copyright (c) 2011 Linaro Limited - * Written by Bahadir Balban, Amit Mahajan, Peter Maydell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "hw/primecell.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "exec/address-spaces.h" -#include "sysemu/blockdev.h" -#include "hw/flash.h" - -#define VEXPRESS_BOARD_ID 0x8e0 -#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) -#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024) - -static struct arm_boot_info vexpress_binfo; - -/* Address maps for peripherals: - * the Versatile Express motherboard has two possible maps, - * the "legacy" one (used for A9) and the "Cortex-A Series" - * map (used for newer cores). - * Individual daughterboards can also have different maps for - * their peripherals. - */ - -enum { - VE_SYSREGS, - VE_SP810, - VE_SERIALPCI, - VE_PL041, - VE_MMCI, - VE_KMI0, - VE_KMI1, - VE_UART0, - VE_UART1, - VE_UART2, - VE_UART3, - VE_WDT, - VE_TIMER01, - VE_TIMER23, - VE_SERIALDVI, - VE_RTC, - VE_COMPACTFLASH, - VE_CLCD, - VE_NORFLASH0, - VE_NORFLASH1, - VE_SRAM, - VE_VIDEORAM, - VE_ETHERNET, - VE_USB, - VE_DAPROM, -}; - -static hwaddr motherboard_legacy_map[] = { - /* CS7: 0x10000000 .. 0x10020000 */ - [VE_SYSREGS] = 0x10000000, - [VE_SP810] = 0x10001000, - [VE_SERIALPCI] = 0x10002000, - [VE_PL041] = 0x10004000, - [VE_MMCI] = 0x10005000, - [VE_KMI0] = 0x10006000, - [VE_KMI1] = 0x10007000, - [VE_UART0] = 0x10009000, - [VE_UART1] = 0x1000a000, - [VE_UART2] = 0x1000b000, - [VE_UART3] = 0x1000c000, - [VE_WDT] = 0x1000f000, - [VE_TIMER01] = 0x10011000, - [VE_TIMER23] = 0x10012000, - [VE_SERIALDVI] = 0x10016000, - [VE_RTC] = 0x10017000, - [VE_COMPACTFLASH] = 0x1001a000, - [VE_CLCD] = 0x1001f000, - /* CS0: 0x40000000 .. 0x44000000 */ - [VE_NORFLASH0] = 0x40000000, - /* CS1: 0x44000000 .. 0x48000000 */ - [VE_NORFLASH1] = 0x44000000, - /* CS2: 0x48000000 .. 0x4a000000 */ - [VE_SRAM] = 0x48000000, - /* CS3: 0x4c000000 .. 0x50000000 */ - [VE_VIDEORAM] = 0x4c000000, - [VE_ETHERNET] = 0x4e000000, - [VE_USB] = 0x4f000000, -}; - -static hwaddr motherboard_aseries_map[] = { - /* CS0: 0x08000000 .. 0x0c000000 */ - [VE_NORFLASH0] = 0x08000000, - /* CS4: 0x0c000000 .. 0x10000000 */ - [VE_NORFLASH1] = 0x0c000000, - /* CS5: 0x10000000 .. 0x14000000 */ - /* CS1: 0x14000000 .. 0x18000000 */ - [VE_SRAM] = 0x14000000, - /* CS2: 0x18000000 .. 0x1c000000 */ - [VE_VIDEORAM] = 0x18000000, - [VE_ETHERNET] = 0x1a000000, - [VE_USB] = 0x1b000000, - /* CS3: 0x1c000000 .. 0x20000000 */ - [VE_DAPROM] = 0x1c000000, - [VE_SYSREGS] = 0x1c010000, - [VE_SP810] = 0x1c020000, - [VE_SERIALPCI] = 0x1c030000, - [VE_PL041] = 0x1c040000, - [VE_MMCI] = 0x1c050000, - [VE_KMI0] = 0x1c060000, - [VE_KMI1] = 0x1c070000, - [VE_UART0] = 0x1c090000, - [VE_UART1] = 0x1c0a0000, - [VE_UART2] = 0x1c0b0000, - [VE_UART3] = 0x1c0c0000, - [VE_WDT] = 0x1c0f0000, - [VE_TIMER01] = 0x1c110000, - [VE_TIMER23] = 0x1c120000, - [VE_SERIALDVI] = 0x1c160000, - [VE_RTC] = 0x1c170000, - [VE_COMPACTFLASH] = 0x1c1a0000, - [VE_CLCD] = 0x1c1f0000, -}; - -/* Structure defining the peculiarities of a specific daughterboard */ - -typedef struct VEDBoardInfo VEDBoardInfo; - -typedef void DBoardInitFn(const VEDBoardInfo *daughterboard, - ram_addr_t ram_size, - const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id); - -struct VEDBoardInfo { - const hwaddr *motherboard_map; - hwaddr loader_start; - const hwaddr gic_cpu_if_addr; - DBoardInitFn *init; -}; - -static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, - ram_addr_t ram_size, - const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id) -{ - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *lowram = g_new(MemoryRegion, 1); - DeviceState *dev; - SysBusDevice *busdev; - qemu_irq *irqp; - int n; - qemu_irq cpu_irq[4]; - ram_addr_t low_ram_size; - - if (!cpu_model) { - cpu_model = "cortex-a9"; - } - - *proc_id = 0x0c000191; - - for (n = 0; n < smp_cpus; n++) { - ARMCPU *cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; - } - - if (ram_size > 0x40000000) { - /* 1GB is the maximum the address space permits */ - fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n"); - exit(1); - } - - memory_region_init_ram(ram, "vexpress.highmem", ram_size); - vmstate_register_ram_global(ram); - low_ram_size = ram_size; - if (low_ram_size > 0x4000000) { - low_ram_size = 0x4000000; - } - /* RAM is from 0x60000000 upwards. The bottom 64MB of the - * address space should in theory be remappable to various - * things including ROM or RAM; we always map the RAM there. - */ - memory_region_init_alias(lowram, "vexpress.lowmem", ram, 0, low_ram_size); - memory_region_add_subregion(sysmem, 0x0, lowram); - memory_region_add_subregion(sysmem, 0x60000000, ram); - - /* 0x1e000000 A9MPCore (SCU) private memory region */ - dev = qdev_create(NULL, "a9mpcore_priv"); - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0x1e000000); - for (n = 0; n < smp_cpus; n++) { - sysbus_connect_irq(busdev, n, cpu_irq[n]); - } - /* Interrupts [42:0] are from the motherboard; - * [47:43] are reserved; [63:48] are daughterboard - * peripherals. Note that some documentation numbers - * external interrupts starting from 32 (because the - * A9MP has internal interrupts 0..31). - */ - for (n = 0; n < 64; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ - - /* 0x10020000 PL111 CLCD (daughterboard) */ - sysbus_create_simple("pl111", 0x10020000, pic[44]); - - /* 0x10060000 AXI RAM */ - /* 0x100e0000 PL341 Dynamic Memory Controller */ - /* 0x100e1000 PL354 Static Memory Controller */ - /* 0x100e2000 System Configuration Controller */ - - sysbus_create_simple("sp804", 0x100e4000, pic[48]); - /* 0x100e5000 SP805 Watchdog module */ - /* 0x100e6000 BP147 TrustZone Protection Controller */ - /* 0x100e9000 PL301 'Fast' AXI matrix */ - /* 0x100ea000 PL301 'Slow' AXI matrix */ - /* 0x100ec000 TrustZone Address Space Controller */ - /* 0x10200000 CoreSight debug APB */ - /* 0x1e00a000 PL310 L2 Cache Controller */ - sysbus_create_varargs("l2x0", 0x1e00a000, NULL); -} - -static const VEDBoardInfo a9_daughterboard = { - .motherboard_map = motherboard_legacy_map, - .loader_start = 0x60000000, - .gic_cpu_if_addr = 0x1e000100, - .init = a9_daughterboard_init, -}; - -static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, - ram_addr_t ram_size, - const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id) -{ - int n; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - qemu_irq cpu_irq[4]; - DeviceState *dev; - SysBusDevice *busdev; - - if (!cpu_model) { - cpu_model = "cortex-a15"; - } - - *proc_id = 0x14000237; - - for (n = 0; n < smp_cpus; n++) { - ARMCPU *cpu; - qemu_irq *irqp; - - cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - irqp = arm_pic_init_cpu(cpu); - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; - } - - { - /* We have to use a separate 64 bit variable here to avoid the gcc - * "comparison is always false due to limited range of data type" - * warning if we are on a host where ram_addr_t is 32 bits. - */ - uint64_t rsz = ram_size; - if (rsz > (30ULL * 1024 * 1024 * 1024)) { - fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n"); - exit(1); - } - } - - memory_region_init_ram(ram, "vexpress.highmem", ram_size); - vmstate_register_ram_global(ram); - /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */ - memory_region_add_subregion(sysmem, 0x80000000, ram); - - /* 0x2c000000 A15MPCore private memory region (GIC) */ - dev = qdev_create(NULL, "a15mpcore_priv"); - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0x2c000000); - for (n = 0; n < smp_cpus; n++) { - sysbus_connect_irq(busdev, n, cpu_irq[n]); - } - /* Interrupts [42:0] are from the motherboard; - * [47:43] are reserved; [63:48] are daughterboard - * peripherals. Note that some documentation numbers - * external interrupts starting from 32 (because there - * are internal interrupts 0..31). - */ - for (n = 0; n < 64; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - /* A15 daughterboard peripherals: */ - - /* 0x20000000: CoreSight interfaces: not modelled */ - /* 0x2a000000: PL301 AXI interconnect: not modelled */ - /* 0x2a420000: SCC: not modelled */ - /* 0x2a430000: system counter: not modelled */ - /* 0x2b000000: HDLCD controller: not modelled */ - /* 0x2b060000: SP805 watchdog: not modelled */ - /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */ - /* 0x2e000000: system SRAM */ - memory_region_init_ram(sram, "vexpress.a15sram", 0x10000); - vmstate_register_ram_global(sram); - memory_region_add_subregion(sysmem, 0x2e000000, sram); - - /* 0x7ffb0000: DMA330 DMA controller: not modelled */ - /* 0x7ffd0000: PL354 static memory controller: not modelled */ -} - -static const VEDBoardInfo a15_daughterboard = { - .motherboard_map = motherboard_aseries_map, - .loader_start = 0x80000000, - .gic_cpu_if_addr = 0x2c002000, - .init = a15_daughterboard_init, -}; - -static void vexpress_common_init(const VEDBoardInfo *daughterboard, - QEMUMachineInitArgs *args) -{ - DeviceState *dev, *sysctl, *pl041; - qemu_irq pic[64]; - uint32_t proc_id; - uint32_t sys_id; - DriveInfo *dinfo; - ram_addr_t vram_size, sram_size; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *vram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - const hwaddr *map = daughterboard->motherboard_map; - - daughterboard->init(daughterboard, args->ram_size, args->cpu_model, - pic, &proc_id); - - /* Motherboard peripherals: the wiring is the same but the - * addresses vary between the legacy and A-Series memory maps. - */ - - sys_id = 0x1190f500; - - sysctl = qdev_create(NULL, "realview_sysctl"); - qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_prop_set_uint32(sysctl, "proc_id", proc_id); - qdev_init_nofail(sysctl); - sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); - - /* VE_SP810: not modelled */ - /* VE_SERIALPCI: not modelled */ - - pl041 = qdev_create(NULL, "pl041"); - qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); - sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); - sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); - - dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL); - /* Wire up MMC card detect and read-only signals */ - qdev_connect_gpio_out(dev, 0, - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT)); - qdev_connect_gpio_out(dev, 1, - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN)); - - sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]); - sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]); - - sysbus_create_simple("pl011", map[VE_UART0], pic[5]); - sysbus_create_simple("pl011", map[VE_UART1], pic[6]); - sysbus_create_simple("pl011", map[VE_UART2], pic[7]); - sysbus_create_simple("pl011", map[VE_UART3], pic[8]); - - sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); - sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); - - /* VE_SERIALDVI: not modelled */ - - sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */ - - /* VE_COMPACTFLASH: not modelled */ - - sysbus_create_simple("pl111", map[VE_CLCD], pic[14]); - - dinfo = drive_get_next(IF_PFLASH); - if (!pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0", - VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, - VEXPRESS_FLASH_SECT_SIZE, - VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4, - 0x00, 0x89, 0x00, 0x18, 0)) { - fprintf(stderr, "vexpress: error registering flash 0.\n"); - exit(1); - } - - dinfo = drive_get_next(IF_PFLASH); - if (!pflash_cfi01_register(map[VE_NORFLASH1], NULL, "vexpress.flash1", - VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, - VEXPRESS_FLASH_SECT_SIZE, - VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4, - 0x00, 0x89, 0x00, 0x18, 0)) { - fprintf(stderr, "vexpress: error registering flash 1.\n"); - exit(1); - } - - sram_size = 0x2000000; - memory_region_init_ram(sram, "vexpress.sram", sram_size); - vmstate_register_ram_global(sram); - memory_region_add_subregion(sysmem, map[VE_SRAM], sram); - - vram_size = 0x800000; - memory_region_init_ram(vram, "vexpress.vram", vram_size); - vmstate_register_ram_global(vram); - memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram); - - /* 0x4e000000 LAN9118 Ethernet */ - if (nd_table[0].used) { - lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]); - } - - /* VE_USB: not modelled */ - - /* VE_DAPROM: not modelled */ - - vexpress_binfo.ram_size = args->ram_size; - vexpress_binfo.kernel_filename = args->kernel_filename; - vexpress_binfo.kernel_cmdline = args->kernel_cmdline; - vexpress_binfo.initrd_filename = args->initrd_filename; - vexpress_binfo.nb_cpus = smp_cpus; - vexpress_binfo.board_id = VEXPRESS_BOARD_ID; - vexpress_binfo.loader_start = daughterboard->loader_start; - vexpress_binfo.smp_loader_start = map[VE_SRAM]; - vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30; - vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr; - arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo); -} - -static void vexpress_a9_init(QEMUMachineInitArgs *args) -{ - vexpress_common_init(&a9_daughterboard, args); -} - -static void vexpress_a15_init(QEMUMachineInitArgs *args) -{ - vexpress_common_init(&a15_daughterboard, args); -} - -static QEMUMachine vexpress_a9_machine = { - .name = "vexpress-a9", - .desc = "ARM Versatile Express for Cortex-A9", - .init = vexpress_a9_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine vexpress_a15_machine = { - .name = "vexpress-a15", - .desc = "ARM Versatile Express for Cortex-A15", - .init = vexpress_a15_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static void vexpress_machine_init(void) -{ - qemu_register_machine(&vexpress_a9_machine); - qemu_register_machine(&vexpress_a15_machine); -} - -machine_init(vexpress_machine_init); diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c deleted file mode 100644 index 41eab1697c..0000000000 --- a/hw/virtex_ml507.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Model of Xilinx Virtex5 ML507 PPC-440 refdesign. - * - * Copyright (c) 2010 Edgar E. Iglesias. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "hw/serial.h" -#include "hw/flash.h" -#include "sysemu/sysemu.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "sysemu/device_tree.h" -#include "hw/loader.h" -#include "elf.h" -#include "qemu/log.h" -#include "exec/address-spaces.h" - -#include "hw/ppc.h" -#include "hw/ppc4xx.h" -#include "hw/ppc405.h" - -#include "sysemu/blockdev.h" -#include "hw/xilinx.h" - -#define EPAPR_MAGIC (0x45504150) -#define FLASH_SIZE (16 * 1024 * 1024) - -static struct boot_info -{ - uint32_t bootstrap_pc; - uint32_t cmdline; - uint32_t fdt; - uint32_t ima_size; - void *vfdt; -} boot_info; - -/* Create reset TLB entries for BookE, spanning the 32bit addr space. */ -static void mmubooke_create_initial_mapping(CPUPPCState *env, - target_ulong va, - hwaddr pa) -{ - ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; - - tlb->attr = 0; - tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); - tlb->size = 1 << 31; /* up to 0x80000000 */ - tlb->EPN = va & TARGET_PAGE_MASK; - tlb->RPN = pa & TARGET_PAGE_MASK; - tlb->PID = 0; - - tlb = &env->tlb.tlbe[1]; - tlb->attr = 0; - tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); - tlb->size = 1 << 31; /* up to 0xffffffff */ - tlb->EPN = 0x80000000 & TARGET_PAGE_MASK; - tlb->RPN = 0x80000000 & TARGET_PAGE_MASK; - tlb->PID = 0; -} - -static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size, - int do_init, - const char *cpu_model, - uint32_t sysclk) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - qemu_irq *irqs; - - cpu = cpu_ppc_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to initialize CPU!\n"); - exit(1); - } - env = &cpu->env; - - ppc_booke_timers_init(cpu, sysclk, 0/* no flags */); - - ppc_dcr_init(env, NULL, NULL); - - /* interrupt controller */ - irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); - irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; - irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; - ppcuic_init(env, irqs, 0x0C0, 0, 1); - return cpu; -} - -static void main_cpu_reset(void *opaque) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - struct boot_info *bi = env->load_info; - - cpu_reset(CPU(cpu)); - /* Linux Kernel Parameters (passing device tree): - * r3: pointer to the fdt - * r4: 0 - * r5: 0 - * r6: epapr magic - * r7: size of IMA in bytes - * r8: 0 - * r9: 0 - */ - env->gpr[1] = (16<<20) - 8; - /* Provide a device-tree. */ - env->gpr[3] = bi->fdt; - env->nip = bi->bootstrap_pc; - - /* Create a mapping for the kernel. */ - mmubooke_create_initial_mapping(env, 0, 0); - env->gpr[6] = tswap32(EPAPR_MAGIC); - env->gpr[7] = bi->ima_size; -} - -#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" -static int xilinx_load_device_tree(hwaddr addr, - uint32_t ramsize, - hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) -{ - char *path; - int fdt_size; -#ifdef CONFIG_FDT - void *fdt; - int r; - - /* Try the local "ppc.dtb" override. */ - fdt = load_device_tree("ppc.dtb", &fdt_size); - if (!fdt) { - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); - if (path) { - fdt = load_device_tree(path, &fdt_size); - g_free(path); - } - if (!fdt) { - return 0; - } - } - - r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); - if (r < 0) - fprintf(stderr, "couldn't set /chosen/bootargs\n"); - cpu_physical_memory_write (addr, (void *)fdt, fdt_size); -#else - /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob - to the kernel. */ - fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000); - if (fdt_size < 0) { - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); - if (path) { - fdt_size = load_image_targphys(path, addr, 0x10000); - g_free(path); - } - } - - if (kernel_cmdline) { - fprintf(stderr, - "Warning: missing libfdt, cannot pass cmdline to kernel!\n"); - } -#endif - return fdt_size; -} - -static void virtex_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - MemoryRegion *address_space_mem = get_system_memory(); - DeviceState *dev; - PowerPCCPU *cpu; - CPUPPCState *env; - hwaddr ram_base = 0; - DriveInfo *dinfo; - MemoryRegion *phys_ram = g_new(MemoryRegion, 1); - qemu_irq irq[32], *cpu_irq; - int kernel_size; - int i; - - /* init CPUs */ - if (cpu_model == NULL) { - cpu_model = "440-Xilinx"; - } - - cpu = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000); - env = &cpu->env; - qemu_register_reset(main_cpu_reset, cpu); - - memory_region_init_ram(phys_ram, "ram", ram_size); - vmstate_register_ram_global(phys_ram); - memory_region_add_subregion(address_space_mem, ram_base, phys_ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE, - dinfo ? dinfo->bdrv : NULL, (64 * 1024), - FLASH_SIZE >> 16, - 1, 0x89, 0x18, 0x0000, 0x0, 1); - - cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT]; - dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(dev, i); - } - - serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200, - serial_hds[0], DEVICE_LITTLE_ENDIAN); - - /* 2 timers at irq 2 @ 62 Mhz. */ - xilinx_timer_create(0x83c00000, irq[3], 0, 62 * 1000000); - - if (kernel_filename) { - uint64_t entry, low, high; - hwaddr boot_offset; - - /* Boots a kernel elf binary. */ - kernel_size = load_elf(kernel_filename, NULL, NULL, - &entry, &low, &high, 1, ELF_MACHINE, 0); - boot_info.bootstrap_pc = entry & 0x00ffffff; - - if (kernel_size < 0) { - boot_offset = 0x1200000; - /* If we failed loading ELF's try a raw image. */ - kernel_size = load_image_targphys(kernel_filename, - boot_offset, - ram_size); - boot_info.bootstrap_pc = boot_offset; - high = boot_info.bootstrap_pc + kernel_size + 8192; - } - - boot_info.ima_size = kernel_size; - - /* Provide a device-tree. */ - boot_info.fdt = high + (8192 * 2); - boot_info.fdt &= ~8191; - xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline); - } - env->load_info = &boot_info; -} - -static QEMUMachine virtex_machine = { - .name = "virtex-ml507", - .desc = "Xilinx Virtex ML507 reference design", - .init = virtex_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void virtex_machine_init(void) -{ - qemu_register_machine(&virtex_machine); -} - -machine_init(virtex_machine_init); diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c deleted file mode 100644 index d477061545..0000000000 --- a/hw/xen_domainbuild.c +++ /dev/null @@ -1,299 +0,0 @@ -#include -#include "hw/xen_backend.h" -#include "hw/xen_domainbuild.h" -#include "qemu/timer.h" -#include "qemu/log.h" - -#include - -static int xenstore_domain_mkdir(char *path) -{ - struct xs_permissions perms_ro[] = {{ - .id = 0, /* set owner: dom0 */ - },{ - .id = xen_domid, - .perms = XS_PERM_READ, - }}; - struct xs_permissions perms_rw[] = {{ - .id = 0, /* set owner: dom0 */ - },{ - .id = xen_domid, - .perms = XS_PERM_READ | XS_PERM_WRITE, - }}; - const char *writable[] = { "device", "control", "error", NULL }; - char subpath[256]; - int i; - - if (!xs_mkdir(xenstore, 0, path)) { - fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path); - return -1; - } - if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) { - fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__); - return -1; - } - - for (i = 0; writable[i]; i++) { - snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]); - if (!xs_mkdir(xenstore, 0, subpath)) { - fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath); - return -1; - } - if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) { - fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__); - return -1; - } - } - return 0; -} - -int xenstore_domain_init1(const char *kernel, const char *ramdisk, - const char *cmdline) -{ - char *dom, uuid_string[42], vm[256], path[256]; - int i; - - snprintf(uuid_string, sizeof(uuid_string), UUID_FMT, - qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3], - qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], - qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11], - qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]); - dom = xs_get_domain_path(xenstore, xen_domid); - snprintf(vm, sizeof(vm), "/vm/%s", uuid_string); - - xenstore_domain_mkdir(dom); - - xenstore_write_str(vm, "image/ostype", "linux"); - if (kernel) - xenstore_write_str(vm, "image/kernel", kernel); - if (ramdisk) - xenstore_write_str(vm, "image/ramdisk", ramdisk); - if (cmdline) - xenstore_write_str(vm, "image/cmdline", cmdline); - - /* name + id */ - xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name"); - xenstore_write_str(vm, "uuid", uuid_string); - xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name"); - xenstore_write_int(dom, "domid", xen_domid); - xenstore_write_str(dom, "vm", vm); - - /* memory */ - xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB - xenstore_write_int(vm, "memory", ram_size >> 20); // MB - xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB - - /* cpus */ - for (i = 0; i < smp_cpus; i++) { - snprintf(path, sizeof(path), "cpu/%d/availability",i); - xenstore_write_str(dom, path, "online"); - } - xenstore_write_int(vm, "vcpu_avail", smp_cpus); - xenstore_write_int(vm, "vcpus", smp_cpus); - - /* vnc password */ - xenstore_write_str(vm, "vncpassword", "" /* FIXME */); - - free(dom); - return 0; -} - -int xenstore_domain_init2(int xenstore_port, int xenstore_mfn, - int console_port, int console_mfn) -{ - char *dom; - - dom = xs_get_domain_path(xenstore, xen_domid); - - /* signal new domain */ - xs_introduce_domain(xenstore, - xen_domid, - xenstore_mfn, - xenstore_port); - - /* xenstore */ - xenstore_write_int(dom, "store/ring-ref", xenstore_mfn); - xenstore_write_int(dom, "store/port", xenstore_port); - - /* console */ - xenstore_write_str(dom, "console/type", "ioemu"); - xenstore_write_int(dom, "console/limit", 128 * 1024); - xenstore_write_int(dom, "console/ring-ref", console_mfn); - xenstore_write_int(dom, "console/port", console_port); - xen_config_dev_console(0); - - free(dom); - return 0; -} - -/* ------------------------------------------------------------- */ - -static QEMUTimer *xen_poll; - -/* check domain state once per second */ -static void xen_domain_poll(void *opaque) -{ - struct xc_dominfo info; - int rc; - - rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info); - if ((rc != 1) || (info.domid != xen_domid)) { - qemu_log("xen: domain %d is gone\n", xen_domid); - goto quit; - } - if (info.dying) { - qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid, - info.crashed ? "crashed" : "", - info.shutdown ? "shutdown" : ""); - goto quit; - } - - qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); - return; - -quit: - qemu_system_shutdown_request(); -} - -static int xen_domain_watcher(void) -{ - int qemu_running = 1; - int fd[2], i, n, rc; - char byte; - - if (pipe(fd) != 0) { - qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno)); - return -1; - } - if (fork() != 0) - return 0; /* not child */ - - /* close all file handles, except stdio/out/err, - * our watch pipe and the xen interface handle */ - n = getdtablesize(); - for (i = 3; i < n; i++) { - if (i == fd[0]) - continue; - if (i == xc_fd(xen_xc)) { - continue; - } - close(i); - } - - /* ignore term signals */ - signal(SIGINT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - - /* wait for qemu exiting */ - while (qemu_running) { - rc = read(fd[0], &byte, 1); - switch (rc) { - case -1: - if (errno == EINTR) - continue; - qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno)); - qemu_running = 0; - break; - case 0: - /* EOF -> qemu exited */ - qemu_running = 0; - break; - default: - qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__); - break; - } - } - - /* cleanup */ - qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid); - xc_domain_destroy(xen_xc, xen_domid); - _exit(0); -} - -/* normal cleanup */ -static void xen_domain_cleanup(void) -{ - char *dom; - - dom = xs_get_domain_path(xenstore, xen_domid); - if (dom) { - xs_rm(xenstore, 0, dom); - free(dom); - } - xs_release_domain(xenstore, xen_domid); -} - -int xen_domain_build_pv(const char *kernel, const char *ramdisk, - const char *cmdline) -{ - uint32_t ssidref = 0; - uint32_t flags = 0; - xen_domain_handle_t uuid; - unsigned int xenstore_port = 0, console_port = 0; - unsigned long xenstore_mfn = 0, console_mfn = 0; - int rc; - - memcpy(uuid, qemu_uuid, sizeof(uuid)); - rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid); - if (rc < 0) { - fprintf(stderr, "xen: xc_domain_create() failed\n"); - goto err; - } - qemu_log("xen: created domain %d\n", xen_domid); - atexit(xen_domain_cleanup); - if (xen_domain_watcher() == -1) { - goto err; - } - - xenstore_domain_init1(kernel, ramdisk, cmdline); - - rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus); - if (rc < 0) { - fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n"); - goto err; - } - -#if 0 - rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256); - if (rc < 0) { - fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n"); - goto err; - } -#endif - - rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10); - if (rc < 0) { - fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n"); - goto err; - } - - xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); - console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); - - rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20, - kernel, ramdisk, cmdline, - 0, flags, - xenstore_port, &xenstore_mfn, - console_port, &console_mfn); - if (rc < 0) { - fprintf(stderr, "xen: xc_linux_build() failed\n"); - goto err; - } - - xenstore_domain_init2(xenstore_port, xenstore_mfn, - console_port, console_mfn); - - qemu_log("xen: unpausing domain %d\n", xen_domid); - rc = xc_domain_unpause(xen_xc, xen_domid); - if (rc < 0) { - fprintf(stderr, "xen: xc_domain_unpause() failed\n"); - goto err; - } - - xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL); - qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); - return 0; - -err: - return -1; -} diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c deleted file mode 100644 index a8177b6340..0000000000 --- a/hw/xen_machine_pv.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * QEMU Xen PV Machine - * - * Copyright (c) 2007 Red Hat - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/hw.h" -#include "hw/pc.h" -#include "hw/boards.h" -#include "hw/xen_backend.h" -#include "hw/xen_domainbuild.h" -#include "sysemu/blockdev.h" - -static void xen_init_pv(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - X86CPU *cpu; - CPUX86State *env; - DriveInfo *dinfo; - int i; - - /* Initialize a dummy CPU */ - if (cpu_model == NULL) { -#ifdef TARGET_X86_64 - cpu_model = "qemu64"; -#else - cpu_model = "qemu32"; -#endif - } - cpu = cpu_x86_init(cpu_model); - env = &cpu->env; - env->halted = 1; - - /* Initialize backend core & drivers */ - if (xen_be_init() != 0) { - fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); - exit(1); - } - - switch (xen_mode) { - case XEN_ATTACH: - /* nothing to do, xend handles everything */ - break; - case XEN_CREATE: - if (xen_domain_build_pv(kernel_filename, initrd_filename, - kernel_cmdline) < 0) { - fprintf(stderr, "xen pv domain creation failed\n"); - exit(1); - } - break; - case XEN_EMULATE: - fprintf(stderr, "xen emulation not implemented (yet)\n"); - exit(1); - break; - } - - xen_be_register("console", &xen_console_ops); - xen_be_register("vkbd", &xen_kbdmouse_ops); - xen_be_register("vfb", &xen_framebuffer_ops); - xen_be_register("qdisk", &xen_blkdev_ops); - xen_be_register("qnic", &xen_netdev_ops); - - /* configure framebuffer */ - if (xenfb_enabled) { - xen_config_dev_vfb(0, "vnc"); - xen_config_dev_vkbd(0); - } - - /* configure disks */ - for (i = 0; i < 16; i++) { - dinfo = drive_get(IF_XEN, 0, i); - if (!dinfo) - continue; - xen_config_dev_blk(dinfo); - } - - /* configure nics */ - for (i = 0; i < nb_nics; i++) { - if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen")) - continue; - xen_config_dev_nic(nd_table + i); - } - - /* config cleanup hook */ - atexit(xen_config_cleanup); - - /* setup framebuffer */ - xen_init_display(xen_domid); -} - -static QEMUMachine xenpv_machine = { - .name = "xenpv", - .desc = "Xen Para-virtualized PC", - .init = xen_init_pv, - .max_cpus = 1, - .default_machine_opts = "accel=xen", - DEFAULT_MACHINE_OPTIONS, -}; - -static void xenpv_machine_init(void) -{ - qemu_register_machine(&xenpv_machine); -} - -machine_init(xenpv_machine_init); diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c deleted file mode 100644 index f78c47e43e..0000000000 --- a/hw/xilinx_zynq.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Xilinx Zynq Baseboard System emulation. - * - * Copyright (c) 2010 Xilinx. - * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com) - * Copyright (c) 2012 Petalogix Pty Ltd. - * Written by Haibing Ma - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "net/net.h" -#include "exec/address-spaces.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/flash.h" -#include "sysemu/blockdev.h" -#include "hw/loader.h" -#include "hw/ssi.h" - -#define NUM_SPI_FLASHES 4 -#define NUM_QSPI_FLASHES 2 -#define NUM_QSPI_BUSSES 2 - -#define FLASH_SIZE (64 * 1024 * 1024) -#define FLASH_SECTOR_SIZE (128 * 1024) - -#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */ - -static struct arm_boot_info zynq_binfo = {}; - -static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *s; - - qemu_check_nic_model(nd, "cadence_gem"); - dev = qdev_create(NULL, "cadence_gem"); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, base); - sysbus_connect_irq(s, 0, irq); -} - -static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, - bool is_qspi) -{ - DeviceState *dev; - SysBusDevice *busdev; - SSIBus *spi; - DeviceState *flash_dev; - int i, j; - int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1; - int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES; - - dev = qdev_create(NULL, "xilinx,spips"); - qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1); - qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); - qdev_prop_set_uint8(dev, "num-busses", num_busses); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, base_addr); - if (is_qspi) { - sysbus_mmio_map(busdev, 1, 0xFC000000); - } - sysbus_connect_irq(busdev, 0, irq); - - for (i = 0; i < num_busses; ++i) { - char bus_name[16]; - qemu_irq cs_line; - - snprintf(bus_name, 16, "spi%d", i); - spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); - - for (j = 0; j < num_ss; ++j) { - flash_dev = ssi_create_slave_no_init(spi, "n25q128"); - qdev_init_nofail(flash_dev); - - cs_line = qdev_get_gpio_in(flash_dev, 0); - sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); - } - } - -} - -static void zynq_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - ARMCPU *cpu; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ext_ram = g_new(MemoryRegion, 1); - MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); - DeviceState *dev; - SysBusDevice *busdev; - qemu_irq *irqp; - qemu_irq pic[64]; - NICInfo *nd; - int n; - qemu_irq cpu_irq; - - if (!cpu_model) { - cpu_model = "cortex-a9"; - } - - cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - irqp = arm_pic_init_cpu(cpu); - cpu_irq = irqp[ARM_PIC_CPU_IRQ]; - - /* max 2GB ram */ - if (ram_size > 0x80000000) { - ram_size = 0x80000000; - } - - /* DDR remapped to address zero. */ - memory_region_init_ram(ext_ram, "zynq.ext_ram", ram_size); - vmstate_register_ram_global(ext_ram); - memory_region_add_subregion(address_space_mem, 0, ext_ram); - - /* 256K of on-chip memory */ - memory_region_init_ram(ocm_ram, "zynq.ocm_ram", 256 << 10); - vmstate_register_ram_global(ocm_ram); - memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram); - - DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); - - /* AMD */ - pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE, - dinfo ? dinfo->bdrv : NULL, FLASH_SECTOR_SIZE, - FLASH_SIZE/FLASH_SECTOR_SIZE, 1, - 1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa, - 0); - - dev = qdev_create(NULL, "xilinx,zynq_slcr"); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); - - dev = qdev_create(NULL, "a9mpcore_priv"); - qdev_prop_set_uint32(dev, "num-cpu", 1); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xF8F00000); - sysbus_connect_irq(busdev, 0, cpu_irq); - - for (n = 0; n < 64; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false); - zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false); - zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true); - - sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); - sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]); - - sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); - sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); - - sysbus_create_varargs("cadence_ttc", 0xF8001000, - pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL); - sysbus_create_varargs("cadence_ttc", 0xF8002000, - pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL); - - for (n = 0; n < nb_nics; n++) { - nd = &nd_table[n]; - if (n == 0) { - gem_init(nd, 0xE000B000, pic[54-IRQ_OFFSET]); - } else if (n == 1) { - gem_init(nd, 0xE000C000, pic[77-IRQ_OFFSET]); - } - } - - dev = qdev_create(NULL, "generic-sdhci"); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); - - dev = qdev_create(NULL, "generic-sdhci"); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); - - zynq_binfo.ram_size = ram_size; - zynq_binfo.kernel_filename = kernel_filename; - zynq_binfo.kernel_cmdline = kernel_cmdline; - zynq_binfo.initrd_filename = initrd_filename; - zynq_binfo.nb_cpus = 1; - zynq_binfo.board_id = 0xd32; - zynq_binfo.loader_start = 0; - arm_load_kernel(arm_env_get_cpu(first_cpu), &zynq_binfo); -} - -static QEMUMachine zynq_machine = { - .name = "xilinx-zynq-a9", - .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9", - .init = zynq_init, - .block_default_type = IF_SCSI, - .max_cpus = 1, - .no_sdcard = 1, - DEFAULT_MACHINE_OPTIONS, -}; - -static void zynq_machine_init(void) -{ - qemu_register_machine(&zynq_machine); -} - -machine_init(zynq_machine_init); diff --git a/hw/xtensa/Makefile.objs b/hw/xtensa/Makefile.objs index 79698e903d..6ead7820c4 100644 --- a/hw/xtensa/Makefile.objs +++ b/hw/xtensa/Makefile.objs @@ -1,5 +1,3 @@ -obj-y += xtensa_pic.o +obj-y += pic_cpu.o obj-y += xtensa_sim.o obj-y += xtensa_lx60.o - -obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c new file mode 100644 index 0000000000..f485a1465c --- /dev/null +++ b/hw/xtensa/pic_cpu.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hw/hw.h" +#include "qemu/log.h" +#include "qemu/timer.h" + +void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d) +{ + uint32_t old_ccount = env->sregs[CCOUNT]; + + env->sregs[CCOUNT] += d; + + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { + int i; + for (i = 0; i < env->config->nccompare; ++i) { + if (env->sregs[CCOMPARE + i] - old_ccount <= d) { + xtensa_timer_irq(env, i, 1); + } + } + } +} + +void check_interrupts(CPUXtensaState *env) +{ + int minlevel = xtensa_get_cintlevel(env); + uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; + int level; + + /* If the CPU is halted advance CCOUNT according to the vm_clock time + * elapsed since the moment when it was advanced last time. + */ + if (env->halted) { + int64_t now = qemu_get_clock_ns(vm_clock); + + xtensa_advance_ccount(env, + muldiv64(now - env->halt_clock, + env->config->clock_freq_khz, 1000000)); + env->halt_clock = now; + } + for (level = env->config->nlevel; level > minlevel; --level) { + if (env->config->level_mask[level] & int_set_enabled) { + env->pending_irq_level = level; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + qemu_log_mask(CPU_LOG_INT, + "%s level = %d, cintlevel = %d, " + "pc = %08x, a0 = %08x, ps = %08x, " + "intset = %08x, intenable = %08x, " + "ccount = %08x\n", + __func__, level, xtensa_get_cintlevel(env), + env->pc, env->regs[0], env->sregs[PS], + env->sregs[INTSET], env->sregs[INTENABLE], + env->sregs[CCOUNT]); + return; + } + } + env->pending_irq_level = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); +} + +static void xtensa_set_irq(void *opaque, int irq, int active) +{ + CPUXtensaState *env = opaque; + + if (irq >= env->config->ninterrupt) { + qemu_log("%s: bad IRQ %d\n", __func__, irq); + } else { + uint32_t irq_bit = 1 << irq; + + if (active) { + env->sregs[INTSET] |= irq_bit; + } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) { + env->sregs[INTSET] &= ~irq_bit; + } + + check_interrupts(env); + } +} + +void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active) +{ + qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active); +} + +void xtensa_rearm_ccompare_timer(CPUXtensaState *env) +{ + int i; + uint32_t wake_ccount = env->sregs[CCOUNT] - 1; + + for (i = 0; i < env->config->nccompare; ++i) { + if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] < + wake_ccount - env->sregs[CCOUNT]) { + wake_ccount = env->sregs[CCOMPARE + i]; + } + } + env->wake_ccount = wake_ccount; + qemu_mod_timer(env->ccompare_timer, env->halt_clock + + muldiv64(wake_ccount - env->sregs[CCOUNT], + 1000000, env->config->clock_freq_khz)); +} + +static void xtensa_ccompare_cb(void *opaque) +{ + XtensaCPU *cpu = opaque; + CPUXtensaState *env = &cpu->env; + + if (env->halted) { + env->halt_clock = qemu_get_clock_ns(vm_clock); + xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); + if (!cpu_has_work(CPU(cpu))) { + env->sregs[CCOUNT] = env->wake_ccount + 1; + xtensa_rearm_ccompare_timer(env); + } + } +} + +void xtensa_irq_init(CPUXtensaState *env) +{ + XtensaCPU *cpu = xtensa_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs( + xtensa_set_irq, env, env->config->ninterrupt); + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) && + env->config->nccompare > 0) { + env->ccompare_timer = + qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu); + } +} + +void *xtensa_get_extint(CPUXtensaState *env, unsigned extint) +{ + if (extint < env->config->nextint) { + unsigned irq = env->config->extint[extint]; + return env->irq_inputs[irq]; + } else { + qemu_log("%s: trying to acquire invalid external interrupt %d\n", + __func__, extint); + return NULL; + } +} diff --git a/hw/xtensa/xtensa_lx60.c b/hw/xtensa/xtensa_lx60.c new file mode 100644 index 0000000000..f2a63d82da --- /dev/null +++ b/hw/xtensa/xtensa_lx60.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "hw/serial.h" +#include "net/net.h" +#include "hw/sysbus.h" +#include "hw/flash.h" +#include "sysemu/blockdev.h" +#include "char/char.h" +#include "hw/xtensa_bootparam.h" + +typedef struct LxBoardDesc { + size_t flash_size; + size_t flash_sector_size; + size_t sram_size; +} LxBoardDesc; + +typedef struct Lx60FpgaState { + MemoryRegion iomem; + uint32_t leds; + uint32_t switches; +} Lx60FpgaState; + +static void lx60_fpga_reset(void *opaque) +{ + Lx60FpgaState *s = opaque; + + s->leds = 0; + s->switches = 0; +} + +static uint64_t lx60_fpga_read(void *opaque, hwaddr addr, + unsigned size) +{ + Lx60FpgaState *s = opaque; + + switch (addr) { + case 0x0: /*build date code*/ + return 0x09272011; + + case 0x4: /*processor clock frequency, Hz*/ + return 10000000; + + case 0x8: /*LEDs (off = 0, on = 1)*/ + return s->leds; + + case 0xc: /*DIP switches (off = 0, on = 1)*/ + return s->switches; + } + return 0; +} + +static void lx60_fpga_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + Lx60FpgaState *s = opaque; + + switch (addr) { + case 0x8: /*LEDs (off = 0, on = 1)*/ + s->leds = val; + break; + + case 0x10: /*board reset*/ + if (val == 0xdead) { + qemu_system_reset_request(); + } + break; + } +} + +static const MemoryRegionOps lx60_fpga_ops = { + .read = lx60_fpga_read, + .write = lx60_fpga_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space, + hwaddr base) +{ + Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState)); + + memory_region_init_io(&s->iomem, &lx60_fpga_ops, s, + "lx60.fpga", 0x10000); + memory_region_add_subregion(address_space, base, &s->iomem); + lx60_fpga_reset(s); + qemu_register_reset(lx60_fpga_reset, s); + return s; +} + +static void lx60_net_init(MemoryRegion *address_space, + hwaddr base, + hwaddr descriptors, + hwaddr buffers, + qemu_irq irq, NICInfo *nd) +{ + DeviceState *dev; + SysBusDevice *s; + MemoryRegion *ram; + + dev = qdev_create(NULL, "open_eth"); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, irq); + memory_region_add_subregion(address_space, base, + sysbus_mmio_get_region(s, 0)); + memory_region_add_subregion(address_space, descriptors, + sysbus_mmio_get_region(s, 1)); + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, "open_eth.ram", 16384); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space, buffers, ram); +} + +static uint64_t translate_phys_addr(void *env, uint64_t addr) +{ + return cpu_get_phys_page_debug(env, addr); +} + +static void lx60_reset(void *opaque) +{ + XtensaCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) +{ +#ifdef TARGET_WORDS_BIGENDIAN + int be = 1; +#else + int be = 0; +#endif + MemoryRegion *system_memory = get_system_memory(); + XtensaCPU *cpu = NULL; + CPUXtensaState *env = NULL; + MemoryRegion *ram, *rom, *system_io; + DriveInfo *dinfo; + pflash_t *flash = NULL; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + int n; + + if (!cpu_model) { + cpu_model = XTENSA_DEFAULT_CPU_MODEL; + } + + for (n = 0; n < smp_cpus; n++) { + cpu = cpu_xtensa_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + env->sregs[PRID] = n; + qemu_register_reset(lx60_reset, cpu); + /* Need MMU initialized prior to ELF loading, + * so that ELF gets loaded into virtual addresses + */ + cpu_reset(CPU(cpu)); + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, "lx60.dram", args->ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(system_memory, 0, ram); + + system_io = g_malloc(sizeof(*system_io)); + memory_region_init(system_io, "lx60.io", 224 * 1024 * 1024); + memory_region_add_subregion(system_memory, 0xf0000000, system_io); + lx60_fpga_init(system_io, 0x0d020000); + if (nd_table[0].used) { + lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000, + xtensa_get_extint(env, 1), nd_table); + } + + if (!serial_hds[0]) { + serial_hds[0] = qemu_chr_new("serial0", "null", NULL); + } + + serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0), + 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); + + dinfo = drive_get(IF_PFLASH, 0, 0); + if (dinfo) { + flash = pflash_cfi01_register(0xf8000000, + NULL, "lx60.io.flash", board->flash_size, + dinfo->bdrv, board->flash_sector_size, + board->flash_size / board->flash_sector_size, + 4, 0x0000, 0x0000, 0x0000, 0x0000, be); + if (flash == NULL) { + fprintf(stderr, "Unable to mount pflash\n"); + exit(1); + } + } + + /* Use presence of kernel file name as 'boot from SRAM' switch. */ + if (kernel_filename) { + rom = g_malloc(sizeof(*rom)); + memory_region_init_ram(rom, "lx60.sram", board->sram_size); + vmstate_register_ram_global(rom); + memory_region_add_subregion(system_memory, 0xfe000000, rom); + + /* Put kernel bootparameters to the end of that SRAM */ + if (kernel_cmdline) { + size_t cmdline_size = strlen(kernel_cmdline) + 1; + size_t bp_size = sizeof(BpTag[4]) + cmdline_size; + uint32_t tagptr = (0xfe000000 + board->sram_size - bp_size) & ~0xff; + + env->regs[2] = tagptr; + + tagptr = put_tag(tagptr, 0x7b0b, 0, NULL); + if (cmdline_size > 1) { + tagptr = put_tag(tagptr, 0x1001, + cmdline_size, kernel_cmdline); + } + tagptr = put_tag(tagptr, 0x7e0b, 0, NULL); + } + uint64_t elf_entry; + uint64_t elf_lowaddr; + int success = load_elf(kernel_filename, translate_phys_addr, env, + &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0); + if (success > 0) { + env->pc = elf_entry; + } + } else { + if (flash) { + MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash); + MemoryRegion *flash_io = g_malloc(sizeof(*flash_io)); + + memory_region_init_alias(flash_io, "lx60.flash", + flash_mr, 0, board->flash_size); + memory_region_add_subregion(system_memory, 0xfe000000, + flash_io); + } + } +} + +static void xtensa_lx60_init(QEMUMachineInitArgs *args) +{ + static const LxBoardDesc lx60_board = { + .flash_size = 0x400000, + .flash_sector_size = 0x10000, + .sram_size = 0x20000, + }; + lx_init(&lx60_board, args); +} + +static void xtensa_lx200_init(QEMUMachineInitArgs *args) +{ + static const LxBoardDesc lx200_board = { + .flash_size = 0x1000000, + .flash_sector_size = 0x20000, + .sram_size = 0x2000000, + }; + lx_init(&lx200_board, args); +} + +static QEMUMachine xtensa_lx60_machine = { + .name = "lx60", + .desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")", + .init = xtensa_lx60_init, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static QEMUMachine xtensa_lx200_machine = { + .name = "lx200", + .desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")", + .init = xtensa_lx200_init, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static void xtensa_lx_machines_init(void) +{ + qemu_register_machine(&xtensa_lx60_machine); + qemu_register_machine(&xtensa_lx200_machine); +} + +machine_init(xtensa_lx_machines_init); diff --git a/hw/xtensa/xtensa_sim.c b/hw/xtensa/xtensa_sim.c new file mode 100644 index 0000000000..5241f8d734 --- /dev/null +++ b/hw/xtensa/xtensa_sim.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "elf.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" + +static uint64_t translate_phys_addr(void *env, uint64_t addr) +{ + return cpu_get_phys_page_debug(env, addr); +} + +static void sim_reset(void *opaque) +{ + XtensaCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static void xtensa_sim_init(QEMUMachineInitArgs *args) +{ + XtensaCPU *cpu = NULL; + CPUXtensaState *env = NULL; + MemoryRegion *ram, *rom; + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + int n; + + if (!cpu_model) { + cpu_model = XTENSA_DEFAULT_CPU_MODEL; + } + + for (n = 0; n < smp_cpus; n++) { + cpu = cpu_xtensa_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + env->sregs[PRID] = n; + qemu_register_reset(sim_reset, cpu); + /* Need MMU initialized prior to ELF loading, + * so that ELF gets loaded into virtual addresses + */ + sim_reset(cpu); + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, "xtensa.sram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(get_system_memory(), 0, ram); + + rom = g_malloc(sizeof(*rom)); + memory_region_init_ram(rom, "xtensa.rom", 0x1000); + vmstate_register_ram_global(rom); + memory_region_add_subregion(get_system_memory(), 0xfe000000, rom); + + if (kernel_filename) { + uint64_t elf_entry; + uint64_t elf_lowaddr; +#ifdef TARGET_WORDS_BIGENDIAN + int success = load_elf(kernel_filename, translate_phys_addr, env, + &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); +#else + int success = load_elf(kernel_filename, translate_phys_addr, env, + &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0); +#endif + if (success > 0) { + env->pc = elf_entry; + } + } +} + +static QEMUMachine xtensa_sim_machine = { + .name = "sim", + .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")", + .is_default = true, + .init = xtensa_sim_init, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static void xtensa_sim_machine_init(void) +{ + qemu_register_machine(&xtensa_sim_machine); +} + +machine_init(xtensa_sim_machine_init); diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c deleted file mode 100644 index f2a63d82da..0000000000 --- a/hw/xtensa_lx60.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the Open Source and Linux Lab nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "exec/memory.h" -#include "exec/address-spaces.h" -#include "hw/serial.h" -#include "net/net.h" -#include "hw/sysbus.h" -#include "hw/flash.h" -#include "sysemu/blockdev.h" -#include "char/char.h" -#include "hw/xtensa_bootparam.h" - -typedef struct LxBoardDesc { - size_t flash_size; - size_t flash_sector_size; - size_t sram_size; -} LxBoardDesc; - -typedef struct Lx60FpgaState { - MemoryRegion iomem; - uint32_t leds; - uint32_t switches; -} Lx60FpgaState; - -static void lx60_fpga_reset(void *opaque) -{ - Lx60FpgaState *s = opaque; - - s->leds = 0; - s->switches = 0; -} - -static uint64_t lx60_fpga_read(void *opaque, hwaddr addr, - unsigned size) -{ - Lx60FpgaState *s = opaque; - - switch (addr) { - case 0x0: /*build date code*/ - return 0x09272011; - - case 0x4: /*processor clock frequency, Hz*/ - return 10000000; - - case 0x8: /*LEDs (off = 0, on = 1)*/ - return s->leds; - - case 0xc: /*DIP switches (off = 0, on = 1)*/ - return s->switches; - } - return 0; -} - -static void lx60_fpga_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - Lx60FpgaState *s = opaque; - - switch (addr) { - case 0x8: /*LEDs (off = 0, on = 1)*/ - s->leds = val; - break; - - case 0x10: /*board reset*/ - if (val == 0xdead) { - qemu_system_reset_request(); - } - break; - } -} - -static const MemoryRegionOps lx60_fpga_ops = { - .read = lx60_fpga_read, - .write = lx60_fpga_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space, - hwaddr base) -{ - Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState)); - - memory_region_init_io(&s->iomem, &lx60_fpga_ops, s, - "lx60.fpga", 0x10000); - memory_region_add_subregion(address_space, base, &s->iomem); - lx60_fpga_reset(s); - qemu_register_reset(lx60_fpga_reset, s); - return s; -} - -static void lx60_net_init(MemoryRegion *address_space, - hwaddr base, - hwaddr descriptors, - hwaddr buffers, - qemu_irq irq, NICInfo *nd) -{ - DeviceState *dev; - SysBusDevice *s; - MemoryRegion *ram; - - dev = qdev_create(NULL, "open_eth"); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, irq); - memory_region_add_subregion(address_space, base, - sysbus_mmio_get_region(s, 0)); - memory_region_add_subregion(address_space, descriptors, - sysbus_mmio_get_region(s, 1)); - - ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, "open_eth.ram", 16384); - vmstate_register_ram_global(ram); - memory_region_add_subregion(address_space, buffers, ram); -} - -static uint64_t translate_phys_addr(void *env, uint64_t addr) -{ - return cpu_get_phys_page_debug(env, addr); -} - -static void lx60_reset(void *opaque) -{ - XtensaCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) -{ -#ifdef TARGET_WORDS_BIGENDIAN - int be = 1; -#else - int be = 0; -#endif - MemoryRegion *system_memory = get_system_memory(); - XtensaCPU *cpu = NULL; - CPUXtensaState *env = NULL; - MemoryRegion *ram, *rom, *system_io; - DriveInfo *dinfo; - pflash_t *flash = NULL; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - int n; - - if (!cpu_model) { - cpu_model = XTENSA_DEFAULT_CPU_MODEL; - } - - for (n = 0; n < smp_cpus; n++) { - cpu = cpu_xtensa_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - env->sregs[PRID] = n; - qemu_register_reset(lx60_reset, cpu); - /* Need MMU initialized prior to ELF loading, - * so that ELF gets loaded into virtual addresses - */ - cpu_reset(CPU(cpu)); - } - - ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, "lx60.dram", args->ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(system_memory, 0, ram); - - system_io = g_malloc(sizeof(*system_io)); - memory_region_init(system_io, "lx60.io", 224 * 1024 * 1024); - memory_region_add_subregion(system_memory, 0xf0000000, system_io); - lx60_fpga_init(system_io, 0x0d020000); - if (nd_table[0].used) { - lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000, - xtensa_get_extint(env, 1), nd_table); - } - - if (!serial_hds[0]) { - serial_hds[0] = qemu_chr_new("serial0", "null", NULL); - } - - serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0), - 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); - - dinfo = drive_get(IF_PFLASH, 0, 0); - if (dinfo) { - flash = pflash_cfi01_register(0xf8000000, - NULL, "lx60.io.flash", board->flash_size, - dinfo->bdrv, board->flash_sector_size, - board->flash_size / board->flash_sector_size, - 4, 0x0000, 0x0000, 0x0000, 0x0000, be); - if (flash == NULL) { - fprintf(stderr, "Unable to mount pflash\n"); - exit(1); - } - } - - /* Use presence of kernel file name as 'boot from SRAM' switch. */ - if (kernel_filename) { - rom = g_malloc(sizeof(*rom)); - memory_region_init_ram(rom, "lx60.sram", board->sram_size); - vmstate_register_ram_global(rom); - memory_region_add_subregion(system_memory, 0xfe000000, rom); - - /* Put kernel bootparameters to the end of that SRAM */ - if (kernel_cmdline) { - size_t cmdline_size = strlen(kernel_cmdline) + 1; - size_t bp_size = sizeof(BpTag[4]) + cmdline_size; - uint32_t tagptr = (0xfe000000 + board->sram_size - bp_size) & ~0xff; - - env->regs[2] = tagptr; - - tagptr = put_tag(tagptr, 0x7b0b, 0, NULL); - if (cmdline_size > 1) { - tagptr = put_tag(tagptr, 0x1001, - cmdline_size, kernel_cmdline); - } - tagptr = put_tag(tagptr, 0x7e0b, 0, NULL); - } - uint64_t elf_entry; - uint64_t elf_lowaddr; - int success = load_elf(kernel_filename, translate_phys_addr, env, - &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0); - if (success > 0) { - env->pc = elf_entry; - } - } else { - if (flash) { - MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash); - MemoryRegion *flash_io = g_malloc(sizeof(*flash_io)); - - memory_region_init_alias(flash_io, "lx60.flash", - flash_mr, 0, board->flash_size); - memory_region_add_subregion(system_memory, 0xfe000000, - flash_io); - } - } -} - -static void xtensa_lx60_init(QEMUMachineInitArgs *args) -{ - static const LxBoardDesc lx60_board = { - .flash_size = 0x400000, - .flash_sector_size = 0x10000, - .sram_size = 0x20000, - }; - lx_init(&lx60_board, args); -} - -static void xtensa_lx200_init(QEMUMachineInitArgs *args) -{ - static const LxBoardDesc lx200_board = { - .flash_size = 0x1000000, - .flash_sector_size = 0x20000, - .sram_size = 0x2000000, - }; - lx_init(&lx200_board, args); -} - -static QEMUMachine xtensa_lx60_machine = { - .name = "lx60", - .desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")", - .init = xtensa_lx60_init, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static QEMUMachine xtensa_lx200_machine = { - .name = "lx200", - .desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")", - .init = xtensa_lx200_init, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static void xtensa_lx_machines_init(void) -{ - qemu_register_machine(&xtensa_lx60_machine); - qemu_register_machine(&xtensa_lx200_machine); -} - -machine_init(xtensa_lx_machines_init); diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c deleted file mode 100644 index f485a1465c..0000000000 --- a/hw/xtensa_pic.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the Open Source and Linux Lab nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "hw/hw.h" -#include "qemu/log.h" -#include "qemu/timer.h" - -void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d) -{ - uint32_t old_ccount = env->sregs[CCOUNT]; - - env->sregs[CCOUNT] += d; - - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { - int i; - for (i = 0; i < env->config->nccompare; ++i) { - if (env->sregs[CCOMPARE + i] - old_ccount <= d) { - xtensa_timer_irq(env, i, 1); - } - } - } -} - -void check_interrupts(CPUXtensaState *env) -{ - int minlevel = xtensa_get_cintlevel(env); - uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; - int level; - - /* If the CPU is halted advance CCOUNT according to the vm_clock time - * elapsed since the moment when it was advanced last time. - */ - if (env->halted) { - int64_t now = qemu_get_clock_ns(vm_clock); - - xtensa_advance_ccount(env, - muldiv64(now - env->halt_clock, - env->config->clock_freq_khz, 1000000)); - env->halt_clock = now; - } - for (level = env->config->nlevel; level > minlevel; --level) { - if (env->config->level_mask[level] & int_set_enabled) { - env->pending_irq_level = level; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - qemu_log_mask(CPU_LOG_INT, - "%s level = %d, cintlevel = %d, " - "pc = %08x, a0 = %08x, ps = %08x, " - "intset = %08x, intenable = %08x, " - "ccount = %08x\n", - __func__, level, xtensa_get_cintlevel(env), - env->pc, env->regs[0], env->sregs[PS], - env->sregs[INTSET], env->sregs[INTENABLE], - env->sregs[CCOUNT]); - return; - } - } - env->pending_irq_level = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); -} - -static void xtensa_set_irq(void *opaque, int irq, int active) -{ - CPUXtensaState *env = opaque; - - if (irq >= env->config->ninterrupt) { - qemu_log("%s: bad IRQ %d\n", __func__, irq); - } else { - uint32_t irq_bit = 1 << irq; - - if (active) { - env->sregs[INTSET] |= irq_bit; - } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) { - env->sregs[INTSET] &= ~irq_bit; - } - - check_interrupts(env); - } -} - -void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active) -{ - qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active); -} - -void xtensa_rearm_ccompare_timer(CPUXtensaState *env) -{ - int i; - uint32_t wake_ccount = env->sregs[CCOUNT] - 1; - - for (i = 0; i < env->config->nccompare; ++i) { - if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] < - wake_ccount - env->sregs[CCOUNT]) { - wake_ccount = env->sregs[CCOMPARE + i]; - } - } - env->wake_ccount = wake_ccount; - qemu_mod_timer(env->ccompare_timer, env->halt_clock + - muldiv64(wake_ccount - env->sregs[CCOUNT], - 1000000, env->config->clock_freq_khz)); -} - -static void xtensa_ccompare_cb(void *opaque) -{ - XtensaCPU *cpu = opaque; - CPUXtensaState *env = &cpu->env; - - if (env->halted) { - env->halt_clock = qemu_get_clock_ns(vm_clock); - xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); - if (!cpu_has_work(CPU(cpu))) { - env->sregs[CCOUNT] = env->wake_ccount + 1; - xtensa_rearm_ccompare_timer(env); - } - } -} - -void xtensa_irq_init(CPUXtensaState *env) -{ - XtensaCPU *cpu = xtensa_env_get_cpu(env); - - env->irq_inputs = (void **)qemu_allocate_irqs( - xtensa_set_irq, env, env->config->ninterrupt); - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) && - env->config->nccompare > 0) { - env->ccompare_timer = - qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu); - } -} - -void *xtensa_get_extint(CPUXtensaState *env, unsigned extint) -{ - if (extint < env->config->nextint) { - unsigned irq = env->config->extint[extint]; - return env->irq_inputs[irq]; - } else { - qemu_log("%s: trying to acquire invalid external interrupt %d\n", - __func__, extint); - return NULL; - } -} diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c deleted file mode 100644 index 5241f8d734..0000000000 --- a/hw/xtensa_sim.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the Open Source and Linux Lab nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "exec/memory.h" -#include "exec/address-spaces.h" - -static uint64_t translate_phys_addr(void *env, uint64_t addr) -{ - return cpu_get_phys_page_debug(env, addr); -} - -static void sim_reset(void *opaque) -{ - XtensaCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -static void xtensa_sim_init(QEMUMachineInitArgs *args) -{ - XtensaCPU *cpu = NULL; - CPUXtensaState *env = NULL; - MemoryRegion *ram, *rom; - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - int n; - - if (!cpu_model) { - cpu_model = XTENSA_DEFAULT_CPU_MODEL; - } - - for (n = 0; n < smp_cpus; n++) { - cpu = cpu_xtensa_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - env->sregs[PRID] = n; - qemu_register_reset(sim_reset, cpu); - /* Need MMU initialized prior to ELF loading, - * so that ELF gets loaded into virtual addresses - */ - sim_reset(cpu); - } - - ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, "xtensa.sram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(get_system_memory(), 0, ram); - - rom = g_malloc(sizeof(*rom)); - memory_region_init_ram(rom, "xtensa.rom", 0x1000); - vmstate_register_ram_global(rom); - memory_region_add_subregion(get_system_memory(), 0xfe000000, rom); - - if (kernel_filename) { - uint64_t elf_entry; - uint64_t elf_lowaddr; -#ifdef TARGET_WORDS_BIGENDIAN - int success = load_elf(kernel_filename, translate_phys_addr, env, - &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); -#else - int success = load_elf(kernel_filename, translate_phys_addr, env, - &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0); -#endif - if (success > 0) { - env->pc = elf_entry; - } - } -} - -static QEMUMachine xtensa_sim_machine = { - .name = "sim", - .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")", - .is_default = true, - .init = xtensa_sim_init, - .max_cpus = 4, - DEFAULT_MACHINE_OPTIONS, -}; - -static void xtensa_sim_machine_init(void) -{ - qemu_register_machine(&xtensa_sim_machine); -} - -machine_init(xtensa_sim_machine_init); diff --git a/hw/z2.c b/hw/z2.c deleted file mode 100644 index cbb6d8085e..0000000000 --- a/hw/z2.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * PXA270-based Zipit Z2 device - * - * Copyright (c) 2011 by Vasily Khoruzhick - * - * Code is based on mainstone platform. - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "hw/hw.h" -#include "hw/pxa.h" -#include "hw/arm-misc.h" -#include "hw/devices.h" -#include "hw/i2c.h" -#include "hw/ssi.h" -#include "hw/boards.h" -#include "sysemu/sysemu.h" -#include "hw/flash.h" -#include "sysemu/blockdev.h" -#include "ui/console.h" -#include "audio/audio.h" -#include "exec/address-spaces.h" - -#ifdef DEBUG_Z2 -#define DPRINTF(fmt, ...) \ - printf(fmt, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) -#endif - -static struct keymap map[0x100] = { - [0 ... 0xff] = { -1, -1 }, - [0x3b] = {0, 0}, /* Option = F1 */ - [0xc8] = {0, 1}, /* Up */ - [0xd0] = {0, 2}, /* Down */ - [0xcb] = {0, 3}, /* Left */ - [0xcd] = {0, 4}, /* Right */ - [0xcf] = {0, 5}, /* End */ - [0x0d] = {0, 6}, /* KPPLUS */ - [0xc7] = {1, 0}, /* Home */ - [0x10] = {1, 1}, /* Q */ - [0x17] = {1, 2}, /* I */ - [0x22] = {1, 3}, /* G */ - [0x2d] = {1, 4}, /* X */ - [0x1c] = {1, 5}, /* Enter */ - [0x0c] = {1, 6}, /* KPMINUS */ - [0xc9] = {2, 0}, /* PageUp */ - [0x11] = {2, 1}, /* W */ - [0x18] = {2, 2}, /* O */ - [0x23] = {2, 3}, /* H */ - [0x2e] = {2, 4}, /* C */ - [0x38] = {2, 5}, /* LeftAlt */ - [0xd1] = {3, 0}, /* PageDown */ - [0x12] = {3, 1}, /* E */ - [0x19] = {3, 2}, /* P */ - [0x24] = {3, 3}, /* J */ - [0x2f] = {3, 4}, /* V */ - [0x2a] = {3, 5}, /* LeftShift */ - [0x01] = {4, 0}, /* Esc */ - [0x13] = {4, 1}, /* R */ - [0x1e] = {4, 2}, /* A */ - [0x25] = {4, 3}, /* K */ - [0x30] = {4, 4}, /* B */ - [0x1d] = {4, 5}, /* LeftCtrl */ - [0x0f] = {5, 0}, /* Tab */ - [0x14] = {5, 1}, /* T */ - [0x1f] = {5, 2}, /* S */ - [0x26] = {5, 3}, /* L */ - [0x31] = {5, 4}, /* N */ - [0x39] = {5, 5}, /* Space */ - [0x3c] = {6, 0}, /* Stop = F2 */ - [0x15] = {6, 1}, /* Y */ - [0x20] = {6, 2}, /* D */ - [0x0e] = {6, 3}, /* Backspace */ - [0x32] = {6, 4}, /* M */ - [0x33] = {6, 5}, /* Comma */ - [0x3d] = {7, 0}, /* Play = F3 */ - [0x16] = {7, 1}, /* U */ - [0x21] = {7, 2}, /* F */ - [0x2c] = {7, 3}, /* Z */ - [0x27] = {7, 4}, /* Semicolon */ - [0x34] = {7, 5}, /* Dot */ -}; - -#define Z2_RAM_SIZE 0x02000000 -#define Z2_FLASH_BASE 0x00000000 -#define Z2_FLASH_SIZE 0x00800000 - -static struct arm_boot_info z2_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = Z2_RAM_SIZE, -}; - -#define Z2_GPIO_SD_DETECT 96 -#define Z2_GPIO_AC_IN 0 -#define Z2_GPIO_KEY_ON 1 -#define Z2_GPIO_LCD_CS 88 - -typedef struct { - SSISlave ssidev; - int32_t selected; - int32_t enabled; - uint8_t buf[3]; - uint32_t cur_reg; - int pos; -} ZipitLCD; - -static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value) -{ - ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); - uint16_t val; - if (z->selected) { - z->buf[z->pos] = value & 0xff; - z->pos++; - } - if (z->pos == 3) { - switch (z->buf[0]) { - case 0x74: - DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]); - z->cur_reg = z->buf[2]; - break; - case 0x76: - val = z->buf[1] << 8 | z->buf[2]; - DPRINTF("%s: value: 0x%.4x\n", __func__, val); - if (z->cur_reg == 0x22 && val == 0x0000) { - z->enabled = 1; - printf("%s: LCD enabled\n", __func__); - } else if (z->cur_reg == 0x10 && val == 0x0000) { - z->enabled = 0; - printf("%s: LCD disabled\n", __func__); - } - break; - default: - DPRINTF("%s: unknown command!\n", __func__); - break; - } - z->pos = 0; - } - return 0; -} - -static void z2_lcd_cs(void *opaque, int line, int level) -{ - ZipitLCD *z2_lcd = opaque; - z2_lcd->selected = !level; -} - -static int zipit_lcd_init(SSISlave *dev) -{ - ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); - z->selected = 0; - z->enabled = 0; - z->pos = 0; - - return 0; -} - -static VMStateDescription vmstate_zipit_lcd_state = { - .name = "zipit-lcd", - .version_id = 2, - .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { - VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), - VMSTATE_INT32(selected, ZipitLCD), - VMSTATE_INT32(enabled, ZipitLCD), - VMSTATE_BUFFER(buf, ZipitLCD), - VMSTATE_UINT32(cur_reg, ZipitLCD), - VMSTATE_INT32(pos, ZipitLCD), - VMSTATE_END_OF_LIST(), - } -}; - -static void zipit_lcd_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = zipit_lcd_init; - k->transfer = zipit_lcd_transfer; - dc->vmsd = &vmstate_zipit_lcd_state; -} - -static const TypeInfo zipit_lcd_info = { - .name = "zipit-lcd", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(ZipitLCD), - .class_init = zipit_lcd_class_init, -}; - -typedef struct { - I2CSlave i2c; - int len; - uint8_t buf[3]; -} AER915State; - -static int aer915_send(I2CSlave *i2c, uint8_t data) -{ - AER915State *s = FROM_I2C_SLAVE(AER915State, i2c); - s->buf[s->len] = data; - if (s->len++ > 2) { - DPRINTF("%s: message too long (%i bytes)\n", - __func__, s->len); - return 1; - } - - if (s->len == 2) { - DPRINTF("%s: reg %d value 0x%02x\n", __func__, - s->buf[0], s->buf[1]); - } - - return 0; -} - -static void aer915_event(I2CSlave *i2c, enum i2c_event event) -{ - AER915State *s = FROM_I2C_SLAVE(AER915State, i2c); - switch (event) { - case I2C_START_SEND: - s->len = 0; - break; - case I2C_START_RECV: - if (s->len != 1) { - DPRINTF("%s: short message!?\n", __func__); - } - break; - case I2C_FINISH: - break; - default: - break; - } -} - -static int aer915_recv(I2CSlave *slave) -{ - int retval = 0x00; - AER915State *s = FROM_I2C_SLAVE(AER915State, slave); - - switch (s->buf[0]) { - /* Return hardcoded battery voltage, - * 0xf0 means ~4.1V - */ - case 0x02: - retval = 0xf0; - break; - /* Return 0x00 for other regs, - * we don't know what they are for, - * anyway they return 0x00 on real hardware. - */ - default: - break; - } - - return retval; -} - -static int aer915_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - -static VMStateDescription vmstate_aer915_state = { - .name = "aer915", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(len, AER915State), - VMSTATE_BUFFER(buf, AER915State), - VMSTATE_END_OF_LIST(), - } -}; - -static void aer915_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = aer915_init; - k->event = aer915_event; - k->recv = aer915_recv; - k->send = aer915_send; - dc->vmsd = &vmstate_aer915_state; -} - -static const TypeInfo aer915_info = { - .name = "aer915", - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(AER915State), - .class_init = aer915_class_init, -}; - -static void z2_init(QEMUMachineInitArgs *args) -{ - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - MemoryRegion *address_space_mem = get_system_memory(); - uint32_t sector_len = 0x10000; - PXA2xxState *mpu; - DriveInfo *dinfo; - int be; - void *z2_lcd; - i2c_bus *bus; - DeviceState *wm; - - if (!cpu_model) { - cpu_model = "pxa270-c5"; - } - - /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model); - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo) { - fprintf(stderr, "Flash image must be given with the " - "'pflash' parameter\n"); - exit(1); - } - - if (!pflash_cfi01_register(Z2_FLASH_BASE, - NULL, "z2.flash0", Z2_FLASH_SIZE, - dinfo->bdrv, sector_len, - Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0, - be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - - /* setup keypad */ - pxa27x_register_keypad(mpu->kp, map, 0x100); - - /* MMC/SD host */ - pxa2xx_mmci_handlers(mpu->mmc, - NULL, - qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT)); - - type_register_static(&zipit_lcd_info); - type_register_static(&aer915_info); - z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd"); - bus = pxa2xx_i2c_bus(mpu->i2c[0]); - i2c_create_slave(bus, "aer915", 0x55); - wm = i2c_create_slave(bus, "wm8750", 0x1b); - mpu->i2s->opaque = wm; - mpu->i2s->codec_out = wm8750_dac_dat; - mpu->i2s->codec_in = wm8750_adc_dat; - wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s); - - qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS, - qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]); - - if (kernel_filename) { - z2_binfo.kernel_filename = kernel_filename; - z2_binfo.kernel_cmdline = kernel_cmdline; - z2_binfo.initrd_filename = initrd_filename; - z2_binfo.board_id = 0x6dd; - arm_load_kernel(mpu->cpu, &z2_binfo); - } -} - -static QEMUMachine z2_machine = { - .name = "z2", - .desc = "Zipit Z2 (PXA27x)", - .init = z2_init, - DEFAULT_MACHINE_OPTIONS, -}; - -static void z2_machine_init(void) -{ - qemu_register_machine(&z2_machine); -} - -machine_init(z2_machine_init); -- cgit v1.2.3 From dd285b06490d7ef5f7b2f5e6c87b85ddf4345078 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: arm: move files referencing CPU to hw/arm/ Signed-off-by: Paolo Bonzini --- hw/arm/Makefile.objs | 13 +- hw/arm/armv7m.c | 284 ++++ hw/arm/exynos4210.c | 349 +++++ hw/arm/omap1.c | 4056 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/arm/omap2.c | 2684 +++++++++++++++++++++++++++++++++ hw/arm/pxa2xx.c | 2291 ++++++++++++++++++++++++++++ hw/arm/pxa2xx_gpio.c | 350 +++++ hw/arm/pxa2xx_pic.c | 334 +++++ hw/armv7m.c | 284 ---- hw/exynos4210.c | 349 ----- hw/omap1.c | 4056 -------------------------------------------------- hw/omap2.c | 2684 --------------------------------- hw/pxa2xx.c | 2291 ---------------------------- hw/pxa2xx_gpio.c | 350 ----- hw/pxa2xx_pic.c | 334 ----- 15 files changed, 10356 insertions(+), 10353 deletions(-) create mode 100644 hw/arm/armv7m.c create mode 100644 hw/arm/exynos4210.c create mode 100644 hw/arm/omap1.c create mode 100644 hw/arm/omap2.c create mode 100644 hw/arm/pxa2xx.c create mode 100644 hw/arm/pxa2xx_gpio.c create mode 100644 hw/arm/pxa2xx_pic.c delete mode 100644 hw/armv7m.c delete mode 100644 hw/exynos4210.c delete mode 100644 hw/omap1.c delete mode 100644 hw/omap2.c delete mode 100644 hw/pxa2xx.c delete mode 100644 hw/pxa2xx_gpio.c delete mode 100644 hw/pxa2xx_pic.c diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index c09cc3aae8..aebbc866e2 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -3,18 +3,18 @@ obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += a9scu.o obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o -obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o +obj-y += exynos4210_gic.o exynos4210_combiner.o obj-y += exynos4210_uart.o exynos4210_pwm.o obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o obj-y += exynos4210_rtc.o exynos4210_i2c.o obj-y += arm_mptimer.o a15mpcore.o -obj-y += armv7m.o armv7m_nvic.o stellaris_enet.o -obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o +obj-y += armv7m_nvic.o stellaris_enet.o +obj-y += pxa2xx_timer.o pxa2xx_dma.o obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o obj-y += zaurus.o ide/microdrive.o tc6393xb.o -obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ +obj-y += omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ omap_gpio.o omap_intc.o omap_uart.o -obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ +obj-y += omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o obj-y += tsc210x.o obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o @@ -30,3 +30,6 @@ obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o + +obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o +obj-y += omap1.o omap2.o diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c new file mode 100644 index 0000000000..1d5bb592c4 --- /dev/null +++ b/hw/arm/armv7m.c @@ -0,0 +1,284 @@ +/* + * ARMV7M System emulation. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL. + */ + +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/loader.h" +#include "elf.h" + +/* Bitbanded IO. Each word corresponds to a single bit. */ + +/* Get the byte address of the real memory for a bitband access. */ +static inline uint32_t bitband_addr(void * opaque, uint32_t addr) +{ + uint32_t res; + + res = *(uint32_t *)opaque; + res |= (addr & 0x1ffffff) >> 5; + return res; + +} + +static uint32_t bitband_readb(void *opaque, hwaddr offset) +{ + uint8_t v; + cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1); + return (v & (1 << ((offset >> 2) & 7))) != 0; +} + +static void bitband_writeb(void *opaque, hwaddr offset, + uint32_t value) +{ + uint32_t addr; + uint8_t mask; + uint8_t v; + addr = bitband_addr(opaque, offset); + mask = (1 << ((offset >> 2) & 7)); + cpu_physical_memory_read(addr, &v, 1); + if (value & 1) + v |= mask; + else + v &= ~mask; + cpu_physical_memory_write(addr, &v, 1); +} + +static uint32_t bitband_readw(void *opaque, hwaddr offset) +{ + uint32_t addr; + uint16_t mask; + uint16_t v; + addr = bitband_addr(opaque, offset) & ~1; + mask = (1 << ((offset >> 2) & 15)); + mask = tswap16(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 2); + return (v & mask) != 0; +} + +static void bitband_writew(void *opaque, hwaddr offset, + uint32_t value) +{ + uint32_t addr; + uint16_t mask; + uint16_t v; + addr = bitband_addr(opaque, offset) & ~1; + mask = (1 << ((offset >> 2) & 15)); + mask = tswap16(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 2); + if (value & 1) + v |= mask; + else + v &= ~mask; + cpu_physical_memory_write(addr, (uint8_t *)&v, 2); +} + +static uint32_t bitband_readl(void *opaque, hwaddr offset) +{ + uint32_t addr; + uint32_t mask; + uint32_t v; + addr = bitband_addr(opaque, offset) & ~3; + mask = (1 << ((offset >> 2) & 31)); + mask = tswap32(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 4); + return (v & mask) != 0; +} + +static void bitband_writel(void *opaque, hwaddr offset, + uint32_t value) +{ + uint32_t addr; + uint32_t mask; + uint32_t v; + addr = bitband_addr(opaque, offset) & ~3; + mask = (1 << ((offset >> 2) & 31)); + mask = tswap32(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 4); + if (value & 1) + v |= mask; + else + v &= ~mask; + cpu_physical_memory_write(addr, (uint8_t *)&v, 4); +} + +static const MemoryRegionOps bitband_ops = { + .old_mmio = { + .read = { bitband_readb, bitband_readw, bitband_readl, }, + .write = { bitband_writeb, bitband_writew, bitband_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t base; +} BitBandState; + +static int bitband_init(SysBusDevice *dev) +{ + BitBandState *s = FROM_SYSBUS(BitBandState, dev); + + memory_region_init_io(&s->iomem, &bitband_ops, &s->base, "bitband", + 0x02000000); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static void armv7m_bitband_init(void) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "ARM,bitband-memory"); + qdev_prop_set_uint32(dev, "base", 0x20000000); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000); + + dev = qdev_create(NULL, "ARM,bitband-memory"); + qdev_prop_set_uint32(dev, "base", 0x40000000); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000); +} + +/* Board init. */ + +static void armv7m_reset(void *opaque) +{ + ARMCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +/* Init CPU and memory for a v7-M based board. + flash_size and sram_size are in kb. + Returns the NVIC array. */ + +qemu_irq *armv7m_init(MemoryRegion *address_space_mem, + int flash_size, int sram_size, + const char *kernel_filename, const char *cpu_model) +{ + ARMCPU *cpu; + CPUARMState *env; + DeviceState *nvic; + /* FIXME: make this local state. */ + static qemu_irq pic[64]; + qemu_irq *cpu_pic; + int image_size; + uint64_t entry; + uint64_t lowaddr; + int i; + int big_endian; + MemoryRegion *sram = g_new(MemoryRegion, 1); + MemoryRegion *flash = g_new(MemoryRegion, 1); + MemoryRegion *hack = g_new(MemoryRegion, 1); + + flash_size *= 1024; + sram_size *= 1024; + + if (cpu_model == NULL) { + cpu_model = "cortex-m3"; + } + cpu = cpu_arm_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + +#if 0 + /* > 32Mb SRAM gets complicated because it overlaps the bitband area. + We don't have proper commandline options, so allocate half of memory + as SRAM, up to a maximum of 32Mb, and the rest as code. */ + if (ram_size > (512 + 32) * 1024 * 1024) + ram_size = (512 + 32) * 1024 * 1024; + sram_size = (ram_size / 2) & TARGET_PAGE_MASK; + if (sram_size > 32 * 1024 * 1024) + sram_size = 32 * 1024 * 1024; + code_size = ram_size - sram_size; +#endif + + /* Flash programming is done via the SCU, so pretend it is ROM. */ + memory_region_init_ram(flash, "armv7m.flash", flash_size); + vmstate_register_ram_global(flash); + memory_region_set_readonly(flash, true); + memory_region_add_subregion(address_space_mem, 0, flash); + memory_region_init_ram(sram, "armv7m.sram", sram_size); + vmstate_register_ram_global(sram); + memory_region_add_subregion(address_space_mem, 0x20000000, sram); + armv7m_bitband_init(); + + nvic = qdev_create(NULL, "armv7m_nvic"); + env->nvic = nvic; + qdev_init_nofail(nvic); + cpu_pic = arm_pic_init_cpu(cpu); + sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); + for (i = 0; i < 64; i++) { + pic[i] = qdev_get_gpio_in(nvic, i); + } + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + + if (!kernel_filename) { + fprintf(stderr, "Guest image must be specified (using -kernel)\n"); + exit(1); + } + + image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr, + NULL, big_endian, ELF_MACHINE, 1); + if (image_size < 0) { + image_size = load_image_targphys(kernel_filename, 0, flash_size); + lowaddr = 0; + } + if (image_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* Hack to map an additional page of ram at the top of the address + space. This stops qemu complaining about executing code outside RAM + when returning from an exception. */ + memory_region_init_ram(hack, "armv7m.hack", 0x1000); + vmstate_register_ram_global(hack); + memory_region_add_subregion(address_space_mem, 0xfffff000, hack); + + qemu_register_reset(armv7m_reset, cpu); + return pic; +} + +static Property bitband_properties[] = { + DEFINE_PROP_UINT32("base", BitBandState, base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void bitband_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = bitband_init; + dc->props = bitband_properties; +} + +static const TypeInfo bitband_info = { + .name = "ARM,bitband-memory", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BitBandState), + .class_init = bitband_class_init, +}; + +static void armv7m_register_types(void) +{ + type_register_static(&bitband_info); +} + +type_init(armv7m_register_types) diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c new file mode 100644 index 0000000000..4592514bb2 --- /dev/null +++ b/hw/arm/exynos4210.c @@ -0,0 +1,349 @@ +/* + * Samsung exynos4210 SoC emulation + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. + * Maksim Kozlov + * Evgeny Voevodin + * Igor Mitsyanko + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/loader.h" +#include "hw/exynos4210.h" +#include "hw/usb/hcd-ehci.h" + +#define EXYNOS4210_CHIPID_ADDR 0x10000000 + +/* PWM */ +#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000 + +/* RTC */ +#define EXYNOS4210_RTC_BASE_ADDR 0x10070000 + +/* MCT */ +#define EXYNOS4210_MCT_BASE_ADDR 0x10050000 + +/* I2C */ +#define EXYNOS4210_I2C_SHIFT 0x00010000 +#define EXYNOS4210_I2C_BASE_ADDR 0x13860000 +/* Interrupt Group of External Interrupt Combiner for I2C */ +#define EXYNOS4210_I2C_INTG 27 +#define EXYNOS4210_HDMI_INTG 16 + +/* UART's definitions */ +#define EXYNOS4210_UART0_BASE_ADDR 0x13800000 +#define EXYNOS4210_UART1_BASE_ADDR 0x13810000 +#define EXYNOS4210_UART2_BASE_ADDR 0x13820000 +#define EXYNOS4210_UART3_BASE_ADDR 0x13830000 +#define EXYNOS4210_UART0_FIFO_SIZE 256 +#define EXYNOS4210_UART1_FIFO_SIZE 64 +#define EXYNOS4210_UART2_FIFO_SIZE 16 +#define EXYNOS4210_UART3_FIFO_SIZE 16 +/* Interrupt Group of External Interrupt Combiner for UART */ +#define EXYNOS4210_UART_INT_GRP 26 + +/* External GIC */ +#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000 +#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000 + +/* Combiner */ +#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000 +#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000 + +/* PMU SFR base address */ +#define EXYNOS4210_PMU_BASE_ADDR 0x10020000 + +/* Display controllers (FIMD) */ +#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 + +/* EHCI */ +#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000 + +static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, + 0x09, 0x00, 0x00, 0x00 }; + +void exynos4210_write_secondary(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + int n; + uint32_t smpboot[] = { + 0xe59f3034, /* ldr r3, External gic_cpu_if */ + 0xe59f2034, /* ldr r2, Internal gic_cpu_if */ + 0xe59f0034, /* ldr r0, startaddr */ + 0xe3a01001, /* mov r1, #1 */ + 0xe5821000, /* str r1, [r2] */ + 0xe5831000, /* str r1, [r3] */ + 0xe3a010ff, /* mov r1, #0xff */ + 0xe5821004, /* str r1, [r2, #4] */ + 0xe5831004, /* str r1, [r3, #4] */ + 0xf57ff04f, /* dsb */ + 0xe320f003, /* wfi */ + 0xe5901000, /* ldr r1, [r0] */ + 0xe1110001, /* tst r1, r1 */ + 0x0afffffb, /* beq */ + 0xe12fff11, /* bx r1 */ + EXYNOS4210_EXT_GIC_CPU_BASE_ADDR, + 0, /* gic_cpu_if: base address of Internal GIC CPU interface */ + 0 /* bootreg: Boot register address is held here */ + }; + smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; + smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start); +} + +Exynos4210State *exynos4210_init(MemoryRegion *system_mem, + unsigned long ram_size) +{ + qemu_irq cpu_irq[EXYNOS4210_NCPUS]; + int i, n; + Exynos4210State *s = g_new(Exynos4210State, 1); + qemu_irq *irqp; + qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; + unsigned long mem_size; + DeviceState *dev; + SysBusDevice *busdev; + + for (n = 0; n < EXYNOS4210_NCPUS; n++) { + s->cpu[n] = cpu_arm_init("cortex-a9"); + if (!s->cpu[n]) { + fprintf(stderr, "Unable to find CPU %d definition\n", n); + exit(1); + } + + /* Create PIC controller for each processor instance */ + irqp = arm_pic_init_cpu(s->cpu[n]); + + /* + * Get GICs gpio_in cpu_irq to connect a combiner to them later. + * Use only IRQ for a while. + */ + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + } + + /*** IRQs ***/ + + s->irq_table = exynos4210_init_irq(&s->irqs); + + /* IRQ Gate */ + for (i = 0; i < EXYNOS4210_NCPUS; i++) { + dev = qdev_create(NULL, "exynos4210.irq_gate"); + qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); + qdev_init_nofail(dev); + /* Get IRQ Gate input in gate_irq */ + for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { + gate_irq[i][n] = qdev_get_gpio_in(dev, n); + } + busdev = SYS_BUS_DEVICE(dev); + + /* Connect IRQ Gate output to cpu_irq */ + sysbus_connect_irq(busdev, 0, cpu_irq[i]); + } + + /* Private memory region and Internal GIC */ + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); + for (n = 0; n < EXYNOS4210_NCPUS; n++) { + sysbus_connect_irq(busdev, n, gate_irq[n][0]); + } + for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) { + s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n); + } + + /* Cache controller */ + sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL); + + /* External GIC */ + dev = qdev_create(NULL, "exynos4210.gic"); + qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + /* Map CPU interface */ + sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); + /* Map Distributer interface */ + sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR); + for (n = 0; n < EXYNOS4210_NCPUS; n++) { + sysbus_connect_irq(busdev, n, gate_irq[n][1]); + } + for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) { + s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n); + } + + /* Internal Interrupt Combiner */ + dev = qdev_create(NULL, "exynos4210.combiner"); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { + sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); + } + exynos4210_combiner_get_gpioin(&s->irqs, dev, 0); + sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR); + + /* External Interrupt Combiner */ + dev = qdev_create(NULL, "exynos4210.combiner"); + qdev_prop_set_uint32(dev, "external", 1); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { + sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); + } + exynos4210_combiner_get_gpioin(&s->irqs, dev, 1); + sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR); + + /* Initialize board IRQs. */ + exynos4210_init_board_irqs(&s->irqs); + + /*** Memory ***/ + + /* Chip-ID and OMR */ + memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid", + sizeof(chipid_and_omr), chipid_and_omr); + memory_region_set_readonly(&s->chipid_mem, true); + memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR, + &s->chipid_mem); + + /* Internal ROM */ + memory_region_init_ram(&s->irom_mem, "exynos4210.irom", + EXYNOS4210_IROM_SIZE); + memory_region_set_readonly(&s->irom_mem, true); + memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR, + &s->irom_mem); + /* mirror of iROM */ + memory_region_init_alias(&s->irom_alias_mem, "exynos4210.irom_alias", + &s->irom_mem, + 0, + EXYNOS4210_IROM_SIZE); + memory_region_set_readonly(&s->irom_alias_mem, true); + memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR, + &s->irom_alias_mem); + + /* Internal RAM */ + memory_region_init_ram(&s->iram_mem, "exynos4210.iram", + EXYNOS4210_IRAM_SIZE); + vmstate_register_ram_global(&s->iram_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR, + &s->iram_mem); + + /* DRAM */ + mem_size = ram_size; + if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { + memory_region_init_ram(&s->dram1_mem, "exynos4210.dram1", + mem_size - EXYNOS4210_DRAM_MAX_SIZE); + vmstate_register_ram_global(&s->dram1_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, + &s->dram1_mem); + mem_size = EXYNOS4210_DRAM_MAX_SIZE; + } + memory_region_init_ram(&s->dram0_mem, "exynos4210.dram0", mem_size); + vmstate_register_ram_global(&s->dram0_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, + &s->dram0_mem); + + /* PMU. + * The only reason of existence at the moment is that secondary CPU boot + * loader uses PMU INFORM5 register as a holding pen. + */ + sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL); + + /* PWM */ + sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR, + s->irq_table[exynos4210_get_irq(22, 0)], + s->irq_table[exynos4210_get_irq(22, 1)], + s->irq_table[exynos4210_get_irq(22, 2)], + s->irq_table[exynos4210_get_irq(22, 3)], + s->irq_table[exynos4210_get_irq(22, 4)], + NULL); + /* RTC */ + sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR, + s->irq_table[exynos4210_get_irq(23, 0)], + s->irq_table[exynos4210_get_irq(23, 1)], + NULL); + + /* Multi Core Timer */ + dev = qdev_create(NULL, "exynos4210.mct"); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + for (n = 0; n < 4; n++) { + /* Connect global timer interrupts to Combiner gpio_in */ + sysbus_connect_irq(busdev, n, + s->irq_table[exynos4210_get_irq(1, 4 + n)]); + } + /* Connect local timer interrupts to Combiner gpio_in */ + sysbus_connect_irq(busdev, 4, + s->irq_table[exynos4210_get_irq(51, 0)]); + sysbus_connect_irq(busdev, 5, + s->irq_table[exynos4210_get_irq(35, 3)]); + sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR); + + /*** I2C ***/ + for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) { + uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n; + qemu_irq i2c_irq; + + if (n < 8) { + i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)]; + } else { + i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)]; + } + + dev = qdev_create(NULL, "exynos4210.i2c"); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, i2c_irq); + sysbus_mmio_map(busdev, 0, addr); + s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); + } + + + /*** UARTs ***/ + exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR, + EXYNOS4210_UART0_FIFO_SIZE, 0, NULL, + s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]); + + exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR, + EXYNOS4210_UART1_FIFO_SIZE, 1, NULL, + s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]); + + exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR, + EXYNOS4210_UART2_FIFO_SIZE, 2, NULL, + s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]); + + exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR, + EXYNOS4210_UART3_FIFO_SIZE, 3, NULL, + s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]); + + /*** Display controller (FIMD) ***/ + sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR, + s->irq_table[exynos4210_get_irq(11, 0)], + s->irq_table[exynos4210_get_irq(11, 1)], + s->irq_table[exynos4210_get_irq(11, 2)], + NULL); + + sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR, + s->irq_table[exynos4210_get_irq(28, 3)]); + + return s; +} diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c new file mode 100644 index 0000000000..6f0a8ca074 --- /dev/null +++ b/hw/arm/omap1.c @@ -0,0 +1,4056 @@ +/* + * TI OMAP processors emulation. + * + * Copyright (C) 2006-2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/omap.h" +#include "sysemu/sysemu.h" +#include "hw/soc_dma.h" +#include "sysemu/blockdev.h" +#include "qemu/range.h" +#include "hw/sysbus.h" + +/* Should signal the TCMI/GPMC */ +uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) +{ + uint8_t ret; + + OMAP_8B_REG(addr); + cpu_physical_memory_read(addr, (void *) &ret, 1); + return ret; +} + +void omap_badwidth_write8(void *opaque, hwaddr addr, + uint32_t value) +{ + uint8_t val8 = value; + + OMAP_8B_REG(addr); + cpu_physical_memory_write(addr, (void *) &val8, 1); +} + +uint32_t omap_badwidth_read16(void *opaque, hwaddr addr) +{ + uint16_t ret; + + OMAP_16B_REG(addr); + cpu_physical_memory_read(addr, (void *) &ret, 2); + return ret; +} + +void omap_badwidth_write16(void *opaque, hwaddr addr, + uint32_t value) +{ + uint16_t val16 = value; + + OMAP_16B_REG(addr); + cpu_physical_memory_write(addr, (void *) &val16, 2); +} + +uint32_t omap_badwidth_read32(void *opaque, hwaddr addr) +{ + uint32_t ret; + + OMAP_32B_REG(addr); + cpu_physical_memory_read(addr, (void *) &ret, 4); + return ret; +} + +void omap_badwidth_write32(void *opaque, hwaddr addr, + uint32_t value) +{ + OMAP_32B_REG(addr); + cpu_physical_memory_write(addr, (void *) &value, 4); +} + +/* MPU OS timers */ +struct omap_mpu_timer_s { + MemoryRegion iomem; + qemu_irq irq; + omap_clk clk; + uint32_t val; + int64_t time; + QEMUTimer *timer; + QEMUBH *tick; + int64_t rate; + int it_ena; + + int enable; + int ptv; + int ar; + int st; + uint32_t reset_val; +}; + +static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) +{ + uint64_t distance = qemu_get_clock_ns(vm_clock) - timer->time; + + if (timer->st && timer->enable && timer->rate) + return timer->val - muldiv64(distance >> (timer->ptv + 1), + timer->rate, get_ticks_per_sec()); + else + return timer->val; +} + +static inline void omap_timer_sync(struct omap_mpu_timer_s *timer) +{ + timer->val = omap_timer_read(timer); + timer->time = qemu_get_clock_ns(vm_clock); +} + +static inline void omap_timer_update(struct omap_mpu_timer_s *timer) +{ + int64_t expires; + + if (timer->enable && timer->st && timer->rate) { + timer->val = timer->reset_val; /* Should skip this on clk enable */ + expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1), + get_ticks_per_sec(), timer->rate); + + /* If timer expiry would be sooner than in about 1 ms and + * auto-reload isn't set, then fire immediately. This is a hack + * to make systems like PalmOS run in acceptable time. PalmOS + * sets the interval to a very low value and polls the status bit + * in a busy loop when it wants to sleep just a couple of CPU + * ticks. */ + if (expires > (get_ticks_per_sec() >> 10) || timer->ar) + qemu_mod_timer(timer->timer, timer->time + expires); + else + qemu_bh_schedule(timer->tick); + } else + qemu_del_timer(timer->timer); +} + +static void omap_timer_fire(void *opaque) +{ + struct omap_mpu_timer_s *timer = opaque; + + if (!timer->ar) { + timer->val = 0; + timer->st = 0; + } + + if (timer->it_ena) + /* Edge-triggered irq */ + qemu_irq_pulse(timer->irq); +} + +static void omap_timer_tick(void *opaque) +{ + struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + + omap_timer_sync(timer); + omap_timer_fire(timer); + omap_timer_update(timer); +} + +static void omap_timer_clk_update(void *opaque, int line, int on) +{ + struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + + omap_timer_sync(timer); + timer->rate = on ? omap_clk_getrate(timer->clk) : 0; + omap_timer_update(timer); +} + +static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) +{ + omap_clk_adduser(timer->clk, + qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]); + timer->rate = omap_clk_getrate(timer->clk); +} + +static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x00: /* CNTL_TIMER */ + return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; + + case 0x04: /* LOAD_TIM */ + break; + + case 0x08: /* READ_TIM */ + return omap_timer_read(s); + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpu_timer_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* CNTL_TIMER */ + omap_timer_sync(s); + s->enable = (value >> 5) & 1; + s->ptv = (value >> 2) & 7; + s->ar = (value >> 1) & 1; + s->st = value & 1; + omap_timer_update(s); + return; + + case 0x04: /* LOAD_TIM */ + s->reset_val = value; + return; + + case 0x08: /* READ_TIM */ + OMAP_RO_REG(addr); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_mpu_timer_ops = { + .read = omap_mpu_timer_read, + .write = omap_mpu_timer_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) +{ + qemu_del_timer(s->timer); + s->enable = 0; + s->reset_val = 31337; + s->val = 0; + s->ptv = 0; + s->ar = 0; + s->st = 0; + s->it_ena = 1; +} + +static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory, + hwaddr base, + qemu_irq irq, omap_clk clk) +{ + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) + g_malloc0(sizeof(struct omap_mpu_timer_s)); + + s->irq = irq; + s->clk = clk; + s->timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, s); + s->tick = qemu_bh_new(omap_timer_fire, s); + omap_mpu_timer_reset(s); + omap_timer_clk_setup(s); + + memory_region_init_io(&s->iomem, &omap_mpu_timer_ops, s, + "omap-mpu-timer", 0x100); + + memory_region_add_subregion(system_memory, base, &s->iomem); + + return s; +} + +/* Watchdog timer */ +struct omap_watchdog_timer_s { + struct omap_mpu_timer_s timer; + MemoryRegion iomem; + uint8_t last_wr; + int mode; + int free; + int reset; +}; + +static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (addr) { + case 0x00: /* CNTL_TIMER */ + return (s->timer.ptv << 9) | (s->timer.ar << 8) | + (s->timer.st << 7) | (s->free << 1); + + case 0x04: /* READ_TIMER */ + return omap_timer_read(&s->timer); + + case 0x08: /* TIMER_MODE */ + return s->mode << 15; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_wd_timer_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* CNTL_TIMER */ + omap_timer_sync(&s->timer); + s->timer.ptv = (value >> 9) & 7; + s->timer.ar = (value >> 8) & 1; + s->timer.st = (value >> 7) & 1; + s->free = (value >> 1) & 1; + omap_timer_update(&s->timer); + break; + + case 0x04: /* LOAD_TIMER */ + s->timer.reset_val = value & 0xffff; + break; + + case 0x08: /* TIMER_MODE */ + if (!s->mode && ((value >> 15) & 1)) + omap_clk_get(s->timer.clk); + s->mode |= (value >> 15) & 1; + if (s->last_wr == 0xf5) { + if ((value & 0xff) == 0xa0) { + if (s->mode) { + s->mode = 0; + omap_clk_put(s->timer.clk); + } + } else { + /* XXX: on T|E hardware somehow this has no effect, + * on Zire 71 it works as specified. */ + s->reset = 1; + qemu_system_reset_request(); + } + } + s->last_wr = value & 0xff; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_wd_timer_ops = { + .read = omap_wd_timer_read, + .write = omap_wd_timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) +{ + qemu_del_timer(s->timer.timer); + if (!s->mode) + omap_clk_get(s->timer.clk); + s->mode = 1; + s->free = 1; + s->reset = 0; + s->timer.enable = 1; + s->timer.it_ena = 1; + s->timer.reset_val = 0xffff; + s->timer.val = 0; + s->timer.st = 0; + s->timer.ptv = 0; + s->timer.ar = 0; + omap_timer_update(&s->timer); +} + +static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory, + hwaddr base, + qemu_irq irq, omap_clk clk) +{ + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) + g_malloc0(sizeof(struct omap_watchdog_timer_s)); + + s->timer.irq = irq; + s->timer.clk = clk; + s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer); + omap_wd_timer_reset(s); + omap_timer_clk_setup(&s->timer); + + memory_region_init_io(&s->iomem, &omap_wd_timer_ops, s, + "omap-wd-timer", 0x100); + memory_region_add_subregion(memory, base, &s->iomem); + + return s; +} + +/* 32-kHz timer */ +struct omap_32khz_timer_s { + struct omap_mpu_timer_s timer; + MemoryRegion iomem; +}; + +static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (offset) { + case 0x00: /* TVR */ + return s->timer.reset_val; + + case 0x04: /* TCR */ + return omap_timer_read(&s->timer); + + case 0x08: /* CR */ + return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_os_timer_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (offset) { + case 0x00: /* TVR */ + s->timer.reset_val = value & 0x00ffffff; + break; + + case 0x04: /* TCR */ + OMAP_RO_REG(addr); + break; + + case 0x08: /* CR */ + s->timer.ar = (value >> 3) & 1; + s->timer.it_ena = (value >> 2) & 1; + if (s->timer.st != (value & 1) || (value & 2)) { + omap_timer_sync(&s->timer); + s->timer.enable = value & 1; + s->timer.st = value & 1; + omap_timer_update(&s->timer); + } + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_os_timer_ops = { + .read = omap_os_timer_read, + .write = omap_os_timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_os_timer_reset(struct omap_32khz_timer_s *s) +{ + qemu_del_timer(s->timer.timer); + s->timer.enable = 0; + s->timer.it_ena = 0; + s->timer.reset_val = 0x00ffffff; + s->timer.val = 0; + s->timer.st = 0; + s->timer.ptv = 0; + s->timer.ar = 1; +} + +static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, + hwaddr base, + qemu_irq irq, omap_clk clk) +{ + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) + g_malloc0(sizeof(struct omap_32khz_timer_s)); + + s->timer.irq = irq; + s->timer.clk = clk; + s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer); + omap_os_timer_reset(s); + omap_timer_clk_setup(&s->timer); + + memory_region_init_io(&s->iomem, &omap_os_timer_ops, s, + "omap-os-timer", 0x800); + memory_region_add_subregion(memory, base, &s->iomem); + + return s; +} + +/* Ultra Low-Power Device Module */ +static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + uint16_t ret; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (addr) { + case 0x14: /* IT_STATUS */ + ret = s->ulpd_pm_regs[addr >> 2]; + s->ulpd_pm_regs[addr >> 2] = 0; + qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); + return ret; + + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ + OMAP_BAD_REG(addr); + /* fall through */ + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x10: /* GAUGING_CTRL */ + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x30: /* CLOCK_CTRL */ + case 0x34: /* SOFT_REQ */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x3c: /* DPLL_CTRL */ + case 0x40: /* STATUS_REQ */ + /* XXX: check clk::usecount state for every clock */ + case 0x48: /* LOCL_TIME */ + case 0x4c: /* APLL_CTRL */ + case 0x50: /* POWER_CTRL */ + return s->ulpd_pm_regs[addr >> 2]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + if (diff & (1 << 4)) /* USB_MCLK_EN */ + omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); + if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ + omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1); +} + +static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ + omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); + if (diff & (1 << 1)) /* SOFT_COM_REQ */ + omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); + if (diff & (1 << 2)) /* SOFT_SDW_REQ */ + omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); + if (diff & (1 << 3)) /* SOFT_USB_REQ */ + omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); +} + +static void omap_ulpd_pm_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int64_t now, ticks; + int div, mult; + static const int bypass_div[4] = { 1, 2, 4, 4 }; + uint16_t diff; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x14: /* IT_STATUS */ + case 0x40: /* STATUS_REQ */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* GAUGING_CTRL */ + /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ + if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) { + now = qemu_get_clock_ns(vm_clock); + + if (value & 1) + s->ulpd_gauge_start = now; + else { + now -= s->ulpd_gauge_start; + + /* 32-kHz ticks */ + ticks = muldiv64(now, 32768, get_ticks_per_sec()); + s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; + s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; + if (ticks >> 32) /* OVERFLOW_32K */ + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; + + /* High frequency ticks */ + ticks = muldiv64(now, 12000000, get_ticks_per_sec()); + s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; + s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; + if (ticks >> 32) /* OVERFLOW_HI_FREQ */ + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; + + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ + qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); + } + } + s->ulpd_pm_regs[addr >> 2] = value; + break; + + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ + OMAP_BAD_REG(addr); + /* fall through */ + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x48: /* LOCL_TIME */ + case 0x50: /* POWER_CTRL */ + s->ulpd_pm_regs[addr >> 2] = value; + break; + + case 0x30: /* CLOCK_CTRL */ + diff = s->ulpd_pm_regs[addr >> 2] ^ value; + s->ulpd_pm_regs[addr >> 2] = value & 0x3f; + omap_ulpd_clk_update(s, diff, value); + break; + + case 0x34: /* SOFT_REQ */ + diff = s->ulpd_pm_regs[addr >> 2] ^ value; + s->ulpd_pm_regs[addr >> 2] = value & 0x1f; + omap_ulpd_req_update(s, diff, value); + break; + + case 0x3c: /* DPLL_CTRL */ + /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is + * omitted altogether, probably a typo. */ + /* This register has identical semantics with DPLL(1:3) control + * registers, see omap_dpll_write() */ + diff = s->ulpd_pm_regs[addr >> 2] & value; + s->ulpd_pm_regs[addr >> 2] = value & 0x2fff; + if (diff & (0x3ff << 2)) { + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + } else { + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + mult = 1; + } + omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult); + } + + /* Enter the desired mode. */ + s->ulpd_pm_regs[addr >> 2] = + (s->ulpd_pm_regs[addr >> 2] & 0xfffe) | + ((s->ulpd_pm_regs[addr >> 2] >> 4) & 1); + + /* Act as if the lock is restored. */ + s->ulpd_pm_regs[addr >> 2] |= 2; + break; + + case 0x4c: /* APLL_CTRL */ + diff = s->ulpd_pm_regs[addr >> 2] & value; + s->ulpd_pm_regs[addr >> 2] = value & 0xf; + if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ + omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s, + (value & (1 << 0)) ? "apll" : "dpll4")); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_ulpd_pm_ops = { + .read = omap_ulpd_pm_read, + .write = omap_ulpd_pm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) +{ + mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x18 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x1c >> 2] = 0x01; + mpu->ulpd_pm_regs[0x20 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff; + mpu->ulpd_pm_regs[0x28 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x2c >> 2] = 0x01; + omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000); + mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000; + omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000); + mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211; + mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */ + mpu->ulpd_pm_regs[0x48 >> 2] = 0x960; + mpu->ulpd_pm_regs[0x4c >> 2] = 0x08; + mpu->ulpd_pm_regs[0x50 >> 2] = 0x08; + omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4); + omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4")); +} + +static void omap_ulpd_pm_init(MemoryRegion *system_memory, + hwaddr base, + struct omap_mpu_state_s *mpu) +{ + memory_region_init_io(&mpu->ulpd_pm_iomem, &omap_ulpd_pm_ops, mpu, + "omap-ulpd-pm", 0x800); + memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem); + omap_ulpd_pm_reset(mpu); +} + +/* OMAP Pin Configuration */ +static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x00: /* FUNC_MUX_CTRL_0 */ + case 0x04: /* FUNC_MUX_CTRL_1 */ + case 0x08: /* FUNC_MUX_CTRL_2 */ + return s->func_mux_ctrl[addr >> 2]; + + case 0x0c: /* COMP_MODE_CTRL_0 */ + return s->comp_mode_ctrl[0]; + + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ + return s->func_mux_ctrl[(addr >> 2) - 1]; + + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ + return s->pull_dwn_ctrl[(addr & 0xf) >> 2]; + + case 0x50: /* GATE_INH_CTRL_0 */ + return s->gate_inh_ctrl[0]; + + case 0x60: /* VOLTAGE_CTRL_0 */ + return s->voltage_ctrl[0]; + + case 0x70: /* TEST_DBG_CTRL_0 */ + return s->test_dbg_ctrl[0]; + + case 0x80: /* MOD_CONF_CTRL_0 */ + return s->mod_conf_ctrl[0]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (s->compat1509) { + if (diff & (1 << 9)) /* BLUETOOTH */ + omap_clk_onoff(omap_findclk(s, "bt_mclk_out"), + (~value >> 9) & 1); + if (diff & (1 << 7)) /* USB.CLKO */ + omap_clk_onoff(omap_findclk(s, "usb.clko"), + (value >> 7) & 1); + } +} + +static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (s->compat1509) { + if (diff & (1 << 31)) /* MCBSP3_CLK_HIZ_DI */ + omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), + (value >> 31) & 1); + if (diff & (1 << 1)) /* CLK32K */ + omap_clk_onoff(omap_findclk(s, "clk32k_out"), + (~value >> 1) & 1); + } +} + +static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (diff & (1 << 31)) /* CONF_MOD_UART3_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart3_ck"), + omap_findclk(s, ((value >> 31) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart2_ck"), + omap_findclk(s, ((value >> 30) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart1_ck"), + omap_findclk(s, ((value >> 29) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ + omap_clk_reparent(omap_findclk(s, "mmc_ck"), + omap_findclk(s, ((value >> 23) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ + omap_clk_reparent(omap_findclk(s, "com_mclk_out"), + omap_findclk(s, ((value >> 12) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ + omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); +} + +static void omap_pin_cfg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + uint32_t diff; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* FUNC_MUX_CTRL_0 */ + diff = s->func_mux_ctrl[addr >> 2] ^ value; + s->func_mux_ctrl[addr >> 2] = value; + omap_pin_funcmux0_update(s, diff, value); + return; + + case 0x04: /* FUNC_MUX_CTRL_1 */ + diff = s->func_mux_ctrl[addr >> 2] ^ value; + s->func_mux_ctrl[addr >> 2] = value; + omap_pin_funcmux1_update(s, diff, value); + return; + + case 0x08: /* FUNC_MUX_CTRL_2 */ + s->func_mux_ctrl[addr >> 2] = value; + return; + + case 0x0c: /* COMP_MODE_CTRL_0 */ + s->comp_mode_ctrl[0] = value; + s->compat1509 = (value != 0x0000eaef); + omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]); + omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]); + return; + + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ + s->func_mux_ctrl[(addr >> 2) - 1] = value; + return; + + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ + s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value; + return; + + case 0x50: /* GATE_INH_CTRL_0 */ + s->gate_inh_ctrl[0] = value; + return; + + case 0x60: /* VOLTAGE_CTRL_0 */ + s->voltage_ctrl[0] = value; + return; + + case 0x70: /* TEST_DBG_CTRL_0 */ + s->test_dbg_ctrl[0] = value; + return; + + case 0x80: /* MOD_CONF_CTRL_0 */ + diff = s->mod_conf_ctrl[0] ^ value; + s->mod_conf_ctrl[0] = value; + omap_pin_modconf1_update(s, diff, value); + return; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_pin_cfg_ops = { + .read = omap_pin_cfg_read, + .write = omap_pin_cfg_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) +{ + /* Start in Compatibility Mode. */ + mpu->compat1509 = 1; + omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0); + omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0); + omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0); + memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl)); + memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl)); + memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl)); + memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl)); + memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl)); + memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl)); + memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl)); +} + +static void omap_pin_cfg_init(MemoryRegion *system_memory, + hwaddr base, + struct omap_mpu_state_s *mpu) +{ + memory_region_init_io(&mpu->pin_cfg_iomem, &omap_pin_cfg_ops, mpu, + "omap-pin-cfg", 0x800); + memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem); + omap_pin_cfg_reset(mpu); +} + +/* Device Identification, Die Identification */ +static uint64_t omap_id_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0xfffe1800: /* DIE_ID_LSB */ + return 0xc9581f0e; + case 0xfffe1804: /* DIE_ID_MSB */ + return 0xa8858bfa; + + case 0xfffe2000: /* PRODUCT_ID_LSB */ + return 0x00aaaafc; + case 0xfffe2004: /* PRODUCT_ID_MSB */ + return 0xcafeb574; + + case 0xfffed400: /* JTAG_ID_LSB */ + switch (s->mpu_model) { + case omap310: + return 0x03310315; + case omap1510: + return 0x03310115; + default: + hw_error("%s: bad mpu model\n", __FUNCTION__); + } + break; + + case 0xfffed404: /* JTAG_ID_MSB */ + switch (s->mpu_model) { + case omap310: + return 0xfb57402f; + case omap1510: + return 0xfb47002f; + default: + hw_error("%s: bad mpu model\n", __FUNCTION__); + } + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_id_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + OMAP_BAD_REG(addr); +} + +static const MemoryRegionOps omap_id_ops = { + .read = omap_id_read, + .write = omap_id_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu) +{ + memory_region_init_io(&mpu->id_iomem, &omap_id_ops, mpu, + "omap-id", 0x100000000ULL); + memory_region_init_alias(&mpu->id_iomem_e18, "omap-id-e18", &mpu->id_iomem, + 0xfffe1800, 0x800); + memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18); + memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-ed4", &mpu->id_iomem, + 0xfffed400, 0x100); + memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4); + if (!cpu_is_omap15xx(mpu)) { + memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-e20", + &mpu->id_iomem, 0xfffe2000, 0x800); + memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20); + } +} + +/* MPUI Control (Dummy) */ +static uint64_t omap_mpui_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x00: /* CTRL */ + return s->mpui_ctrl; + case 0x04: /* DEBUG_ADDR */ + return 0x01ffffff; + case 0x08: /* DEBUG_DATA */ + return 0xffffffff; + case 0x0c: /* DEBUG_FLAG */ + return 0x00000800; + case 0x10: /* STATUS */ + return 0x00000000; + + /* Not in OMAP310 */ + case 0x14: /* DSP_STATUS */ + case 0x18: /* DSP_BOOT_CONFIG */ + return 0x00000000; + case 0x1c: /* DSP_MPUI_CONFIG */ + return 0x0000ffff; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpui_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* CTRL */ + s->mpui_ctrl = value & 0x007fffff; + break; + + case 0x04: /* DEBUG_ADDR */ + case 0x08: /* DEBUG_DATA */ + case 0x0c: /* DEBUG_FLAG */ + case 0x10: /* STATUS */ + /* Not in OMAP310 */ + case 0x14: /* DSP_STATUS */ + OMAP_RO_REG(addr); + break; + case 0x18: /* DSP_BOOT_CONFIG */ + case 0x1c: /* DSP_MPUI_CONFIG */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_mpui_ops = { + .read = omap_mpui_read, + .write = omap_mpui_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_mpui_reset(struct omap_mpu_state_s *s) +{ + s->mpui_ctrl = 0x0003ff1b; +} + +static void omap_mpui_init(MemoryRegion *memory, hwaddr base, + struct omap_mpu_state_s *mpu) +{ + memory_region_init_io(&mpu->mpui_iomem, &omap_mpui_ops, mpu, + "omap-mpui", 0x100); + memory_region_add_subregion(memory, base, &mpu->mpui_iomem); + + omap_mpui_reset(mpu); +} + +/* TIPB Bridges */ +struct omap_tipb_bridge_s { + qemu_irq abort; + MemoryRegion iomem; + + int width_intr; + uint16_t control; + uint16_t alloc; + uint16_t buffer; + uint16_t enh_control; +}; + +static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + + if (size < 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (addr) { + case 0x00: /* TIPB_CNTL */ + return s->control; + case 0x04: /* TIPB_BUS_ALLOC */ + return s->alloc; + case 0x08: /* MPU_TIPB_CNTL */ + return s->buffer; + case 0x0c: /* ENHANCED_TIPB_CNTL */ + return s->enh_control; + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ + return 0xffff; + case 0x1c: /* DEBUG_CNTR_SIG */ + return 0x00f8; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tipb_bridge_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + + if (size < 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* TIPB_CNTL */ + s->control = value & 0xffff; + break; + + case 0x04: /* TIPB_BUS_ALLOC */ + s->alloc = value & 0x003f; + break; + + case 0x08: /* MPU_TIPB_CNTL */ + s->buffer = value & 0x0003; + break; + + case 0x0c: /* ENHANCED_TIPB_CNTL */ + s->width_intr = !(value & 2); + s->enh_control = value & 0x000f; + break; + + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ + case 0x1c: /* DEBUG_CNTR_SIG */ + OMAP_RO_REG(addr); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_tipb_bridge_ops = { + .read = omap_tipb_bridge_read, + .write = omap_tipb_bridge_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) +{ + s->control = 0xffff; + s->alloc = 0x0009; + s->buffer = 0x0000; + s->enh_control = 0x000f; +} + +static struct omap_tipb_bridge_s *omap_tipb_bridge_init( + MemoryRegion *memory, hwaddr base, + qemu_irq abort_irq, omap_clk clk) +{ + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) + g_malloc0(sizeof(struct omap_tipb_bridge_s)); + + s->abort = abort_irq; + omap_tipb_bridge_reset(s); + + memory_region_init_io(&s->iomem, &omap_tipb_bridge_ops, s, + "omap-tipb-bridge", 0x100); + memory_region_add_subregion(memory, base, &s->iomem); + + return s; +} + +/* Dummy Traffic Controller's Memory Interface */ +static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + uint32_t ret; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x0c: /* EMIFS_CONFIG */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ + return s->tcmi_regs[addr >> 2]; + + case 0x20: /* EMIFF_SDRAM_CONFIG */ + ret = s->tcmi_regs[addr >> 2]; + s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ + /* XXX: We can try using the VGA_DIRTY flag for this */ + return ret; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tcmi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x20: /* EMIFF_SDRAM_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ + s->tcmi_regs[addr >> 2] = value; + break; + case 0x0c: /* EMIFS_CONFIG */ + s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_tcmi_ops = { + .read = omap_tcmi_read, + .write = omap_tcmi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) +{ + mpu->tcmi_regs[0x00 >> 2] = 0x00000000; + mpu->tcmi_regs[0x04 >> 2] = 0x00000000; + mpu->tcmi_regs[0x08 >> 2] = 0x00000000; + mpu->tcmi_regs[0x0c >> 2] = 0x00000010; + mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x20 >> 2] = 0x00618800; + mpu->tcmi_regs[0x24 >> 2] = 0x00000037; + mpu->tcmi_regs[0x28 >> 2] = 0x00000000; + mpu->tcmi_regs[0x2c >> 2] = 0x00000000; + mpu->tcmi_regs[0x30 >> 2] = 0x00000000; + mpu->tcmi_regs[0x3c >> 2] = 0x00000003; + mpu->tcmi_regs[0x40 >> 2] = 0x00000000; +} + +static void omap_tcmi_init(MemoryRegion *memory, hwaddr base, + struct omap_mpu_state_s *mpu) +{ + memory_region_init_io(&mpu->tcmi_iomem, &omap_tcmi_ops, mpu, + "omap-tcmi", 0x100); + memory_region_add_subregion(memory, base, &mpu->tcmi_iomem); + omap_tcmi_reset(mpu); +} + +/* Digital phase-locked loops control */ +struct dpll_ctl_s { + MemoryRegion iomem; + uint16_t mode; + omap_clk dpll; +}; + +static uint64_t omap_dpll_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + if (addr == 0x00) /* CTL_REG */ + return s->mode; + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_dpll_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + uint16_t diff; + static const int bypass_div[4] = { 1, 2, 4, 4 }; + int div, mult; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + if (addr == 0x00) { /* CTL_REG */ + /* See omap_ulpd_pm_write() too */ + diff = s->mode & value; + s->mode = value & 0x2fff; + if (diff & (0x3ff << 2)) { + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + } else { + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + mult = 1; + } + omap_clk_setrate(s->dpll, div, mult); + } + + /* Enter the desired mode. */ + s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1); + + /* Act as if the lock is restored. */ + s->mode |= 2; + } else { + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_dpll_ops = { + .read = omap_dpll_read, + .write = omap_dpll_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_dpll_reset(struct dpll_ctl_s *s) +{ + s->mode = 0x2002; + omap_clk_setrate(s->dpll, 1, 1); +} + +static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory, + hwaddr base, omap_clk clk) +{ + struct dpll_ctl_s *s = g_malloc0(sizeof(*s)); + memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100); + + s->dpll = clk; + omap_dpll_reset(s); + + memory_region_add_subregion(memory, base, &s->iomem); + return s; +} + +/* MPU Clock/Reset/Power Mode Control */ +static uint64_t omap_clkm_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (addr) { + case 0x00: /* ARM_CKCTL */ + return s->clkm.arm_ckctl; + + case 0x04: /* ARM_IDLECT1 */ + return s->clkm.arm_idlect1; + + case 0x08: /* ARM_IDLECT2 */ + return s->clkm.arm_idlect2; + + case 0x0c: /* ARM_EWUPCT */ + return s->clkm.arm_ewupct; + + case 0x10: /* ARM_RSTCT1 */ + return s->clkm.arm_rstct1; + + case 0x14: /* ARM_RSTCT2 */ + return s->clkm.arm_rstct2; + + case 0x18: /* ARM_SYSST */ + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; + + case 0x1c: /* ARM_CKOUT1 */ + return s->clkm.arm_ckout1; + + case 0x20: /* ARM_CKOUT2 */ + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ + if (value & (1 << 14)) + /* Reserved */; + else { + clk = omap_findclk(s, "arminth_ck"); + omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); + } + } + if (diff & (1 << 12)) { /* ARM_TIMXO */ + clk = omap_findclk(s, "armtim_ck"); + if (value & (1 << 12)) + omap_clk_reparent(clk, omap_findclk(s, "clkin")); + else + omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); + } + /* XXX: en_dspck */ + if (diff & (3 << 10)) { /* DSPMMUDIV */ + clk = omap_findclk(s, "dspmmu_ck"); + omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1); + } + if (diff & (3 << 8)) { /* TCDIV */ + clk = omap_findclk(s, "tc_ck"); + omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1); + } + if (diff & (3 << 6)) { /* DSPDIV */ + clk = omap_findclk(s, "dsp_ck"); + omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1); + } + if (diff & (3 << 4)) { /* ARMDIV */ + clk = omap_findclk(s, "arm_ck"); + omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1); + } + if (diff & (3 << 2)) { /* LCDDIV */ + clk = omap_findclk(s, "lcd_ck"); + omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1); + } + if (diff & (3 << 0)) { /* PERDIV */ + clk = omap_findclk(s, "armper_ck"); + omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1); + } +} + +static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (value & (1 << 11)) { /* SETARM_IDLE */ + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + } + if (!(value & (1 << 10))) /* WKUP_MODE */ + qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ + +#define SET_CANIDLE(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_canidle(clk, (value >> bit) & 1); \ + } + SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ + SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ + SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ + SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ + SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ + SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ + SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ + SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ +} + +static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + +#define SET_ONOFF(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_onoff(clk, (value >> bit) & 1); \ + } + SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ + SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ + SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ + SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ + SET_ONOFF("lb_ck", 4) /* EN_LBCK */ + SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ + SET_ONOFF("mpui_ck", 6) /* EN_APICK */ + SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ + SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ + SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ + SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ +} + +static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (diff & (3 << 4)) { /* TCLKOUT */ + clk = omap_findclk(s, "tclk_out"); + switch ((value >> 4) & 3) { + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen3")); + omap_clk_onoff(clk, 1); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); + omap_clk_onoff(clk, 1); + break; + default: + omap_clk_onoff(clk, 0); + } + } + if (diff & (3 << 2)) { /* DCLKOUT */ + clk = omap_findclk(s, "dclk_out"); + switch ((value >> 2) & 3) { + case 0: + omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck")); + break; + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen2")); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "dsp_ck")); + break; + case 3: + omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); + break; + } + } + if (diff & (3 << 0)) { /* ACLKOUT */ + clk = omap_findclk(s, "aclk_out"); + switch ((value >> 0) & 3) { + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); + omap_clk_onoff(clk, 1); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "arm_ck")); + omap_clk_onoff(clk, 1); + break; + case 3: + omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); + omap_clk_onoff(clk, 1); + break; + default: + omap_clk_onoff(clk, 0); + } + } +} + +static void omap_clkm_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + uint16_t diff; + omap_clk clk; + static const char *clkschemename[8] = { + "fully synchronous", "fully asynchronous", "synchronous scalable", + "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4", + }; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* ARM_CKCTL */ + diff = s->clkm.arm_ckctl ^ value; + s->clkm.arm_ckctl = value & 0x7fff; + omap_clkm_ckctl_update(s, diff, value); + return; + + case 0x04: /* ARM_IDLECT1 */ + diff = s->clkm.arm_idlect1 ^ value; + s->clkm.arm_idlect1 = value & 0x0fff; + omap_clkm_idlect1_update(s, diff, value); + return; + + case 0x08: /* ARM_IDLECT2 */ + diff = s->clkm.arm_idlect2 ^ value; + s->clkm.arm_idlect2 = value & 0x07ff; + omap_clkm_idlect2_update(s, diff, value); + return; + + case 0x0c: /* ARM_EWUPCT */ + s->clkm.arm_ewupct = value & 0x003f; + return; + + case 0x10: /* ARM_RSTCT1 */ + diff = s->clkm.arm_rstct1 ^ value; + s->clkm.arm_rstct1 = value & 0x0007; + if (value & 9) { + qemu_system_reset_request(); + s->clkm.cold_start = 0xa; + } + if (diff & ~value & 4) { /* DSP_RST */ + omap_mpui_reset(s); + omap_tipb_bridge_reset(s->private_tipb); + omap_tipb_bridge_reset(s->public_tipb); + } + if (diff & 2) { /* DSP_EN */ + clk = omap_findclk(s, "dsp_ck"); + omap_clk_canidle(clk, (~value >> 1) & 1); + } + return; + + case 0x14: /* ARM_RSTCT2 */ + s->clkm.arm_rstct2 = value & 0x0001; + return; + + case 0x18: /* ARM_SYSST */ + if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) { + s->clkm.clocking_scheme = (value >> 11) & 7; + printf("%s: clocking scheme set to %s\n", __FUNCTION__, + clkschemename[s->clkm.clocking_scheme]); + } + s->clkm.cold_start &= value & 0x3f; + return; + + case 0x1c: /* ARM_CKOUT1 */ + diff = s->clkm.arm_ckout1 ^ value; + s->clkm.arm_ckout1 = value & 0x003f; + omap_clkm_ckout1_update(s, diff, value); + return; + + case 0x20: /* ARM_CKOUT2 */ + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_clkm_ops = { + .read = omap_clkm_read, + .write = omap_clkm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (addr) { + case 0x04: /* DSP_IDLECT1 */ + return s->clkm.dsp_idlect1; + + case 0x08: /* DSP_IDLECT2 */ + return s->clkm.dsp_idlect2; + + case 0x14: /* DSP_RSTCT2 */ + return s->clkm.dsp_rstct2; + + case 0x18: /* DSP_SYSST */ + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | + (s->cpu->env.halted << 6); /* Quite useless... */ + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ +} + +static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ +} + +static void omap_clkdsp_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + uint16_t diff; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (addr) { + case 0x04: /* DSP_IDLECT1 */ + diff = s->clkm.dsp_idlect1 ^ value; + s->clkm.dsp_idlect1 = value & 0x01f7; + omap_clkdsp_idlect1_update(s, diff, value); + break; + + case 0x08: /* DSP_IDLECT2 */ + s->clkm.dsp_idlect2 = value & 0x0037; + diff = s->clkm.dsp_idlect1 ^ value; + omap_clkdsp_idlect2_update(s, diff, value); + break; + + case 0x14: /* DSP_RSTCT2 */ + s->clkm.dsp_rstct2 = value & 0x0001; + break; + + case 0x18: /* DSP_SYSST */ + s->clkm.cold_start &= value & 0x3f; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_clkdsp_ops = { + .read = omap_clkdsp_read, + .write = omap_clkdsp_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_clkm_reset(struct omap_mpu_state_s *s) +{ + if (s->wdt && s->wdt->reset) + s->clkm.cold_start = 0x6; + s->clkm.clocking_scheme = 0; + omap_clkm_ckctl_update(s, ~0, 0x3000); + s->clkm.arm_ckctl = 0x3000; + omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400); + s->clkm.arm_idlect1 = 0x0400; + omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100); + s->clkm.arm_idlect2 = 0x0100; + s->clkm.arm_ewupct = 0x003f; + s->clkm.arm_rstct1 = 0x0000; + s->clkm.arm_rstct2 = 0x0000; + s->clkm.arm_ckout1 = 0x0015; + s->clkm.dpll1_mode = 0x2002; + omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040); + s->clkm.dsp_idlect1 = 0x0040; + omap_clkdsp_idlect2_update(s, ~0, 0x0000); + s->clkm.dsp_idlect2 = 0x0000; + s->clkm.dsp_rstct2 = 0x0000; +} + +static void omap_clkm_init(MemoryRegion *memory, hwaddr mpu_base, + hwaddr dsp_base, struct omap_mpu_state_s *s) +{ + memory_region_init_io(&s->clkm_iomem, &omap_clkm_ops, s, + "omap-clkm", 0x100); + memory_region_init_io(&s->clkdsp_iomem, &omap_clkdsp_ops, s, + "omap-clkdsp", 0x1000); + + s->clkm.arm_idlect1 = 0x03ff; + s->clkm.arm_idlect2 = 0x0100; + s->clkm.dsp_idlect1 = 0x0002; + omap_clkm_reset(s); + s->clkm.cold_start = 0x3a; + + memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem); + memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem); +} + +/* MPU I/O */ +struct omap_mpuio_s { + qemu_irq irq; + qemu_irq kbd_irq; + qemu_irq *in; + qemu_irq handler[16]; + qemu_irq wakeup; + MemoryRegion iomem; + + uint16_t inputs; + uint16_t outputs; + uint16_t dir; + uint16_t edge; + uint16_t mask; + uint16_t ints; + + uint16_t debounce; + uint16_t latch; + uint8_t event; + + uint8_t buttons[5]; + uint8_t row_latch; + uint8_t cols; + int kbd_mask; + int clk; +}; + +static void omap_mpuio_set(void *opaque, int line, int level) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + uint16_t prev = s->inputs; + + if (level) + s->inputs |= 1 << line; + else + s->inputs &= ~(1 << line); + + if (((1 << line) & s->dir & ~s->mask) && s->clk) { + if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) { + s->ints |= 1 << line; + qemu_irq_raise(s->irq); + /* TODO: wakeup */ + } + if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ + (s->event >> 1) == line) /* PIN_SELECT */ + s->latch = s->inputs; + } +} + +static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) +{ + int i; + uint8_t *row, rows = 0, cols = ~s->cols; + + for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1) + if (*row & cols) + rows |= i; + + qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk); + s->row_latch = ~rows; +} + +static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t ret; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (offset) { + case 0x00: /* INPUT_LATCH */ + return s->inputs; + + case 0x04: /* OUTPUT_REG */ + return s->outputs; + + case 0x08: /* IO_CNTL */ + return s->dir; + + case 0x10: /* KBR_LATCH */ + return s->row_latch; + + case 0x14: /* KBC_REG */ + return s->cols; + + case 0x18: /* GPIO_EVENT_MODE_REG */ + return s->event; + + case 0x1c: /* GPIO_INT_EDGE_REG */ + return s->edge; + + case 0x20: /* KBD_INT */ + return (~s->row_latch & 0x1f) && !s->kbd_mask; + + case 0x24: /* GPIO_INT */ + ret = s->ints; + s->ints &= s->mask; + if (ret) + qemu_irq_lower(s->irq); + return ret; + + case 0x28: /* KBD_MASKIT */ + return s->kbd_mask; + + case 0x2c: /* GPIO_MASKIT */ + return s->mask; + + case 0x30: /* GPIO_DEBOUNCING_REG */ + return s->debounce; + + case 0x34: /* GPIO_LATCH_REG */ + return s->latch; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpuio_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t diff; + int ln; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (offset) { + case 0x04: /* OUTPUT_REG */ + diff = (s->outputs ^ value) & ~s->dir; + s->outputs = value; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x08: /* IO_CNTL */ + diff = s->outputs & (s->dir ^ value); + s->dir = value; + + value = s->outputs & ~s->dir; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x14: /* KBC_REG */ + s->cols = value; + omap_mpuio_kbd_update(s); + break; + + case 0x18: /* GPIO_EVENT_MODE_REG */ + s->event = value & 0x1f; + break; + + case 0x1c: /* GPIO_INT_EDGE_REG */ + s->edge = value; + break; + + case 0x28: /* KBD_MASKIT */ + s->kbd_mask = value & 1; + omap_mpuio_kbd_update(s); + break; + + case 0x2c: /* GPIO_MASKIT */ + s->mask = value; + break; + + case 0x30: /* GPIO_DEBOUNCING_REG */ + s->debounce = value & 0x1ff; + break; + + case 0x00: /* INPUT_LATCH */ + case 0x10: /* KBR_LATCH */ + case 0x20: /* KBD_INT */ + case 0x24: /* GPIO_INT */ + case 0x34: /* GPIO_LATCH_REG */ + OMAP_RO_REG(addr); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_mpuio_ops = { + .read = omap_mpuio_read, + .write = omap_mpuio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_mpuio_reset(struct omap_mpuio_s *s) +{ + s->inputs = 0; + s->outputs = 0; + s->dir = ~0; + s->event = 0; + s->edge = 0; + s->kbd_mask = 0; + s->mask = 0; + s->debounce = 0; + s->latch = 0; + s->ints = 0; + s->row_latch = 0x1f; + s->clk = 1; +} + +static void omap_mpuio_onoff(void *opaque, int line, int on) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + + s->clk = on; + if (on) + omap_mpuio_kbd_update(s); +} + +static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory, + hwaddr base, + qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, + omap_clk clk) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) + g_malloc0(sizeof(struct omap_mpuio_s)); + + s->irq = gpio_int; + s->kbd_irq = kbd_int; + s->wakeup = wakeup; + s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); + omap_mpuio_reset(s); + + memory_region_init_io(&s->iomem, &omap_mpuio_ops, s, + "omap-mpuio", 0x800); + memory_region_add_subregion(memory, base, &s->iomem); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); + + return s; +} + +qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s) +{ + return s->in; +} + +void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler) +{ + if (line >= 16 || line < 0) + hw_error("%s: No GPIO line %i\n", __FUNCTION__, line); + s->handler[line] = handler; +} + +void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) +{ + if (row >= 5 || row < 0) + hw_error("%s: No key %i-%i\n", __FUNCTION__, col, row); + + if (down) + s->buttons[row] |= 1 << col; + else + s->buttons[row] &= ~(1 << col); + + omap_mpuio_kbd_update(s); +} + +/* MicroWire Interface */ +struct omap_uwire_s { + MemoryRegion iomem; + qemu_irq txirq; + qemu_irq rxirq; + qemu_irq txdrq; + + uint16_t txbuf; + uint16_t rxbuf; + uint16_t control; + uint16_t setup[5]; + + uWireSlave *chip[4]; +}; + +static void omap_uwire_transfer_start(struct omap_uwire_s *s) +{ + int chipselect = (s->control >> 10) & 3; /* INDEX */ + uWireSlave *slave = s->chip[chipselect]; + + if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->send) + slave->send(slave->opaque, + s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); + s->control &= ~(1 << 14); /* CSRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } + + if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->receive) + s->rxbuf = slave->receive(slave->opaque); + s->control |= 1 << 15; /* RDRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } +} + +static uint64_t omap_uwire_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (offset) { + case 0x00: /* RDR */ + s->control &= ~(1 << 15); /* RDRB */ + return s->rxbuf; + + case 0x04: /* CSR */ + return s->control; + + case 0x08: /* SR1 */ + return s->setup[0]; + case 0x0c: /* SR2 */ + return s->setup[1]; + case 0x10: /* SR3 */ + return s->setup[2]; + case 0x14: /* SR4 */ + return s->setup[3]; + case 0x18: /* SR5 */ + return s->setup[4]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_uwire_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (offset) { + case 0x00: /* TDR */ + s->txbuf = value; /* TD */ + if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ + ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ + (s->control & (1 << 12)))) { /* CS_CMD */ + s->control |= 1 << 14; /* CSRB */ + omap_uwire_transfer_start(s); + } + break; + + case 0x04: /* CSR */ + s->control = value & 0x1fff; + if (value & (1 << 13)) /* START */ + omap_uwire_transfer_start(s); + break; + + case 0x08: /* SR1 */ + s->setup[0] = value & 0x003f; + break; + + case 0x0c: /* SR2 */ + s->setup[1] = value & 0x0fc0; + break; + + case 0x10: /* SR3 */ + s->setup[2] = value & 0x0003; + break; + + case 0x14: /* SR4 */ + s->setup[3] = value & 0x0001; + break; + + case 0x18: /* SR5 */ + s->setup[4] = value & 0x000f; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_uwire_ops = { + .read = omap_uwire_read, + .write = omap_uwire_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_uwire_reset(struct omap_uwire_s *s) +{ + s->control = 0; + s->setup[0] = 0; + s->setup[1] = 0; + s->setup[2] = 0; + s->setup[3] = 0; + s->setup[4] = 0; +} + +static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory, + hwaddr base, + qemu_irq txirq, qemu_irq rxirq, + qemu_irq dma, + omap_clk clk) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) + g_malloc0(sizeof(struct omap_uwire_s)); + + s->txirq = txirq; + s->rxirq = rxirq; + s->txdrq = dma; + omap_uwire_reset(s); + + memory_region_init_io(&s->iomem, &omap_uwire_ops, s, "omap-uwire", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); + + return s; +} + +void omap_uwire_attach(struct omap_uwire_s *s, + uWireSlave *slave, int chipselect) +{ + if (chipselect < 0 || chipselect > 3) { + fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect); + exit(-1); + } + + s->chip[chipselect] = slave; +} + +/* Pseudonoise Pulse-Width Light Modulator */ +struct omap_pwl_s { + MemoryRegion iomem; + uint8_t output; + uint8_t level; + uint8_t enable; + int clk; +}; + +static void omap_pwl_update(struct omap_pwl_s *s) +{ + int output = (s->clk && s->enable) ? s->level : 0; + + if (output != s->output) { + s->output = output; + printf("%s: Backlight now at %i/256\n", __FUNCTION__, output); + } +} + +static uint64_t omap_pwl_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + + switch (offset) { + case 0x00: /* PWL_LEVEL */ + return s->level; + case 0x04: /* PWL_CTRL */ + return s->enable; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_pwl_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + + switch (offset) { + case 0x00: /* PWL_LEVEL */ + s->level = value; + omap_pwl_update(s); + break; + case 0x04: /* PWL_CTRL */ + s->enable = value & 1; + omap_pwl_update(s); + break; + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_pwl_ops = { + .read = omap_pwl_read, + .write = omap_pwl_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_pwl_reset(struct omap_pwl_s *s) +{ + s->output = 0; + s->level = 0; + s->enable = 0; + s->clk = 1; + omap_pwl_update(s); +} + +static void omap_pwl_clk_update(void *opaque, int line, int on) +{ + struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; + + s->clk = on; + omap_pwl_update(s); +} + +static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory, + hwaddr base, + omap_clk clk) +{ + struct omap_pwl_s *s = g_malloc0(sizeof(*s)); + + omap_pwl_reset(s); + + memory_region_init_io(&s->iomem, &omap_pwl_ops, s, + "omap-pwl", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); + return s; +} + +/* Pulse-Width Tone module */ +struct omap_pwt_s { + MemoryRegion iomem; + uint8_t frc; + uint8_t vrc; + uint8_t gcr; + omap_clk clk; +}; + +static uint64_t omap_pwt_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + + switch (offset) { + case 0x00: /* FRC */ + return s->frc; + case 0x04: /* VCR */ + return s->vrc; + case 0x08: /* GCR */ + return s->gcr; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_pwt_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + + switch (offset) { + case 0x00: /* FRC */ + s->frc = value & 0x3f; + break; + case 0x04: /* VRC */ + if ((value ^ s->vrc) & 1) { + if (value & 1) + printf("%s: %iHz buzz on\n", __FUNCTION__, (int) + /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */ + ((omap_clk_getrate(s->clk) >> 3) / + /* Pre-multiplexer divider */ + ((s->gcr & 2) ? 1 : 154) / + /* Octave multiplexer */ + (2 << (value & 3)) * + /* 101/107 divider */ + ((value & (1 << 2)) ? 101 : 107) * + /* 49/55 divider */ + ((value & (1 << 3)) ? 49 : 55) * + /* 50/63 divider */ + ((value & (1 << 4)) ? 50 : 63) * + /* 80/127 divider */ + ((value & (1 << 5)) ? 80 : 127) / + (107 * 55 * 63 * 127))); + else + printf("%s: silence!\n", __FUNCTION__); + } + s->vrc = value & 0x7f; + break; + case 0x08: /* GCR */ + s->gcr = value & 3; + break; + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_pwt_ops = { + .read =omap_pwt_read, + .write = omap_pwt_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_pwt_reset(struct omap_pwt_s *s) +{ + s->frc = 0; + s->vrc = 0; + s->gcr = 0; +} + +static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory, + hwaddr base, + omap_clk clk) +{ + struct omap_pwt_s *s = g_malloc0(sizeof(*s)); + s->clk = clk; + omap_pwt_reset(s); + + memory_region_init_io(&s->iomem, &omap_pwt_ops, s, + "omap-pwt", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); + return s; +} + +/* Real-time Clock module */ +struct omap_rtc_s { + MemoryRegion iomem; + qemu_irq irq; + qemu_irq alarm; + QEMUTimer *clk; + + uint8_t interrupts; + uint8_t status; + int16_t comp_reg; + int running; + int pm_am; + int auto_comp; + int round; + struct tm alarm_tm; + time_t alarm_ti; + + struct tm current_tm; + time_t ti; + uint64_t tick; +}; + +static void omap_rtc_interrupts_update(struct omap_rtc_s *s) +{ + /* s->alarm is level-triggered */ + qemu_set_irq(s->alarm, (s->status >> 6) & 1); +} + +static void omap_rtc_alarm_update(struct omap_rtc_s *s) +{ + s->alarm_ti = mktimegm(&s->alarm_tm); + if (s->alarm_ti == -1) + printf("%s: conversion failed\n", __FUNCTION__); +} + +static uint64_t omap_rtc_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint8_t i; + + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + + switch (offset) { + case 0x00: /* SECONDS_REG */ + return to_bcd(s->current_tm.tm_sec); + + case 0x04: /* MINUTES_REG */ + return to_bcd(s->current_tm.tm_min); + + case 0x08: /* HOURS_REG */ + if (s->pm_am) + return ((s->current_tm.tm_hour > 11) << 7) | + to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); + else + return to_bcd(s->current_tm.tm_hour); + + case 0x0c: /* DAYS_REG */ + return to_bcd(s->current_tm.tm_mday); + + case 0x10: /* MONTHS_REG */ + return to_bcd(s->current_tm.tm_mon + 1); + + case 0x14: /* YEARS_REG */ + return to_bcd(s->current_tm.tm_year % 100); + + case 0x18: /* WEEK_REG */ + return s->current_tm.tm_wday; + + case 0x20: /* ALARM_SECONDS_REG */ + return to_bcd(s->alarm_tm.tm_sec); + + case 0x24: /* ALARM_MINUTES_REG */ + return to_bcd(s->alarm_tm.tm_min); + + case 0x28: /* ALARM_HOURS_REG */ + if (s->pm_am) + return ((s->alarm_tm.tm_hour > 11) << 7) | + to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); + else + return to_bcd(s->alarm_tm.tm_hour); + + case 0x2c: /* ALARM_DAYS_REG */ + return to_bcd(s->alarm_tm.tm_mday); + + case 0x30: /* ALARM_MONTHS_REG */ + return to_bcd(s->alarm_tm.tm_mon + 1); + + case 0x34: /* ALARM_YEARS_REG */ + return to_bcd(s->alarm_tm.tm_year % 100); + + case 0x40: /* RTC_CTRL_REG */ + return (s->pm_am << 3) | (s->auto_comp << 2) | + (s->round << 1) | s->running; + + case 0x44: /* RTC_STATUS_REG */ + i = s->status; + s->status &= ~0x3d; + return i; + + case 0x48: /* RTC_INTERRUPTS_REG */ + return s->interrupts; + + case 0x4c: /* RTC_COMP_LSB_REG */ + return ((uint16_t) s->comp_reg) & 0xff; + + case 0x50: /* RTC_COMP_MSB_REG */ + return ((uint16_t) s->comp_reg) >> 8; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_rtc_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + struct tm new_tm; + time_t ti[2]; + + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + + switch (offset) { + case 0x00: /* SECONDS_REG */ +#ifdef ALMDEBUG + printf("RTC SEC_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_sec; + s->ti += from_bcd(value); + return; + + case 0x04: /* MINUTES_REG */ +#ifdef ALMDEBUG + printf("RTC MIN_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_min * 60; + s->ti += from_bcd(value) * 60; + return; + + case 0x08: /* HOURS_REG */ +#ifdef ALMDEBUG + printf("RTC HRS_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_hour * 3600; + if (s->pm_am) { + s->ti += (from_bcd(value & 0x3f) & 12) * 3600; + s->ti += ((value >> 7) & 1) * 43200; + } else + s->ti += from_bcd(value & 0x3f) * 3600; + return; + + case 0x0c: /* DAYS_REG */ +#ifdef ALMDEBUG + printf("RTC DAY_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_mday * 86400; + s->ti += from_bcd(value) * 86400; + return; + + case 0x10: /* MONTHS_REG */ +#ifdef ALMDEBUG + printf("RTC MTH_REG <-- %02x\n", value); +#endif + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); + new_tm.tm_mon = from_bcd(value); + ti[0] = mktimegm(&s->current_tm); + ti[1] = mktimegm(&new_tm); + + if (ti[0] != -1 && ti[1] != -1) { + s->ti -= ti[0]; + s->ti += ti[1]; + } else { + /* A less accurate version */ + s->ti -= s->current_tm.tm_mon * 2592000; + s->ti += from_bcd(value) * 2592000; + } + return; + + case 0x14: /* YEARS_REG */ +#ifdef ALMDEBUG + printf("RTC YRS_REG <-- %02x\n", value); +#endif + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); + new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100); + ti[0] = mktimegm(&s->current_tm); + ti[1] = mktimegm(&new_tm); + + if (ti[0] != -1 && ti[1] != -1) { + s->ti -= ti[0]; + s->ti += ti[1]; + } else { + /* A less accurate version */ + s->ti -= (s->current_tm.tm_year % 100) * 31536000; + s->ti += from_bcd(value) * 31536000; + } + return; + + case 0x18: /* WEEK_REG */ + return; /* Ignored */ + + case 0x20: /* ALARM_SECONDS_REG */ +#ifdef ALMDEBUG + printf("ALM SEC_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_sec = from_bcd(value); + omap_rtc_alarm_update(s); + return; + + case 0x24: /* ALARM_MINUTES_REG */ +#ifdef ALMDEBUG + printf("ALM MIN_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_min = from_bcd(value); + omap_rtc_alarm_update(s); + return; + + case 0x28: /* ALARM_HOURS_REG */ +#ifdef ALMDEBUG + printf("ALM HRS_REG <-- %02x\n", value); +#endif + if (s->pm_am) + s->alarm_tm.tm_hour = + ((from_bcd(value & 0x3f)) % 12) + + ((value >> 7) & 1) * 12; + else + s->alarm_tm.tm_hour = from_bcd(value); + omap_rtc_alarm_update(s); + return; + + case 0x2c: /* ALARM_DAYS_REG */ +#ifdef ALMDEBUG + printf("ALM DAY_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_mday = from_bcd(value); + omap_rtc_alarm_update(s); + return; + + case 0x30: /* ALARM_MONTHS_REG */ +#ifdef ALMDEBUG + printf("ALM MON_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_mon = from_bcd(value); + omap_rtc_alarm_update(s); + return; + + case 0x34: /* ALARM_YEARS_REG */ +#ifdef ALMDEBUG + printf("ALM YRS_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_year = from_bcd(value); + omap_rtc_alarm_update(s); + return; + + case 0x40: /* RTC_CTRL_REG */ +#ifdef ALMDEBUG + printf("RTC CONTROL <-- %02x\n", value); +#endif + s->pm_am = (value >> 3) & 1; + s->auto_comp = (value >> 2) & 1; + s->round = (value >> 1) & 1; + s->running = value & 1; + s->status &= 0xfd; + s->status |= s->running << 1; + return; + + case 0x44: /* RTC_STATUS_REG */ +#ifdef ALMDEBUG + printf("RTC STATUSL <-- %02x\n", value); +#endif + s->status &= ~((value & 0xc0) ^ 0x80); + omap_rtc_interrupts_update(s); + return; + + case 0x48: /* RTC_INTERRUPTS_REG */ +#ifdef ALMDEBUG + printf("RTC INTRS <-- %02x\n", value); +#endif + s->interrupts = value; + return; + + case 0x4c: /* RTC_COMP_LSB_REG */ +#ifdef ALMDEBUG + printf("RTC COMPLSB <-- %02x\n", value); +#endif + s->comp_reg &= 0xff00; + s->comp_reg |= 0x00ff & value; + return; + + case 0x50: /* RTC_COMP_MSB_REG */ +#ifdef ALMDEBUG + printf("RTC COMPMSB <-- %02x\n", value); +#endif + s->comp_reg &= 0x00ff; + s->comp_reg |= 0xff00 & (value << 8); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_rtc_ops = { + .read = omap_rtc_read, + .write = omap_rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_rtc_tick(void *opaque) +{ + struct omap_rtc_s *s = opaque; + + if (s->round) { + /* Round to nearest full minute. */ + if (s->current_tm.tm_sec < 30) + s->ti -= s->current_tm.tm_sec; + else + s->ti += 60 - s->current_tm.tm_sec; + + s->round = 0; + } + + localtime_r(&s->ti, &s->current_tm); + + if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { + s->status |= 0x40; + omap_rtc_interrupts_update(s); + } + + if (s->interrupts & 0x04) + switch (s->interrupts & 3) { + case 0: + s->status |= 0x04; + qemu_irq_pulse(s->irq); + break; + case 1: + if (s->current_tm.tm_sec) + break; + s->status |= 0x08; + qemu_irq_pulse(s->irq); + break; + case 2: + if (s->current_tm.tm_sec || s->current_tm.tm_min) + break; + s->status |= 0x10; + qemu_irq_pulse(s->irq); + break; + case 3: + if (s->current_tm.tm_sec || + s->current_tm.tm_min || s->current_tm.tm_hour) + break; + s->status |= 0x20; + qemu_irq_pulse(s->irq); + break; + } + + /* Move on */ + if (s->running) + s->ti ++; + s->tick += 1000; + + /* + * Every full hour add a rough approximation of the compensation + * register to the 32kHz Timer (which drives the RTC) value. + */ + if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) + s->tick += s->comp_reg * 1000 / 32768; + + qemu_mod_timer(s->clk, s->tick); +} + +static void omap_rtc_reset(struct omap_rtc_s *s) +{ + struct tm tm; + + s->interrupts = 0; + s->comp_reg = 0; + s->running = 0; + s->pm_am = 0; + s->auto_comp = 0; + s->round = 0; + s->tick = qemu_get_clock_ms(rtc_clock); + memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); + s->alarm_tm.tm_mday = 0x01; + s->status = 1 << 7; + qemu_get_timedate(&tm, 0); + s->ti = mktimegm(&tm); + + omap_rtc_alarm_update(s); + omap_rtc_tick(s); +} + +static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, + hwaddr base, + qemu_irq timerirq, qemu_irq alarmirq, + omap_clk clk) +{ + struct omap_rtc_s *s = (struct omap_rtc_s *) + g_malloc0(sizeof(struct omap_rtc_s)); + + s->irq = timerirq; + s->alarm = alarmirq; + s->clk = qemu_new_timer_ms(rtc_clock, omap_rtc_tick, s); + + omap_rtc_reset(s); + + memory_region_init_io(&s->iomem, &omap_rtc_ops, s, + "omap-rtc", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); + + return s; +} + +/* Multi-channel Buffered Serial Port interfaces */ +struct omap_mcbsp_s { + MemoryRegion iomem; + qemu_irq txirq; + qemu_irq rxirq; + qemu_irq txdrq; + qemu_irq rxdrq; + + uint16_t spcr[2]; + uint16_t rcr[2]; + uint16_t xcr[2]; + uint16_t srgr[2]; + uint16_t mcr[2]; + uint16_t pcr; + uint16_t rcer[8]; + uint16_t xcer[8]; + int tx_rate; + int rx_rate; + int tx_req; + int rx_req; + + I2SCodec *codec; + QEMUTimer *source_timer; + QEMUTimer *sink_timer; +}; + +static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) +{ + int irq; + + switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ + case 0: + irq = (s->spcr[0] >> 1) & 1; /* RRDY */ + break; + case 3: + irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ + break; + default: + irq = 0; + break; + } + + if (irq) + qemu_irq_pulse(s->rxirq); + + switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ + case 0: + irq = (s->spcr[1] >> 1) & 1; /* XRDY */ + break; + case 3: + irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ + break; + default: + irq = 0; + break; + } + + if (irq) + qemu_irq_pulse(s->txirq); +} + +static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) +{ + if ((s->spcr[0] >> 1) & 1) /* RRDY */ + s->spcr[0] |= 1 << 2; /* RFULL */ + s->spcr[0] |= 1 << 1; /* RRDY */ + qemu_irq_raise(s->rxdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_source_tick(void *opaque) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; + + if (!s->rx_rate) + return; + if (s->rx_req) + printf("%s: Rx FIFO overrun\n", __FUNCTION__); + + s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; + + omap_mcbsp_rx_newdata(s); + qemu_mod_timer(s->source_timer, qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec()); +} + +static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) +{ + if (!s->codec || !s->codec->rts) + omap_mcbsp_source_tick(s); + else if (s->codec->in.len) { + s->rx_req = s->codec->in.len; + omap_mcbsp_rx_newdata(s); + } +} + +static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) +{ + qemu_del_timer(s->source_timer); +} + +static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) +{ + s->spcr[0] &= ~(1 << 1); /* RRDY */ + qemu_irq_lower(s->rxdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) +{ + s->spcr[1] |= 1 << 1; /* XRDY */ + qemu_irq_raise(s->txdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_sink_tick(void *opaque) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; + + if (!s->tx_rate) + return; + if (s->tx_req) + printf("%s: Tx FIFO underrun\n", __FUNCTION__); + + s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; + + omap_mcbsp_tx_newdata(s); + qemu_mod_timer(s->sink_timer, qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec()); +} + +static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) +{ + if (!s->codec || !s->codec->cts) + omap_mcbsp_sink_tick(s); + else if (s->codec->out.size) { + s->tx_req = s->codec->out.size; + omap_mcbsp_tx_newdata(s); + } +} + +static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) +{ + s->spcr[1] &= ~(1 << 1); /* XRDY */ + qemu_irq_lower(s->txdrq); + omap_mcbsp_intr_update(s); + if (s->codec && s->codec->cts) + s->codec->tx_swallow(s->codec->opaque); +} + +static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) +{ + s->tx_req = 0; + omap_mcbsp_tx_done(s); + qemu_del_timer(s->sink_timer); +} + +static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) +{ + int prev_rx_rate, prev_tx_rate; + int rx_rate = 0, tx_rate = 0; + int cpu_rate = 1500000; /* XXX */ + + /* TODO: check CLKSTP bit */ + if (s->spcr[1] & (1 << 6)) { /* GRST */ + if (s->spcr[0] & (1 << 0)) { /* RRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 8))) { /* CLKRM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + rx_rate = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + } else + if (s->codec) + rx_rate = s->codec->rx_rate; + } + + if (s->spcr[1] & (1 << 0)) { /* XRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 9))) { /* CLKXM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + tx_rate = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + } else + if (s->codec) + tx_rate = s->codec->tx_rate; + } + } + prev_tx_rate = s->tx_rate; + prev_rx_rate = s->rx_rate; + s->tx_rate = tx_rate; + s->rx_rate = rx_rate; + + if (s->codec) + s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); + + if (!prev_tx_rate && tx_rate) + omap_mcbsp_tx_start(s); + else if (s->tx_rate && !tx_rate) + omap_mcbsp_tx_stop(s); + + if (!prev_rx_rate && rx_rate) + omap_mcbsp_rx_start(s); + else if (prev_tx_rate && !tx_rate) + omap_mcbsp_rx_stop(s); +} + +static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t ret; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (offset) { + case 0x00: /* DRR2 */ + if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ + return 0x0000; + /* Fall through. */ + case 0x02: /* DRR1 */ + if (s->rx_req < 2) { + printf("%s: Rx FIFO underrun\n", __FUNCTION__); + omap_mcbsp_rx_done(s); + } else { + s->tx_req -= 2; + if (s->codec && s->codec->in.len >= 2) { + ret = s->codec->in.fifo[s->codec->in.start ++] << 8; + ret |= s->codec->in.fifo[s->codec->in.start ++]; + s->codec->in.len -= 2; + } else + ret = 0x0000; + if (!s->tx_req) + omap_mcbsp_rx_done(s); + return ret; + } + return 0x0000; + + case 0x04: /* DXR2 */ + case 0x06: /* DXR1 */ + return 0x0000; + + case 0x08: /* SPCR2 */ + return s->spcr[1]; + case 0x0a: /* SPCR1 */ + return s->spcr[0]; + case 0x0c: /* RCR2 */ + return s->rcr[1]; + case 0x0e: /* RCR1 */ + return s->rcr[0]; + case 0x10: /* XCR2 */ + return s->xcr[1]; + case 0x12: /* XCR1 */ + return s->xcr[0]; + case 0x14: /* SRGR2 */ + return s->srgr[1]; + case 0x16: /* SRGR1 */ + return s->srgr[0]; + case 0x18: /* MCR2 */ + return s->mcr[1]; + case 0x1a: /* MCR1 */ + return s->mcr[0]; + case 0x1c: /* RCERA */ + return s->rcer[0]; + case 0x1e: /* RCERB */ + return s->rcer[1]; + case 0x20: /* XCERA */ + return s->xcer[0]; + case 0x22: /* XCERB */ + return s->xcer[1]; + case 0x24: /* PCR0 */ + return s->pcr; + case 0x26: /* RCERC */ + return s->rcer[2]; + case 0x28: /* RCERD */ + return s->rcer[3]; + case 0x2a: /* XCERC */ + return s->xcer[2]; + case 0x2c: /* XCERD */ + return s->xcer[3]; + case 0x2e: /* RCERE */ + return s->rcer[4]; + case 0x30: /* RCERF */ + return s->rcer[5]; + case 0x32: /* XCERE */ + return s->xcer[4]; + case 0x34: /* XCERF */ + return s->xcer[5]; + case 0x36: /* RCERG */ + return s->rcer[6]; + case 0x38: /* RCERH */ + return s->rcer[7]; + case 0x3a: /* XCERG */ + return s->xcer[6]; + case 0x3c: /* XCERH */ + return s->xcer[7]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mcbsp_writeh(void *opaque, hwaddr addr, + uint32_t value) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* DRR2 */ + case 0x02: /* DRR1 */ + OMAP_RO_REG(addr); + return; + + case 0x04: /* DXR2 */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + return; + /* Fall through. */ + case 0x06: /* DXR1 */ + if (s->tx_req > 1) { + s->tx_req -= 2; + if (s->codec && s->codec->cts) { + s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; + } + if (s->tx_req < 2) + omap_mcbsp_tx_done(s); + } else + printf("%s: Tx FIFO overrun\n", __FUNCTION__); + return; + + case 0x08: /* SPCR2 */ + s->spcr[1] &= 0x0002; + s->spcr[1] |= 0x03f9 & value; + s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ + if (~value & 1) /* XRST */ + s->spcr[1] &= ~6; + omap_mcbsp_req_update(s); + return; + case 0x0a: /* SPCR1 */ + s->spcr[0] &= 0x0006; + s->spcr[0] |= 0xf8f9 & value; + if (value & (1 << 15)) /* DLB */ + printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); + if (~value & 1) { /* RRST */ + s->spcr[0] &= ~6; + s->rx_req = 0; + omap_mcbsp_rx_done(s); + } + omap_mcbsp_req_update(s); + return; + + case 0x0c: /* RCR2 */ + s->rcr[1] = value & 0xffff; + return; + case 0x0e: /* RCR1 */ + s->rcr[0] = value & 0x7fe0; + return; + case 0x10: /* XCR2 */ + s->xcr[1] = value & 0xffff; + return; + case 0x12: /* XCR1 */ + s->xcr[0] = value & 0x7fe0; + return; + case 0x14: /* SRGR2 */ + s->srgr[1] = value & 0xffff; + omap_mcbsp_req_update(s); + return; + case 0x16: /* SRGR1 */ + s->srgr[0] = value & 0xffff; + omap_mcbsp_req_update(s); + return; + case 0x18: /* MCR2 */ + s->mcr[1] = value & 0x03e3; + if (value & 3) /* XMCM */ + printf("%s: Tx channel selection mode enable attempt\n", + __FUNCTION__); + return; + case 0x1a: /* MCR1 */ + s->mcr[0] = value & 0x03e1; + if (value & 1) /* RMCM */ + printf("%s: Rx channel selection mode enable attempt\n", + __FUNCTION__); + return; + case 0x1c: /* RCERA */ + s->rcer[0] = value & 0xffff; + return; + case 0x1e: /* RCERB */ + s->rcer[1] = value & 0xffff; + return; + case 0x20: /* XCERA */ + s->xcer[0] = value & 0xffff; + return; + case 0x22: /* XCERB */ + s->xcer[1] = value & 0xffff; + return; + case 0x24: /* PCR0 */ + s->pcr = value & 0x7faf; + return; + case 0x26: /* RCERC */ + s->rcer[2] = value & 0xffff; + return; + case 0x28: /* RCERD */ + s->rcer[3] = value & 0xffff; + return; + case 0x2a: /* XCERC */ + s->xcer[2] = value & 0xffff; + return; + case 0x2c: /* XCERD */ + s->xcer[3] = value & 0xffff; + return; + case 0x2e: /* RCERE */ + s->rcer[4] = value & 0xffff; + return; + case 0x30: /* RCERF */ + s->rcer[5] = value & 0xffff; + return; + case 0x32: /* XCERE */ + s->xcer[4] = value & 0xffff; + return; + case 0x34: /* XCERF */ + s->xcer[5] = value & 0xffff; + return; + case 0x36: /* RCERG */ + s->rcer[6] = value & 0xffff; + return; + case 0x38: /* RCERH */ + s->rcer[7] = value & 0xffff; + return; + case 0x3a: /* XCERG */ + s->xcer[6] = value & 0xffff; + return; + case 0x3c: /* XCERH */ + s->xcer[7] = value & 0xffff; + return; + } + + OMAP_BAD_REG(addr); +} + +static void omap_mcbsp_writew(void *opaque, hwaddr addr, + uint32_t value) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (offset == 0x04) { /* DXR */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + return; + if (s->tx_req > 3) { + s->tx_req -= 4; + if (s->codec && s->codec->cts) { + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 24) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 16) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 8) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 0) & 0xff; + } + if (s->tx_req < 4) + omap_mcbsp_tx_done(s); + } else + printf("%s: Tx FIFO overrun\n", __FUNCTION__); + return; + } + + omap_badwidth_write16(opaque, addr, value); +} + +static void omap_mcbsp_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + switch (size) { + case 2: return omap_mcbsp_writeh(opaque, addr, value); + case 4: return omap_mcbsp_writew(opaque, addr, value); + default: return omap_badwidth_write16(opaque, addr, value); + } +} + +static const MemoryRegionOps omap_mcbsp_ops = { + .read = omap_mcbsp_read, + .write = omap_mcbsp_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_mcbsp_reset(struct omap_mcbsp_s *s) +{ + memset(&s->spcr, 0, sizeof(s->spcr)); + memset(&s->rcr, 0, sizeof(s->rcr)); + memset(&s->xcr, 0, sizeof(s->xcr)); + s->srgr[0] = 0x0001; + s->srgr[1] = 0x2000; + memset(&s->mcr, 0, sizeof(s->mcr)); + memset(&s->pcr, 0, sizeof(s->pcr)); + memset(&s->rcer, 0, sizeof(s->rcer)); + memset(&s->xcer, 0, sizeof(s->xcer)); + s->tx_req = 0; + s->rx_req = 0; + s->tx_rate = 0; + s->rx_rate = 0; + qemu_del_timer(s->source_timer); + qemu_del_timer(s->sink_timer); +} + +static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, + hwaddr base, + qemu_irq txirq, qemu_irq rxirq, + qemu_irq *dma, omap_clk clk) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) + g_malloc0(sizeof(struct omap_mcbsp_s)); + + s->txirq = txirq; + s->rxirq = rxirq; + s->txdrq = dma[0]; + s->rxdrq = dma[1]; + s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s); + s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s); + omap_mcbsp_reset(s); + + memory_region_init_io(&s->iomem, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); + + return s; +} + +static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + + if (s->rx_rate) { + s->rx_req = s->codec->in.len; + omap_mcbsp_rx_newdata(s); + } +} + +static void omap_mcbsp_i2s_start(void *opaque, int line, int level) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + + if (s->tx_rate) { + s->tx_req = s->codec->out.size; + omap_mcbsp_tx_newdata(s); + } +} + +void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave) +{ + s->codec = slave; + slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0]; + slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; +} + +/* LED Pulse Generators */ +struct omap_lpg_s { + MemoryRegion iomem; + QEMUTimer *tm; + + uint8_t control; + uint8_t power; + int64_t on; + int64_t period; + int clk; + int cycle; +}; + +static void omap_lpg_tick(void *opaque) +{ + struct omap_lpg_s *s = opaque; + + if (s->cycle) + qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->period - s->on); + else + qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->on); + + s->cycle = !s->cycle; + printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); +} + +static void omap_lpg_update(struct omap_lpg_s *s) +{ + int64_t on, period = 1, ticks = 1000; + static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 }; + + if (~s->control & (1 << 6)) /* LPGRES */ + on = 0; + else if (s->control & (1 << 7)) /* PERM_ON */ + on = period; + else { + period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ + 256 / 32); + on = (s->clk && s->power) ? muldiv64(ticks, + per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ + } + + qemu_del_timer(s->tm); + if (on == period && s->on < s->period) + printf("%s: LED is on\n", __FUNCTION__); + else if (on == 0 && s->on) + printf("%s: LED is off\n", __FUNCTION__); + else if (on && (on != s->on || period != s->period)) { + s->cycle = 0; + s->on = on; + s->period = period; + omap_lpg_tick(s); + return; + } + + s->on = on; + s->period = period; +} + +static void omap_lpg_reset(struct omap_lpg_s *s) +{ + s->control = 0x00; + s->power = 0x00; + s->clk = 1; + omap_lpg_update(s); +} + +static uint64_t omap_lpg_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 1) { + return omap_badwidth_read8(opaque, addr); + } + + switch (offset) { + case 0x00: /* LCR */ + return s->control; + + case 0x04: /* PMR */ + return s->power; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_lpg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (size != 1) { + return omap_badwidth_write8(opaque, addr, value); + } + + switch (offset) { + case 0x00: /* LCR */ + if (~value & (1 << 6)) /* LPGRES */ + omap_lpg_reset(s); + s->control = value & 0xff; + omap_lpg_update(s); + return; + + case 0x04: /* PMR */ + s->power = value & 0x01; + omap_lpg_update(s); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_lpg_ops = { + .read = omap_lpg_read, + .write = omap_lpg_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_lpg_clk_update(void *opaque, int line, int on) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + + s->clk = on; + omap_lpg_update(s); +} + +static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, + hwaddr base, omap_clk clk) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) + g_malloc0(sizeof(struct omap_lpg_s)); + + s->tm = qemu_new_timer_ms(vm_clock, omap_lpg_tick, s); + + omap_lpg_reset(s); + + memory_region_init_io(&s->iomem, &omap_lpg_ops, s, "omap-lpg", 0x800); + memory_region_add_subregion(system_memory, base, &s->iomem); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]); + + return s; +} + +/* MPUI Peripheral Bridge configuration */ +static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr, + unsigned size) +{ + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + if (addr == OMAP_MPUI_BASE) /* CMR */ + return 0xfe4d; + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpui_io_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + /* FIXME: infinite loop */ + omap_badwidth_write16(opaque, addr, value); +} + +static const MemoryRegionOps omap_mpui_io_ops = { + .read = omap_mpui_io_read, + .write = omap_mpui_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_setup_mpui_io(MemoryRegion *system_memory, + struct omap_mpu_state_s *mpu) +{ + memory_region_init_io(&mpu->mpui_io_iomem, &omap_mpui_io_ops, mpu, + "omap-mpui-io", 0x7fff); + memory_region_add_subregion(system_memory, OMAP_MPUI_BASE, + &mpu->mpui_io_iomem); +} + +/* General chip reset */ +static void omap1_mpu_reset(void *opaque) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + omap_dma_reset(mpu->dma); + omap_mpu_timer_reset(mpu->timer[0]); + omap_mpu_timer_reset(mpu->timer[1]); + omap_mpu_timer_reset(mpu->timer[2]); + omap_wd_timer_reset(mpu->wdt); + omap_os_timer_reset(mpu->os_timer); + omap_lcdc_reset(mpu->lcd); + omap_ulpd_pm_reset(mpu); + omap_pin_cfg_reset(mpu); + omap_mpui_reset(mpu); + omap_tipb_bridge_reset(mpu->private_tipb); + omap_tipb_bridge_reset(mpu->public_tipb); + omap_dpll_reset(mpu->dpll[0]); + omap_dpll_reset(mpu->dpll[1]); + omap_dpll_reset(mpu->dpll[2]); + omap_uart_reset(mpu->uart[0]); + omap_uart_reset(mpu->uart[1]); + omap_uart_reset(mpu->uart[2]); + omap_mmc_reset(mpu->mmc); + omap_mpuio_reset(mpu->mpuio); + omap_uwire_reset(mpu->microwire); + omap_pwl_reset(mpu->pwl); + omap_pwt_reset(mpu->pwt); + omap_rtc_reset(mpu->rtc); + omap_mcbsp_reset(mpu->mcbsp1); + omap_mcbsp_reset(mpu->mcbsp2); + omap_mcbsp_reset(mpu->mcbsp3); + omap_lpg_reset(mpu->led[0]); + omap_lpg_reset(mpu->led[1]); + omap_clkm_reset(mpu); + cpu_reset(CPU(mpu->cpu)); +} + +static const struct omap_map_s { + hwaddr phys_dsp; + hwaddr phys_mpu; + uint32_t size; + const char *name; +} omap15xx_dsp_mm[] = { + /* Strobe 0 */ + { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ + { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ + { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ + { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ + { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ + { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ + { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ + { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ + { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ + { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ + { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ + { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ + { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ + { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ + { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ + { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ + { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ + /* Strobe 1 */ + { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ + + { 0 } +}; + +static void omap_setup_dsp_mapping(MemoryRegion *system_memory, + const struct omap_map_s *map) +{ + MemoryRegion *io; + + for (; map->phys_dsp; map ++) { + io = g_new(MemoryRegion, 1); + memory_region_init_alias(io, map->name, + system_memory, map->phys_mpu, map->size); + memory_region_add_subregion(system_memory, map->phys_dsp, io); + } +} + +void omap_mpu_wakeup(void *opaque, int irq, int req) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + if (mpu->cpu->env.halted) { + cpu_interrupt(&mpu->cpu->env, CPU_INTERRUPT_EXITTB); + } +} + +static const struct dma_irq_map omap1_dma_irq_map[] = { + { 0, OMAP_INT_DMA_CH0_6 }, + { 0, OMAP_INT_DMA_CH1_7 }, + { 0, OMAP_INT_DMA_CH2_8 }, + { 0, OMAP_INT_DMA_CH3 }, + { 0, OMAP_INT_DMA_CH4 }, + { 0, OMAP_INT_DMA_CH5 }, + { 1, OMAP_INT_1610_DMA_CH6 }, + { 1, OMAP_INT_1610_DMA_CH7 }, + { 1, OMAP_INT_1610_DMA_CH8 }, + { 1, OMAP_INT_1610_DMA_CH9 }, + { 1, OMAP_INT_1610_DMA_CH10 }, + { 1, OMAP_INT_1610_DMA_CH11 }, + { 1, OMAP_INT_1610_DMA_CH12 }, + { 1, OMAP_INT_1610_DMA_CH13 }, + { 1, OMAP_INT_1610_DMA_CH14 }, + { 1, OMAP_INT_1610_DMA_CH15 } +}; + +/* DMA ports for OMAP1 */ +static int omap_validate_emiff_addr(struct omap_mpu_state_s *s, + hwaddr addr) +{ + return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr); +} + +static int omap_validate_emifs_addr(struct omap_mpu_state_s *s, + hwaddr addr) +{ + return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE, + addr); +} + +static int omap_validate_imif_addr(struct omap_mpu_state_s *s, + hwaddr addr) +{ + return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr); +} + +static int omap_validate_tipb_addr(struct omap_mpu_state_s *s, + hwaddr addr) +{ + return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr); +} + +static int omap_validate_local_addr(struct omap_mpu_state_s *s, + hwaddr addr) +{ + return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr); +} + +static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, + hwaddr addr) +{ + return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr); +} + +struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, + unsigned long sdram_size, + const char *core) +{ + int i; + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) + g_malloc0(sizeof(struct omap_mpu_state_s)); + qemu_irq *cpu_irq; + qemu_irq dma_irqs[6]; + DriveInfo *dinfo; + SysBusDevice *busdev; + + if (!core) + core = "ti925t"; + + /* Core */ + s->mpu_model = omap310; + s->cpu = cpu_arm_init(core); + if (s->cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + s->sdram_size = sdram_size; + s->sram_size = OMAP15XX_SRAM_SIZE; + + s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + + /* Clocks */ + omap_clk_init(s); + + /* Memory-mapped stuff */ + memory_region_init_ram(&s->emiff_ram, "omap1.dram", s->sdram_size); + vmstate_register_ram_global(&s->emiff_ram); + memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram); + memory_region_init_ram(&s->imif_ram, "omap1.sram", s->sram_size); + vmstate_register_ram_global(&s->imif_ram); + memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram); + + omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); + + cpu_irq = arm_pic_init_cpu(s->cpu); + s->ih[0] = qdev_create(NULL, "omap-intc"); + qdev_prop_set_uint32(s->ih[0], "size", 0x100); + qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck")); + qdev_init_nofail(s->ih[0]); + busdev = SYS_BUS_DEVICE(s->ih[0]); + sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); + sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); + sysbus_mmio_map(busdev, 0, 0xfffecb00); + s->ih[1] = qdev_create(NULL, "omap-intc"); + qdev_prop_set_uint32(s->ih[1], "size", 0x800); + qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck")); + qdev_init_nofail(s->ih[1]); + busdev = SYS_BUS_DEVICE(s->ih[1]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ)); + /* The second interrupt controller's FIQ output is not wired up */ + sysbus_mmio_map(busdev, 0, 0xfffe0000); + + for (i = 0; i < 6; i++) { + dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih], + omap1_dma_irq_map[i].intr); + } + s->dma = omap_dma_init(0xfffed800, dma_irqs, system_memory, + qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD), + s, omap_findclk(s, "dma_ck"), omap_dma_3_1); + + s->port[emiff ].addr_valid = omap_validate_emiff_addr; + s->port[emifs ].addr_valid = omap_validate_emifs_addr; + s->port[imif ].addr_valid = omap_validate_imif_addr; + s->port[tipb ].addr_valid = omap_validate_tipb_addr; + s->port[local ].addr_valid = omap_validate_local_addr; + s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; + + /* Register SDRAM and SRAM DMA ports for fast transfers. */ + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram), + OMAP_EMIFF_BASE, s->sdram_size); + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram), + OMAP_IMIF_BASE, s->sram_size); + + s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500, + qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1), + omap_findclk(s, "mputim_ck")); + s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600, + qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2), + omap_findclk(s, "mputim_ck")); + s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700, + qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3), + omap_findclk(s, "mputim_ck")); + + s->wdt = omap_wd_timer_init(system_memory, 0xfffec800, + qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER), + omap_findclk(s, "armwdt_ck")); + + s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000, + qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER), + omap_findclk(s, "clk32-kHz")); + + s->lcd = omap_lcdc_init(system_memory, 0xfffec000, + qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL), + omap_dma_get_lcdch(s->dma), + omap_findclk(s, "lcd_ck")); + + omap_ulpd_pm_init(system_memory, 0xfffe0800, s); + omap_pin_cfg_init(system_memory, 0xfffe1000, s); + omap_id_init(system_memory, s); + + omap_mpui_init(system_memory, 0xfffec900, s); + + s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00, + qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV), + omap_findclk(s, "tipb_ck")); + s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300, + qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB), + omap_findclk(s, "tipb_ck")); + + omap_tcmi_init(system_memory, 0xfffecc00, s); + + s->uart[0] = omap_uart_init(0xfffb0000, + qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1), + omap_findclk(s, "uart1_ck"), + omap_findclk(s, "uart1_ck"), + s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX], + "uart1", + serial_hds[0]); + s->uart[1] = omap_uart_init(0xfffb0800, + qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2), + omap_findclk(s, "uart2_ck"), + omap_findclk(s, "uart2_ck"), + s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX], + "uart2", + serial_hds[0] ? serial_hds[1] : NULL); + s->uart[2] = omap_uart_init(0xfffb9800, + qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3), + omap_findclk(s, "uart3_ck"), + omap_findclk(s, "uart3_ck"), + s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX], + "uart3", + serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL); + + s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00, + omap_findclk(s, "dpll1")); + s->dpll[1] = omap_dpll_init(system_memory, 0xfffed000, + omap_findclk(s, "dpll2")); + s->dpll[2] = omap_dpll_init(system_memory, 0xfffed100, + omap_findclk(s, "dpll3")); + + dinfo = drive_get(IF_SD, 0, 0); + if (!dinfo) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = omap_mmc_init(0xfffb7800, system_memory, dinfo->bdrv, + qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN), + &s->drq[OMAP_DMA_MMC_TX], + omap_findclk(s, "mmc_ck")); + + s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000, + qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD), + qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO), + s->wakeup, omap_findclk(s, "clk32-kHz")); + + s->gpio = qdev_create(NULL, "omap-gpio"); + qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); + qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck")); + qdev_init_nofail(s->gpio); + sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0, + qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1)); + sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000); + + s->microwire = omap_uwire_init(system_memory, 0xfffb3000, + qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX), + qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX), + s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); + + s->pwl = omap_pwl_init(system_memory, 0xfffb5800, + omap_findclk(s, "armxor_ck")); + s->pwt = omap_pwt_init(system_memory, 0xfffb6000, + omap_findclk(s, "armxor_ck")); + + s->i2c[0] = qdev_create(NULL, "omap_i2c"); + qdev_prop_set_uint8(s->i2c[0], "revision", 0x11); + qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck")); + qdev_init_nofail(s->i2c[0]); + busdev = SYS_BUS_DEVICE(s->i2c[0]); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C)); + sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]); + sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]); + sysbus_mmio_map(busdev, 0, 0xfffb3800); + + s->rtc = omap_rtc_init(system_memory, 0xfffb4800, + qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER), + qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM), + omap_findclk(s, "clk32-kHz")); + + s->mcbsp1 = omap_mcbsp_init(system_memory, 0xfffb1800, + qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX), + qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX), + &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); + s->mcbsp2 = omap_mcbsp_init(system_memory, 0xfffb1000, + qdev_get_gpio_in(s->ih[0], + OMAP_INT_310_McBSP2_TX), + qdev_get_gpio_in(s->ih[0], + OMAP_INT_310_McBSP2_RX), + &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); + s->mcbsp3 = omap_mcbsp_init(system_memory, 0xfffb7000, + qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX), + qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX), + &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); + + s->led[0] = omap_lpg_init(system_memory, + 0xfffbd000, omap_findclk(s, "clk32-kHz")); + s->led[1] = omap_lpg_init(system_memory, + 0xfffbd800, omap_findclk(s, "clk32-kHz")); + + /* Register mappings not currenlty implemented: + * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) + * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) + * USB W2FC fffb4000 - fffb47ff + * Camera Interface fffb6800 - fffb6fff + * USB Host fffba000 - fffba7ff + * FAC fffba800 - fffbafff + * HDQ/1-Wire fffbc000 - fffbc7ff + * TIPB switches fffbc800 - fffbcfff + * Mailbox fffcf000 - fffcf7ff + * Local bus IF fffec100 - fffec1ff + * Local bus MMU fffec200 - fffec2ff + * DSP MMU fffed200 - fffed2ff + */ + + omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm); + omap_setup_mpui_io(system_memory, s); + + qemu_register_reset(omap1_mpu_reset, s); + + return s; +} diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c new file mode 100644 index 0000000000..0a2cd7bab6 --- /dev/null +++ b/hw/arm/omap2.c @@ -0,0 +1,2684 @@ +/* + * TI OMAP processors emulation. + * + * Copyright (C) 2007-2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "sysemu/blockdev.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/omap.h" +#include "sysemu/sysemu.h" +#include "qemu/timer.h" +#include "char/char.h" +#include "hw/flash.h" +#include "hw/soc_dma.h" +#include "hw/sysbus.h" +#include "audio/audio.h" + +/* Enhanced Audio Controller (CODEC only) */ +struct omap_eac_s { + qemu_irq irq; + MemoryRegion iomem; + + uint16_t sysconfig; + uint8_t config[4]; + uint8_t control; + uint8_t address; + uint16_t data; + uint8_t vtol; + uint8_t vtsl; + uint16_t mixer; + uint16_t gain[4]; + uint8_t att; + uint16_t max[7]; + + struct { + qemu_irq txdrq; + qemu_irq rxdrq; + uint32_t (*txrx)(void *opaque, uint32_t, int); + void *opaque; + +#define EAC_BUF_LEN 1024 + uint32_t rxbuf[EAC_BUF_LEN]; + int rxoff; + int rxlen; + int rxavail; + uint32_t txbuf[EAC_BUF_LEN]; + int txlen; + int txavail; + + int enable; + int rate; + + uint16_t config[4]; + + /* These need to be moved to the actual codec */ + QEMUSoundCard card; + SWVoiceIn *in_voice; + SWVoiceOut *out_voice; + int hw_enable; + } codec; + + struct { + uint8_t control; + uint16_t config; + } modem, bt; +}; + +static inline void omap_eac_interrupt_update(struct omap_eac_s *s) +{ + qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */ +} + +static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s) +{ + qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) && + ((s->codec.config[1] >> 12) & 1)); /* DMAREN */ +} + +static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s) +{ + qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail && + ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */ +} + +static inline void omap_eac_in_refill(struct omap_eac_s *s) +{ + int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2; + int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2; + int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start); + int recv = 1; + uint8_t *buf = (uint8_t *) s->codec.rxbuf + start; + + left -= leftwrap; + start = 0; + while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start, + leftwrap)) > 0) { /* Be defensive */ + start += recv; + leftwrap -= recv; + } + if (recv <= 0) + s->codec.rxavail = 0; + else + s->codec.rxavail -= start >> 2; + s->codec.rxlen += start >> 2; + + if (recv > 0 && left > 0) { + start = 0; + while (left && (recv = AUD_read(s->codec.in_voice, + (uint8_t *) s->codec.rxbuf + start, + left)) > 0) { /* Be defensive */ + start += recv; + left -= recv; + } + if (recv <= 0) + s->codec.rxavail = 0; + else + s->codec.rxavail -= start >> 2; + s->codec.rxlen += start >> 2; + } +} + +static inline void omap_eac_out_empty(struct omap_eac_s *s) +{ + int left = s->codec.txlen << 2; + int start = 0; + int sent = 1; + + while (left && (sent = AUD_write(s->codec.out_voice, + (uint8_t *) s->codec.txbuf + start, + left)) > 0) { /* Be defensive */ + start += sent; + left -= sent; + } + + if (!sent) { + s->codec.txavail = 0; + omap_eac_out_dmarequest_update(s); + } + + if (start) + s->codec.txlen = 0; +} + +static void omap_eac_in_cb(void *opaque, int avail_b) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + + s->codec.rxavail = avail_b >> 2; + omap_eac_in_refill(s); + /* TODO: possibly discard current buffer if overrun */ + omap_eac_in_dmarequest_update(s); +} + +static void omap_eac_out_cb(void *opaque, int free_b) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + + s->codec.txavail = free_b >> 2; + if (s->codec.txlen) + omap_eac_out_empty(s); + else + omap_eac_out_dmarequest_update(s); +} + +static void omap_eac_enable_update(struct omap_eac_s *s) +{ + s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */ + (s->codec.config[1] & 2) && /* AUDEN */ + s->codec.hw_enable; +} + +static const int omap_eac_fsint[4] = { + 8000, + 11025, + 22050, + 44100, +}; + +static const int omap_eac_fsint2[8] = { + 8000, + 11025, + 22050, + 44100, + 48000, + 0, 0, 0, +}; + +static const int omap_eac_fsint3[16] = { + 8000, + 11025, + 16000, + 22050, + 24000, + 32000, + 44100, + 48000, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void omap_eac_rate_update(struct omap_eac_s *s) +{ + int fsint[3]; + + fsint[2] = (s->codec.config[3] >> 9) & 0xf; + fsint[1] = (s->codec.config[2] >> 0) & 0x7; + fsint[0] = (s->codec.config[0] >> 6) & 0x3; + if (fsint[2] < 0xf) + s->codec.rate = omap_eac_fsint3[fsint[2]]; + else if (fsint[1] < 0x7) + s->codec.rate = omap_eac_fsint2[fsint[1]]; + else + s->codec.rate = omap_eac_fsint[fsint[0]]; +} + +static void omap_eac_volume_update(struct omap_eac_s *s) +{ + /* TODO */ +} + +static void omap_eac_format_update(struct omap_eac_s *s) +{ + struct audsettings fmt; + + /* The hardware buffers at most one sample */ + if (s->codec.rxlen) + s->codec.rxlen = 1; + + if (s->codec.in_voice) { + AUD_set_active_in(s->codec.in_voice, 0); + AUD_close_in(&s->codec.card, s->codec.in_voice); + s->codec.in_voice = NULL; + } + if (s->codec.out_voice) { + omap_eac_out_empty(s); + AUD_set_active_out(s->codec.out_voice, 0); + AUD_close_out(&s->codec.card, s->codec.out_voice); + s->codec.out_voice = NULL; + s->codec.txavail = 0; + } + /* Discard what couldn't be written */ + s->codec.txlen = 0; + + omap_eac_enable_update(s); + if (!s->codec.enable) + return; + + omap_eac_rate_update(s); + fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */ + fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */ + fmt.freq = s->codec.rate; + /* TODO: signedness possibly depends on the CODEC hardware - or + * does I2S specify it? */ + /* All register writes are 16 bits so we we store 16-bit samples + * in the buffers regardless of AGCFR[B8_16] value. */ + fmt.fmt = AUD_FMT_U16; + + s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice, + "eac.codec.in", s, omap_eac_in_cb, &fmt); + s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice, + "eac.codec.out", s, omap_eac_out_cb, &fmt); + + omap_eac_volume_update(s); + + AUD_set_active_in(s->codec.in_voice, 1); + AUD_set_active_out(s->codec.out_voice, 1); +} + +static void omap_eac_reset(struct omap_eac_s *s) +{ + s->sysconfig = 0; + s->config[0] = 0x0c; + s->config[1] = 0x09; + s->config[2] = 0xab; + s->config[3] = 0x03; + s->control = 0x00; + s->address = 0x00; + s->data = 0x0000; + s->vtol = 0x00; + s->vtsl = 0x00; + s->mixer = 0x0000; + s->gain[0] = 0xe7e7; + s->gain[1] = 0x6767; + s->gain[2] = 0x6767; + s->gain[3] = 0x6767; + s->att = 0xce; + s->max[0] = 0; + s->max[1] = 0; + s->max[2] = 0; + s->max[3] = 0; + s->max[4] = 0; + s->max[5] = 0; + s->max[6] = 0; + + s->modem.control = 0x00; + s->modem.config = 0x0000; + s->bt.control = 0x00; + s->bt.config = 0x0000; + s->codec.config[0] = 0x0649; + s->codec.config[1] = 0x0000; + s->codec.config[2] = 0x0007; + s->codec.config[3] = 0x1ffc; + s->codec.rxoff = 0; + s->codec.rxlen = 0; + s->codec.txlen = 0; + s->codec.rxavail = 0; + s->codec.txavail = 0; + + omap_eac_format_update(s); + omap_eac_interrupt_update(s); +} + +static uint64_t omap_eac_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + uint32_t ret; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (addr) { + case 0x000: /* CPCFR1 */ + return s->config[0]; + case 0x004: /* CPCFR2 */ + return s->config[1]; + case 0x008: /* CPCFR3 */ + return s->config[2]; + case 0x00c: /* CPCFR4 */ + return s->config[3]; + + case 0x010: /* CPTCTL */ + return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) | + ((s->codec.txlen < s->codec.txavail) << 5); + + case 0x014: /* CPTTADR */ + return s->address; + case 0x018: /* CPTDATL */ + return s->data & 0xff; + case 0x01c: /* CPTDATH */ + return s->data >> 8; + case 0x020: /* CPTVSLL */ + return s->vtol; + case 0x024: /* CPTVSLH */ + return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */ + case 0x040: /* MPCTR */ + return s->modem.control; + case 0x044: /* MPMCCFR */ + return s->modem.config; + case 0x060: /* BPCTR */ + return s->bt.control; + case 0x064: /* BPMCCFR */ + return s->bt.config; + case 0x080: /* AMSCFR */ + return s->mixer; + case 0x084: /* AMVCTR */ + return s->gain[0]; + case 0x088: /* AM1VCTR */ + return s->gain[1]; + case 0x08c: /* AM2VCTR */ + return s->gain[2]; + case 0x090: /* AM3VCTR */ + return s->gain[3]; + case 0x094: /* ASTCTR */ + return s->att; + case 0x098: /* APD1LCR */ + return s->max[0]; + case 0x09c: /* APD1RCR */ + return s->max[1]; + case 0x0a0: /* APD2LCR */ + return s->max[2]; + case 0x0a4: /* APD2RCR */ + return s->max[3]; + case 0x0a8: /* APD3LCR */ + return s->max[4]; + case 0x0ac: /* APD3RCR */ + return s->max[5]; + case 0x0b0: /* APD4R */ + return s->max[6]; + case 0x0b4: /* ADWR */ + /* This should be write-only? Docs list it as read-only. */ + return 0x0000; + case 0x0b8: /* ADRDR */ + if (likely(s->codec.rxlen > 1)) { + ret = s->codec.rxbuf[s->codec.rxoff ++]; + s->codec.rxlen --; + s->codec.rxoff &= EAC_BUF_LEN - 1; + return ret; + } else if (s->codec.rxlen) { + ret = s->codec.rxbuf[s->codec.rxoff ++]; + s->codec.rxlen --; + s->codec.rxoff &= EAC_BUF_LEN - 1; + if (s->codec.rxavail) + omap_eac_in_refill(s); + omap_eac_in_dmarequest_update(s); + return ret; + } + return 0x0000; + case 0x0bc: /* AGCFR */ + return s->codec.config[0]; + case 0x0c0: /* AGCTR */ + return s->codec.config[1] | ((s->codec.config[1] & 2) << 14); + case 0x0c4: /* AGCFR2 */ + return s->codec.config[2]; + case 0x0c8: /* AGCFR3 */ + return s->codec.config[3]; + case 0x0cc: /* MBPDMACTR */ + case 0x0d0: /* MPDDMARR */ + case 0x0d8: /* MPUDMARR */ + case 0x0e4: /* BPDDMARR */ + case 0x0ec: /* BPUDMARR */ + return 0x0000; + + case 0x100: /* VERSION_NUMBER */ + return 0x0010; + + case 0x104: /* SYSCONFIG */ + return s->sysconfig; + + case 0x108: /* SYSSTATUS */ + return 1 | 0xe; /* RESETDONE | stuff */ + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_eac_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_eac_s *s = (struct omap_eac_s *) opaque; + + if (size != 2) { + return omap_badwidth_write16(opaque, addr, value); + } + + switch (addr) { + case 0x098: /* APD1LCR */ + case 0x09c: /* APD1RCR */ + case 0x0a0: /* APD2LCR */ + case 0x0a4: /* APD2RCR */ + case 0x0a8: /* APD3LCR */ + case 0x0ac: /* APD3RCR */ + case 0x0b0: /* APD4R */ + case 0x0b8: /* ADRDR */ + case 0x0d0: /* MPDDMARR */ + case 0x0d8: /* MPUDMARR */ + case 0x0e4: /* BPDDMARR */ + case 0x0ec: /* BPUDMARR */ + case 0x100: /* VERSION_NUMBER */ + case 0x108: /* SYSSTATUS */ + OMAP_RO_REG(addr); + return; + + case 0x000: /* CPCFR1 */ + s->config[0] = value & 0xff; + omap_eac_format_update(s); + break; + case 0x004: /* CPCFR2 */ + s->config[1] = value & 0xff; + omap_eac_format_update(s); + break; + case 0x008: /* CPCFR3 */ + s->config[2] = value & 0xff; + omap_eac_format_update(s); + break; + case 0x00c: /* CPCFR4 */ + s->config[3] = value & 0xff; + omap_eac_format_update(s); + break; + + case 0x010: /* CPTCTL */ + /* Assuming TXF and TXE bits are read-only... */ + s->control = value & 0x5f; + omap_eac_interrupt_update(s); + break; + + case 0x014: /* CPTTADR */ + s->address = value & 0xff; + break; + case 0x018: /* CPTDATL */ + s->data &= 0xff00; + s->data |= value & 0xff; + break; + case 0x01c: /* CPTDATH */ + s->data &= 0x00ff; + s->data |= value << 8; + break; + case 0x020: /* CPTVSLL */ + s->vtol = value & 0xf8; + break; + case 0x024: /* CPTVSLH */ + s->vtsl = value & 0x9f; + break; + case 0x040: /* MPCTR */ + s->modem.control = value & 0x8f; + break; + case 0x044: /* MPMCCFR */ + s->modem.config = value & 0x7fff; + break; + case 0x060: /* BPCTR */ + s->bt.control = value & 0x8f; + break; + case 0x064: /* BPMCCFR */ + s->bt.config = value & 0x7fff; + break; + case 0x080: /* AMSCFR */ + s->mixer = value & 0x0fff; + break; + case 0x084: /* AMVCTR */ + s->gain[0] = value & 0xffff; + break; + case 0x088: /* AM1VCTR */ + s->gain[1] = value & 0xff7f; + break; + case 0x08c: /* AM2VCTR */ + s->gain[2] = value & 0xff7f; + break; + case 0x090: /* AM3VCTR */ + s->gain[3] = value & 0xff7f; + break; + case 0x094: /* ASTCTR */ + s->att = value & 0xff; + break; + + case 0x0b4: /* ADWR */ + s->codec.txbuf[s->codec.txlen ++] = value; + if (unlikely(s->codec.txlen == EAC_BUF_LEN || + s->codec.txlen == s->codec.txavail)) { + if (s->codec.txavail) + omap_eac_out_empty(s); + /* Discard what couldn't be written */ + s->codec.txlen = 0; + } + break; + + case 0x0bc: /* AGCFR */ + s->codec.config[0] = value & 0x07ff; + omap_eac_format_update(s); + break; + case 0x0c0: /* AGCTR */ + s->codec.config[1] = value & 0x780f; + omap_eac_format_update(s); + break; + case 0x0c4: /* AGCFR2 */ + s->codec.config[2] = value & 0x003f; + omap_eac_format_update(s); + break; + case 0x0c8: /* AGCFR3 */ + s->codec.config[3] = value & 0xffff; + omap_eac_format_update(s); + break; + case 0x0cc: /* MBPDMACTR */ + case 0x0d4: /* MPDDMAWR */ + case 0x0e0: /* MPUDMAWR */ + case 0x0e8: /* BPDDMAWR */ + case 0x0f0: /* BPUDMAWR */ + break; + + case 0x104: /* SYSCONFIG */ + if (value & (1 << 1)) /* SOFTRESET */ + omap_eac_reset(s); + s->sysconfig = value & 0x31d; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_eac_ops = { + .read = omap_eac_read, + .write = omap_eac_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, + qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) +{ + struct omap_eac_s *s = (struct omap_eac_s *) + g_malloc0(sizeof(struct omap_eac_s)); + + s->irq = irq; + s->codec.rxdrq = *drq ++; + s->codec.txdrq = *drq; + omap_eac_reset(s); + + AUD_register_card("OMAP EAC", &s->codec.card); + + memory_region_init_io(&s->iomem, &omap_eac_ops, s, "omap.eac", + omap_l4_region_size(ta, 0)); + omap_l4_attach(ta, 0, &s->iomem); + + return s; +} + +/* STI/XTI (emulation interface) console - reverse engineered only */ +struct omap_sti_s { + qemu_irq irq; + MemoryRegion iomem; + MemoryRegion iomem_fifo; + CharDriverState *chr; + + uint32_t sysconfig; + uint32_t systest; + uint32_t irqst; + uint32_t irqen; + uint32_t clkcontrol; + uint32_t serial_config; +}; + +#define STI_TRACE_CONSOLE_CHANNEL 239 +#define STI_TRACE_CONTROL_CHANNEL 253 + +static inline void omap_sti_interrupt_update(struct omap_sti_s *s) +{ + qemu_set_irq(s->irq, s->irqst & s->irqen); +} + +static void omap_sti_reset(struct omap_sti_s *s) +{ + s->sysconfig = 0; + s->irqst = 0; + s->irqen = 0; + s->clkcontrol = 0; + s->serial_config = 0; + + omap_sti_interrupt_update(s); +} + +static uint64_t omap_sti_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_sti_s *s = (struct omap_sti_s *) opaque; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x00: /* STI_REVISION */ + return 0x10; + + case 0x10: /* STI_SYSCONFIG */ + return s->sysconfig; + + case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ + return 0x00; + + case 0x18: /* STI_IRQSTATUS */ + return s->irqst; + + case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ + return s->irqen; + + case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ + case 0x28: /* STI_RX_DR / XTI_RXDATA */ + /* TODO */ + return 0; + + case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ + return s->clkcontrol; + + case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ + return s->serial_config; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sti_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_sti_s *s = (struct omap_sti_s *) opaque; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* STI_REVISION */ + case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ + OMAP_RO_REG(addr); + return; + + case 0x10: /* STI_SYSCONFIG */ + if (value & (1 << 1)) /* SOFTRESET */ + omap_sti_reset(s); + s->sysconfig = value & 0xfe; + break; + + case 0x18: /* STI_IRQSTATUS */ + s->irqst &= ~value; + omap_sti_interrupt_update(s); + break; + + case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ + s->irqen = value & 0xffff; + omap_sti_interrupt_update(s); + break; + + case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ + s->clkcontrol = value & 0xff; + break; + + case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ + s->serial_config = value & 0xff; + break; + + case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ + case 0x28: /* STI_RX_DR / XTI_RXDATA */ + /* TODO */ + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_sti_ops = { + .read = omap_sti_read, + .write = omap_sti_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, + unsigned size) +{ + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sti_fifo_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_sti_s *s = (struct omap_sti_s *) opaque; + int ch = addr >> 6; + uint8_t byte = value; + + if (size != 1) { + return omap_badwidth_write8(opaque, addr, size); + } + + if (ch == STI_TRACE_CONTROL_CHANNEL) { + /* Flush channel value. */ + qemu_chr_fe_write(s->chr, (const uint8_t *) "\r", 1); + } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) { + if (value == 0xc0 || value == 0xc3) { + /* Open channel ch. */ + } else if (value == 0x00) + qemu_chr_fe_write(s->chr, (const uint8_t *) "\n", 1); + else + qemu_chr_fe_write(s->chr, &byte, 1); + } +} + +static const MemoryRegionOps omap_sti_fifo_ops = { + .read = omap_sti_fifo_read, + .write = omap_sti_fifo_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta, + MemoryRegion *sysmem, + hwaddr channel_base, qemu_irq irq, omap_clk clk, + CharDriverState *chr) +{ + struct omap_sti_s *s = (struct omap_sti_s *) + g_malloc0(sizeof(struct omap_sti_s)); + + s->irq = irq; + omap_sti_reset(s); + + s->chr = chr ?: qemu_chr_new("null", "null", NULL); + + memory_region_init_io(&s->iomem, &omap_sti_ops, s, "omap.sti", + omap_l4_region_size(ta, 0)); + omap_l4_attach(ta, 0, &s->iomem); + + memory_region_init_io(&s->iomem_fifo, &omap_sti_fifo_ops, s, + "omap.sti.fifo", 0x10000); + memory_region_add_subregion(sysmem, channel_base, &s->iomem_fifo); + + return s; +} + +/* L4 Interconnect */ +#define L4TA(n) (n) +#define L4TAO(n) ((n) + 39) + +static const struct omap_l4_region_s omap_l4_region[125] = { + [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */ + [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */ + [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */ + [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */ + [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */ + [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */ + [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */ + [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */ + [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */ + [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */ + [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */ + [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */ + [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */ + [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */ + [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */ + [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */ + [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */ + [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */ + [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */ + [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */ + [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */ + [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */ + [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */ + [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */ + [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */ + [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */ + [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */ + [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */ + [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */ + [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */ + [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */ + [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */ + [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */ + [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */ + [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */ + [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */ + [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */ + [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */ + [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */ + [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */ + [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */ + [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */ + [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */ + [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */ + [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */ + [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */ + [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */ + [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */ + [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */ + [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */ + [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */ + [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */ + [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */ + [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */ + [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */ + [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */ + [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */ + [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */ + [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */ + [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */ + [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */ + [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */ + [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */ + [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */ + [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */ + [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */ + [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */ + [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */ + [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */ + [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */ + [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */ + [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */ + [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */ + [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */ + [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */ + [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */ + [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */ + [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */ + [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */ + [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */ + [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */ + [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */ + [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */ + [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */ + [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */ + [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */ + [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */ + [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */ + [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */ + [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */ + [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */ + [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */ + [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */ + [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */ + [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */ + [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */ + [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */ + [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */ + [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */ + [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */ + [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */ + [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */ + [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */ + [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */ + [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */ + [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */ + [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */ + [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */ + [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */ + [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */ + [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */ + [111] = { 0xa0000, 0x1000, 32 }, /* RNG */ + [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */ + [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */ + [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */ + [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */ + [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */ + [117] = { 0xa6000, 0x1000, 32 }, /* AES */ + [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */ + [119] = { 0xa8000, 0x2000, 32 }, /* PKA */ + [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */ + [121] = { 0xb0000, 0x1000, 32 }, /* MG */ + [122] = { 0xb1000, 0x1000, 32 | 16 | 8 }, + [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */ + [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */ +}; + +static const struct omap_l4_agent_info_s omap_l4_agent_info[54] = { + { 0, 0, 3, 2 }, /* L4IA initiatior agent */ + { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */ + { L4TAO(2), 5, 2, 1 }, /* 32K timer */ + { L4TAO(3), 7, 3, 2 }, /* PRCM */ + { L4TA(1), 10, 2, 1 }, /* BCM */ + { L4TA(2), 12, 2, 1 }, /* Test JTAG */ + { L4TA(3), 14, 6, 3 }, /* Quad GPIO */ + { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */ + { L4TA(7), 24, 2, 1 }, /* GP timer 1 */ + { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */ + { L4TA(10), 28, 5, 4 }, /* Display subsystem */ + { L4TA(11), 33, 5, 4 }, /* Camera subsystem */ + { L4TA(12), 38, 2, 1 }, /* sDMA */ + { L4TA(13), 40, 5, 4 }, /* SSI */ + { L4TAO(4), 45, 2, 1 }, /* USB */ + { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */ + { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */ + { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */ + { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */ + { L4TA(18), 55, 2, 1 }, /* XTI */ + { L4TA(19), 57, 2, 1 }, /* UART1 */ + { L4TA(20), 59, 2, 1 }, /* UART2 */ + { L4TA(21), 61, 2, 1 }, /* UART3 */ + { L4TAO(5), 63, 2, 1 }, /* I2C1 */ + { L4TAO(6), 65, 2, 1 }, /* I2C2 */ + { L4TAO(7), 67, 2, 1 }, /* McBSP1 */ + { L4TAO(8), 69, 2, 1 }, /* McBSP2 */ + { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */ + { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */ + { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */ + { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */ + { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */ + { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */ + { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */ + { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */ + { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */ + { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */ + { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */ + { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */ + { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */ + { L4TA(32), 97, 2, 1 }, /* EAC */ + { L4TA(33), 99, 2, 1 }, /* FAC */ + { L4TA(34), 101, 2, 1 }, /* IPC */ + { L4TA(35), 103, 2, 1 }, /* SPI1 */ + { L4TA(36), 105, 2, 1 }, /* SPI2 */ + { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */ + { L4TAO(10), 109, 2, 1 }, + { L4TAO(11), 111, 2, 1 }, /* RNG */ + { L4TAO(12), 113, 2, 1 }, /* DES3DES */ + { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */ + { L4TA(37), 117, 2, 1 }, /* AES */ + { L4TA(38), 119, 2, 1 }, /* PKA */ + { -1, 121, 2, 1 }, + { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */ +}; + +#define omap_l4ta(bus, cs) \ + omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TA(cs)) +#define omap_l4tao(bus, cs) \ + omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TAO(cs)) + +/* Power, Reset, and Clock Management */ +struct omap_prcm_s { + qemu_irq irq[3]; + struct omap_mpu_state_s *mpu; + MemoryRegion iomem0; + MemoryRegion iomem1; + + uint32_t irqst[3]; + uint32_t irqen[3]; + + uint32_t sysconfig; + uint32_t voltctrl; + uint32_t scratch[20]; + + uint32_t clksrc[1]; + uint32_t clkout[1]; + uint32_t clkemul[1]; + uint32_t clkpol[1]; + uint32_t clksel[8]; + uint32_t clken[12]; + uint32_t clkctrl[4]; + uint32_t clkidle[7]; + uint32_t setuptime[2]; + + uint32_t wkup[3]; + uint32_t wken[3]; + uint32_t wkst[3]; + uint32_t rst[4]; + uint32_t rstctrl[1]; + uint32_t power[4]; + uint32_t rsttime_wkup; + + uint32_t ev; + uint32_t evtime[2]; + + int dpll_lock, apll_lock[2]; +}; + +static void omap_prcm_int_update(struct omap_prcm_s *s, int dom) +{ + qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]); + /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */ +} + +static uint64_t omap_prcm_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; + uint32_t ret; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x000: /* PRCM_REVISION */ + return 0x10; + + case 0x010: /* PRCM_SYSCONFIG */ + return s->sysconfig; + + case 0x018: /* PRCM_IRQSTATUS_MPU */ + return s->irqst[0]; + + case 0x01c: /* PRCM_IRQENABLE_MPU */ + return s->irqen[0]; + + case 0x050: /* PRCM_VOLTCTRL */ + return s->voltctrl; + case 0x054: /* PRCM_VOLTST */ + return s->voltctrl & 3; + + case 0x060: /* PRCM_CLKSRC_CTRL */ + return s->clksrc[0]; + case 0x070: /* PRCM_CLKOUT_CTRL */ + return s->clkout[0]; + case 0x078: /* PRCM_CLKEMUL_CTRL */ + return s->clkemul[0]; + case 0x080: /* PRCM_CLKCFG_CTRL */ + case 0x084: /* PRCM_CLKCFG_STATUS */ + return 0; + + case 0x090: /* PRCM_VOLTSETUP */ + return s->setuptime[0]; + + case 0x094: /* PRCM_CLKSSETUP */ + return s->setuptime[1]; + + case 0x098: /* PRCM_POLCTRL */ + return s->clkpol[0]; + + case 0x0b0: /* GENERAL_PURPOSE1 */ + case 0x0b4: /* GENERAL_PURPOSE2 */ + case 0x0b8: /* GENERAL_PURPOSE3 */ + case 0x0bc: /* GENERAL_PURPOSE4 */ + case 0x0c0: /* GENERAL_PURPOSE5 */ + case 0x0c4: /* GENERAL_PURPOSE6 */ + case 0x0c8: /* GENERAL_PURPOSE7 */ + case 0x0cc: /* GENERAL_PURPOSE8 */ + case 0x0d0: /* GENERAL_PURPOSE9 */ + case 0x0d4: /* GENERAL_PURPOSE10 */ + case 0x0d8: /* GENERAL_PURPOSE11 */ + case 0x0dc: /* GENERAL_PURPOSE12 */ + case 0x0e0: /* GENERAL_PURPOSE13 */ + case 0x0e4: /* GENERAL_PURPOSE14 */ + case 0x0e8: /* GENERAL_PURPOSE15 */ + case 0x0ec: /* GENERAL_PURPOSE16 */ + case 0x0f0: /* GENERAL_PURPOSE17 */ + case 0x0f4: /* GENERAL_PURPOSE18 */ + case 0x0f8: /* GENERAL_PURPOSE19 */ + case 0x0fc: /* GENERAL_PURPOSE20 */ + return s->scratch[(addr - 0xb0) >> 2]; + + case 0x140: /* CM_CLKSEL_MPU */ + return s->clksel[0]; + case 0x148: /* CM_CLKSTCTRL_MPU */ + return s->clkctrl[0]; + + case 0x158: /* RM_RSTST_MPU */ + return s->rst[0]; + case 0x1c8: /* PM_WKDEP_MPU */ + return s->wkup[0]; + case 0x1d4: /* PM_EVGENCTRL_MPU */ + return s->ev; + case 0x1d8: /* PM_EVEGENONTIM_MPU */ + return s->evtime[0]; + case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ + return s->evtime[1]; + case 0x1e0: /* PM_PWSTCTRL_MPU */ + return s->power[0]; + case 0x1e4: /* PM_PWSTST_MPU */ + return 0; + + case 0x200: /* CM_FCLKEN1_CORE */ + return s->clken[0]; + case 0x204: /* CM_FCLKEN2_CORE */ + return s->clken[1]; + case 0x210: /* CM_ICLKEN1_CORE */ + return s->clken[2]; + case 0x214: /* CM_ICLKEN2_CORE */ + return s->clken[3]; + case 0x21c: /* CM_ICLKEN4_CORE */ + return s->clken[4]; + + case 0x220: /* CM_IDLEST1_CORE */ + /* TODO: check the actual iclk status */ + return 0x7ffffff9; + case 0x224: /* CM_IDLEST2_CORE */ + /* TODO: check the actual iclk status */ + return 0x00000007; + case 0x22c: /* CM_IDLEST4_CORE */ + /* TODO: check the actual iclk status */ + return 0x0000001f; + + case 0x230: /* CM_AUTOIDLE1_CORE */ + return s->clkidle[0]; + case 0x234: /* CM_AUTOIDLE2_CORE */ + return s->clkidle[1]; + case 0x238: /* CM_AUTOIDLE3_CORE */ + return s->clkidle[2]; + case 0x23c: /* CM_AUTOIDLE4_CORE */ + return s->clkidle[3]; + + case 0x240: /* CM_CLKSEL1_CORE */ + return s->clksel[1]; + case 0x244: /* CM_CLKSEL2_CORE */ + return s->clksel[2]; + + case 0x248: /* CM_CLKSTCTRL_CORE */ + return s->clkctrl[1]; + + case 0x2a0: /* PM_WKEN1_CORE */ + return s->wken[0]; + case 0x2a4: /* PM_WKEN2_CORE */ + return s->wken[1]; + + case 0x2b0: /* PM_WKST1_CORE */ + return s->wkst[0]; + case 0x2b4: /* PM_WKST2_CORE */ + return s->wkst[1]; + case 0x2c8: /* PM_WKDEP_CORE */ + return 0x1e; + + case 0x2e0: /* PM_PWSTCTRL_CORE */ + return s->power[1]; + case 0x2e4: /* PM_PWSTST_CORE */ + return 0x000030 | (s->power[1] & 0xfc00); + + case 0x300: /* CM_FCLKEN_GFX */ + return s->clken[5]; + case 0x310: /* CM_ICLKEN_GFX */ + return s->clken[6]; + case 0x320: /* CM_IDLEST_GFX */ + /* TODO: check the actual iclk status */ + return 0x00000001; + case 0x340: /* CM_CLKSEL_GFX */ + return s->clksel[3]; + case 0x348: /* CM_CLKSTCTRL_GFX */ + return s->clkctrl[2]; + case 0x350: /* RM_RSTCTRL_GFX */ + return s->rstctrl[0]; + case 0x358: /* RM_RSTST_GFX */ + return s->rst[1]; + case 0x3c8: /* PM_WKDEP_GFX */ + return s->wkup[1]; + + case 0x3e0: /* PM_PWSTCTRL_GFX */ + return s->power[2]; + case 0x3e4: /* PM_PWSTST_GFX */ + return s->power[2] & 3; + + case 0x400: /* CM_FCLKEN_WKUP */ + return s->clken[7]; + case 0x410: /* CM_ICLKEN_WKUP */ + return s->clken[8]; + case 0x420: /* CM_IDLEST_WKUP */ + /* TODO: check the actual iclk status */ + return 0x0000003f; + case 0x430: /* CM_AUTOIDLE_WKUP */ + return s->clkidle[4]; + case 0x440: /* CM_CLKSEL_WKUP */ + return s->clksel[4]; + case 0x450: /* RM_RSTCTRL_WKUP */ + return 0; + case 0x454: /* RM_RSTTIME_WKUP */ + return s->rsttime_wkup; + case 0x458: /* RM_RSTST_WKUP */ + return s->rst[2]; + case 0x4a0: /* PM_WKEN_WKUP */ + return s->wken[2]; + case 0x4b0: /* PM_WKST_WKUP */ + return s->wkst[2]; + + case 0x500: /* CM_CLKEN_PLL */ + return s->clken[9]; + case 0x520: /* CM_IDLEST_CKGEN */ + ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8); + if (!(s->clksel[6] & 3)) + /* Core uses 32-kHz clock */ + ret |= 3 << 0; + else if (!s->dpll_lock) + /* DPLL not locked, core uses ref_clk */ + ret |= 1 << 0; + else + /* Core uses DPLL */ + ret |= 2 << 0; + return ret; + case 0x530: /* CM_AUTOIDLE_PLL */ + return s->clkidle[5]; + case 0x540: /* CM_CLKSEL1_PLL */ + return s->clksel[5]; + case 0x544: /* CM_CLKSEL2_PLL */ + return s->clksel[6]; + + case 0x800: /* CM_FCLKEN_DSP */ + return s->clken[10]; + case 0x810: /* CM_ICLKEN_DSP */ + return s->clken[11]; + case 0x820: /* CM_IDLEST_DSP */ + /* TODO: check the actual iclk status */ + return 0x00000103; + case 0x830: /* CM_AUTOIDLE_DSP */ + return s->clkidle[6]; + case 0x840: /* CM_CLKSEL_DSP */ + return s->clksel[7]; + case 0x848: /* CM_CLKSTCTRL_DSP */ + return s->clkctrl[3]; + case 0x850: /* RM_RSTCTRL_DSP */ + return 0; + case 0x858: /* RM_RSTST_DSP */ + return s->rst[3]; + case 0x8c8: /* PM_WKDEP_DSP */ + return s->wkup[2]; + case 0x8e0: /* PM_PWSTCTRL_DSP */ + return s->power[3]; + case 0x8e4: /* PM_PWSTST_DSP */ + return 0x008030 | (s->power[3] & 0x3003); + + case 0x8f0: /* PRCM_IRQSTATUS_DSP */ + return s->irqst[1]; + case 0x8f4: /* PRCM_IRQENABLE_DSP */ + return s->irqen[1]; + + case 0x8f8: /* PRCM_IRQSTATUS_IVA */ + return s->irqst[2]; + case 0x8fc: /* PRCM_IRQENABLE_IVA */ + return s->irqen[2]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_prcm_apll_update(struct omap_prcm_s *s) +{ + int mode[2]; + + mode[0] = (s->clken[9] >> 6) & 3; + s->apll_lock[0] = (mode[0] == 3); + mode[1] = (s->clken[9] >> 2) & 3; + s->apll_lock[1] = (mode[1] == 3); + /* TODO: update clocks */ + + if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[1] == 2) + fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n", + __FUNCTION__); +} + +static void omap_prcm_dpll_update(struct omap_prcm_s *s) +{ + omap_clk dpll = omap_findclk(s->mpu, "dpll"); + omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll"); + omap_clk core = omap_findclk(s->mpu, "core_clk"); + int mode = (s->clken[9] >> 0) & 3; + int mult, div; + + mult = (s->clksel[5] >> 12) & 0x3ff; + div = (s->clksel[5] >> 8) & 0xf; + if (mult == 0 || mult == 1) + mode = 1; /* Bypass */ + + s->dpll_lock = 0; + switch (mode) { + case 0: + fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__); + break; + case 1: /* Low-power bypass mode (Default) */ + case 2: /* Fast-relock bypass mode */ + omap_clk_setrate(dpll, 1, 1); + omap_clk_setrate(dpll_x2, 1, 1); + break; + case 3: /* Lock mode */ + s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */ + + omap_clk_setrate(dpll, div + 1, mult); + omap_clk_setrate(dpll_x2, div + 1, mult * 2); + break; + } + + switch ((s->clksel[6] >> 0) & 3) { + case 0: + omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz")); + break; + case 1: + omap_clk_reparent(core, dpll); + break; + case 2: + /* Default */ + omap_clk_reparent(core, dpll_x2); + break; + case 3: + fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__); + break; + } +} + +static void omap_prcm_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x000: /* PRCM_REVISION */ + case 0x054: /* PRCM_VOLTST */ + case 0x084: /* PRCM_CLKCFG_STATUS */ + case 0x1e4: /* PM_PWSTST_MPU */ + case 0x220: /* CM_IDLEST1_CORE */ + case 0x224: /* CM_IDLEST2_CORE */ + case 0x22c: /* CM_IDLEST4_CORE */ + case 0x2c8: /* PM_WKDEP_CORE */ + case 0x2e4: /* PM_PWSTST_CORE */ + case 0x320: /* CM_IDLEST_GFX */ + case 0x3e4: /* PM_PWSTST_GFX */ + case 0x420: /* CM_IDLEST_WKUP */ + case 0x520: /* CM_IDLEST_CKGEN */ + case 0x820: /* CM_IDLEST_DSP */ + case 0x8e4: /* PM_PWSTST_DSP */ + OMAP_RO_REG(addr); + return; + + case 0x010: /* PRCM_SYSCONFIG */ + s->sysconfig = value & 1; + break; + + case 0x018: /* PRCM_IRQSTATUS_MPU */ + s->irqst[0] &= ~value; + omap_prcm_int_update(s, 0); + break; + case 0x01c: /* PRCM_IRQENABLE_MPU */ + s->irqen[0] = value & 0x3f; + omap_prcm_int_update(s, 0); + break; + + case 0x050: /* PRCM_VOLTCTRL */ + s->voltctrl = value & 0xf1c3; + break; + + case 0x060: /* PRCM_CLKSRC_CTRL */ + s->clksrc[0] = value & 0xdb; + /* TODO update clocks */ + break; + + case 0x070: /* PRCM_CLKOUT_CTRL */ + s->clkout[0] = value & 0xbbbb; + /* TODO update clocks */ + break; + + case 0x078: /* PRCM_CLKEMUL_CTRL */ + s->clkemul[0] = value & 1; + /* TODO update clocks */ + break; + + case 0x080: /* PRCM_CLKCFG_CTRL */ + break; + + case 0x090: /* PRCM_VOLTSETUP */ + s->setuptime[0] = value & 0xffff; + break; + case 0x094: /* PRCM_CLKSSETUP */ + s->setuptime[1] = value & 0xffff; + break; + + case 0x098: /* PRCM_POLCTRL */ + s->clkpol[0] = value & 0x701; + break; + + case 0x0b0: /* GENERAL_PURPOSE1 */ + case 0x0b4: /* GENERAL_PURPOSE2 */ + case 0x0b8: /* GENERAL_PURPOSE3 */ + case 0x0bc: /* GENERAL_PURPOSE4 */ + case 0x0c0: /* GENERAL_PURPOSE5 */ + case 0x0c4: /* GENERAL_PURPOSE6 */ + case 0x0c8: /* GENERAL_PURPOSE7 */ + case 0x0cc: /* GENERAL_PURPOSE8 */ + case 0x0d0: /* GENERAL_PURPOSE9 */ + case 0x0d4: /* GENERAL_PURPOSE10 */ + case 0x0d8: /* GENERAL_PURPOSE11 */ + case 0x0dc: /* GENERAL_PURPOSE12 */ + case 0x0e0: /* GENERAL_PURPOSE13 */ + case 0x0e4: /* GENERAL_PURPOSE14 */ + case 0x0e8: /* GENERAL_PURPOSE15 */ + case 0x0ec: /* GENERAL_PURPOSE16 */ + case 0x0f0: /* GENERAL_PURPOSE17 */ + case 0x0f4: /* GENERAL_PURPOSE18 */ + case 0x0f8: /* GENERAL_PURPOSE19 */ + case 0x0fc: /* GENERAL_PURPOSE20 */ + s->scratch[(addr - 0xb0) >> 2] = value; + break; + + case 0x140: /* CM_CLKSEL_MPU */ + s->clksel[0] = value & 0x1f; + /* TODO update clocks */ + break; + case 0x148: /* CM_CLKSTCTRL_MPU */ + s->clkctrl[0] = value & 0x1f; + break; + + case 0x158: /* RM_RSTST_MPU */ + s->rst[0] &= ~value; + break; + case 0x1c8: /* PM_WKDEP_MPU */ + s->wkup[0] = value & 0x15; + break; + + case 0x1d4: /* PM_EVGENCTRL_MPU */ + s->ev = value & 0x1f; + break; + case 0x1d8: /* PM_EVEGENONTIM_MPU */ + s->evtime[0] = value; + break; + case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ + s->evtime[1] = value; + break; + + case 0x1e0: /* PM_PWSTCTRL_MPU */ + s->power[0] = value & 0xc0f; + break; + + case 0x200: /* CM_FCLKEN1_CORE */ + s->clken[0] = value & 0xbfffffff; + /* TODO update clocks */ + /* The EN_EAC bit only gets/puts func_96m_clk. */ + break; + case 0x204: /* CM_FCLKEN2_CORE */ + s->clken[1] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x210: /* CM_ICLKEN1_CORE */ + s->clken[2] = value & 0xfffffff9; + /* TODO update clocks */ + /* The EN_EAC bit only gets/puts core_l4_iclk. */ + break; + case 0x214: /* CM_ICLKEN2_CORE */ + s->clken[3] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x21c: /* CM_ICLKEN4_CORE */ + s->clken[4] = value & 0x0000001f; + /* TODO update clocks */ + break; + + case 0x230: /* CM_AUTOIDLE1_CORE */ + s->clkidle[0] = value & 0xfffffff9; + /* TODO update clocks */ + break; + case 0x234: /* CM_AUTOIDLE2_CORE */ + s->clkidle[1] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x238: /* CM_AUTOIDLE3_CORE */ + s->clkidle[2] = value & 0x00000007; + /* TODO update clocks */ + break; + case 0x23c: /* CM_AUTOIDLE4_CORE */ + s->clkidle[3] = value & 0x0000001f; + /* TODO update clocks */ + break; + + case 0x240: /* CM_CLKSEL1_CORE */ + s->clksel[1] = value & 0x0fffbf7f; + /* TODO update clocks */ + break; + + case 0x244: /* CM_CLKSEL2_CORE */ + s->clksel[2] = value & 0x00fffffc; + /* TODO update clocks */ + break; + + case 0x248: /* CM_CLKSTCTRL_CORE */ + s->clkctrl[1] = value & 0x7; + break; + + case 0x2a0: /* PM_WKEN1_CORE */ + s->wken[0] = value & 0x04667ff8; + break; + case 0x2a4: /* PM_WKEN2_CORE */ + s->wken[1] = value & 0x00000005; + break; + + case 0x2b0: /* PM_WKST1_CORE */ + s->wkst[0] &= ~value; + break; + case 0x2b4: /* PM_WKST2_CORE */ + s->wkst[1] &= ~value; + break; + + case 0x2e0: /* PM_PWSTCTRL_CORE */ + s->power[1] = (value & 0x00fc3f) | (1 << 2); + break; + + case 0x300: /* CM_FCLKEN_GFX */ + s->clken[5] = value & 6; + /* TODO update clocks */ + break; + case 0x310: /* CM_ICLKEN_GFX */ + s->clken[6] = value & 1; + /* TODO update clocks */ + break; + case 0x340: /* CM_CLKSEL_GFX */ + s->clksel[3] = value & 7; + /* TODO update clocks */ + break; + case 0x348: /* CM_CLKSTCTRL_GFX */ + s->clkctrl[2] = value & 1; + break; + case 0x350: /* RM_RSTCTRL_GFX */ + s->rstctrl[0] = value & 1; + /* TODO: reset */ + break; + case 0x358: /* RM_RSTST_GFX */ + s->rst[1] &= ~value; + break; + case 0x3c8: /* PM_WKDEP_GFX */ + s->wkup[1] = value & 0x13; + break; + case 0x3e0: /* PM_PWSTCTRL_GFX */ + s->power[2] = (value & 0x00c0f) | (3 << 2); + break; + + case 0x400: /* CM_FCLKEN_WKUP */ + s->clken[7] = value & 0xd; + /* TODO update clocks */ + break; + case 0x410: /* CM_ICLKEN_WKUP */ + s->clken[8] = value & 0x3f; + /* TODO update clocks */ + break; + case 0x430: /* CM_AUTOIDLE_WKUP */ + s->clkidle[4] = value & 0x0000003f; + /* TODO update clocks */ + break; + case 0x440: /* CM_CLKSEL_WKUP */ + s->clksel[4] = value & 3; + /* TODO update clocks */ + break; + case 0x450: /* RM_RSTCTRL_WKUP */ + /* TODO: reset */ + if (value & 2) + qemu_system_reset_request(); + break; + case 0x454: /* RM_RSTTIME_WKUP */ + s->rsttime_wkup = value & 0x1fff; + break; + case 0x458: /* RM_RSTST_WKUP */ + s->rst[2] &= ~value; + break; + case 0x4a0: /* PM_WKEN_WKUP */ + s->wken[2] = value & 0x00000005; + break; + case 0x4b0: /* PM_WKST_WKUP */ + s->wkst[2] &= ~value; + break; + + case 0x500: /* CM_CLKEN_PLL */ + if (value & 0xffffff30) + fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for " + "future compatibility\n", __FUNCTION__); + if ((s->clken[9] ^ value) & 0xcc) { + s->clken[9] &= ~0xcc; + s->clken[9] |= value & 0xcc; + omap_prcm_apll_update(s); + } + if ((s->clken[9] ^ value) & 3) { + s->clken[9] &= ~3; + s->clken[9] |= value & 3; + omap_prcm_dpll_update(s); + } + break; + case 0x530: /* CM_AUTOIDLE_PLL */ + s->clkidle[5] = value & 0x000000cf; + /* TODO update clocks */ + break; + case 0x540: /* CM_CLKSEL1_PLL */ + if (value & 0xfc4000d7) + fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for " + "future compatibility\n", __FUNCTION__); + if ((s->clksel[5] ^ value) & 0x003fff00) { + s->clksel[5] = value & 0x03bfff28; + omap_prcm_dpll_update(s); + } + /* TODO update the other clocks */ + + s->clksel[5] = value & 0x03bfff28; + break; + case 0x544: /* CM_CLKSEL2_PLL */ + if (value & ~3) + fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for " + "future compatibility\n", __FUNCTION__); + if (s->clksel[6] != (value & 3)) { + s->clksel[6] = value & 3; + omap_prcm_dpll_update(s); + } + break; + + case 0x800: /* CM_FCLKEN_DSP */ + s->clken[10] = value & 0x501; + /* TODO update clocks */ + break; + case 0x810: /* CM_ICLKEN_DSP */ + s->clken[11] = value & 0x2; + /* TODO update clocks */ + break; + case 0x830: /* CM_AUTOIDLE_DSP */ + s->clkidle[6] = value & 0x2; + /* TODO update clocks */ + break; + case 0x840: /* CM_CLKSEL_DSP */ + s->clksel[7] = value & 0x3fff; + /* TODO update clocks */ + break; + case 0x848: /* CM_CLKSTCTRL_DSP */ + s->clkctrl[3] = value & 0x101; + break; + case 0x850: /* RM_RSTCTRL_DSP */ + /* TODO: reset */ + break; + case 0x858: /* RM_RSTST_DSP */ + s->rst[3] &= ~value; + break; + case 0x8c8: /* PM_WKDEP_DSP */ + s->wkup[2] = value & 0x13; + break; + case 0x8e0: /* PM_PWSTCTRL_DSP */ + s->power[3] = (value & 0x03017) | (3 << 2); + break; + + case 0x8f0: /* PRCM_IRQSTATUS_DSP */ + s->irqst[1] &= ~value; + omap_prcm_int_update(s, 1); + break; + case 0x8f4: /* PRCM_IRQENABLE_DSP */ + s->irqen[1] = value & 0x7; + omap_prcm_int_update(s, 1); + break; + + case 0x8f8: /* PRCM_IRQSTATUS_IVA */ + s->irqst[2] &= ~value; + omap_prcm_int_update(s, 2); + break; + case 0x8fc: /* PRCM_IRQENABLE_IVA */ + s->irqen[2] = value & 0x7; + omap_prcm_int_update(s, 2); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_prcm_ops = { + .read = omap_prcm_read, + .write = omap_prcm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_prcm_reset(struct omap_prcm_s *s) +{ + s->sysconfig = 0; + s->irqst[0] = 0; + s->irqst[1] = 0; + s->irqst[2] = 0; + s->irqen[0] = 0; + s->irqen[1] = 0; + s->irqen[2] = 0; + s->voltctrl = 0x1040; + s->ev = 0x14; + s->evtime[0] = 0; + s->evtime[1] = 0; + s->clkctrl[0] = 0; + s->clkctrl[1] = 0; + s->clkctrl[2] = 0; + s->clkctrl[3] = 0; + s->clken[1] = 7; + s->clken[3] = 7; + s->clken[4] = 0; + s->clken[5] = 0; + s->clken[6] = 0; + s->clken[7] = 0xc; + s->clken[8] = 0x3e; + s->clken[9] = 0x0d; + s->clken[10] = 0; + s->clken[11] = 0; + s->clkidle[0] = 0; + s->clkidle[2] = 7; + s->clkidle[3] = 0; + s->clkidle[4] = 0; + s->clkidle[5] = 0x0c; + s->clkidle[6] = 0; + s->clksel[0] = 0x01; + s->clksel[1] = 0x02100121; + s->clksel[2] = 0x00000000; + s->clksel[3] = 0x01; + s->clksel[4] = 0; + s->clksel[7] = 0x0121; + s->wkup[0] = 0x15; + s->wkup[1] = 0x13; + s->wkup[2] = 0x13; + s->wken[0] = 0x04667ff8; + s->wken[1] = 0x00000005; + s->wken[2] = 5; + s->wkst[0] = 0; + s->wkst[1] = 0; + s->wkst[2] = 0; + s->power[0] = 0x00c; + s->power[1] = 4; + s->power[2] = 0x0000c; + s->power[3] = 0x14; + s->rstctrl[0] = 1; + s->rst[3] = 1; + omap_prcm_apll_update(s); + omap_prcm_dpll_update(s); +} + +static void omap_prcm_coldreset(struct omap_prcm_s *s) +{ + s->setuptime[0] = 0; + s->setuptime[1] = 0; + memset(&s->scratch, 0, sizeof(s->scratch)); + s->rst[0] = 0x01; + s->rst[1] = 0x00; + s->rst[2] = 0x01; + s->clken[0] = 0; + s->clken[2] = 0; + s->clkidle[1] = 0; + s->clksel[5] = 0; + s->clksel[6] = 2; + s->clksrc[0] = 0x43; + s->clkout[0] = 0x0303; + s->clkemul[0] = 0; + s->clkpol[0] = 0x100; + s->rsttime_wkup = 0x1002; + + omap_prcm_reset(s); +} + +static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, + qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, + struct omap_mpu_state_s *mpu) +{ + struct omap_prcm_s *s = (struct omap_prcm_s *) + g_malloc0(sizeof(struct omap_prcm_s)); + + s->irq[0] = mpu_int; + s->irq[1] = dsp_int; + s->irq[2] = iva_int; + s->mpu = mpu; + omap_prcm_coldreset(s); + + memory_region_init_io(&s->iomem0, &omap_prcm_ops, s, "omap.pcrm0", + omap_l4_region_size(ta, 0)); + memory_region_init_io(&s->iomem1, &omap_prcm_ops, s, "omap.pcrm1", + omap_l4_region_size(ta, 1)); + omap_l4_attach(ta, 0, &s->iomem0); + omap_l4_attach(ta, 1, &s->iomem1); + + return s; +} + +/* System and Pinout control */ +struct omap_sysctl_s { + struct omap_mpu_state_s *mpu; + MemoryRegion iomem; + + uint32_t sysconfig; + uint32_t devconfig; + uint32_t psaconfig; + uint32_t padconf[0x45]; + uint8_t obs; + uint32_t msuspendmux[5]; +}; + +static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr) +{ + + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + int pad_offset, byte_offset; + int value; + + switch (addr) { + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + pad_offset = (addr - 0x30) >> 2; + byte_offset = (addr - 0x30) & (4 - 1); + + value = s->padconf[pad_offset]; + value = (value >> (byte_offset * 8)) & 0xff; + + return value; + + default: + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static uint32_t omap_sysctl_read(void *opaque, hwaddr addr) +{ + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + + switch (addr) { + case 0x000: /* CONTROL_REVISION */ + return 0x20; + + case 0x010: /* CONTROL_SYSCONFIG */ + return s->sysconfig; + + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + return s->padconf[(addr - 0x30) >> 2]; + + case 0x270: /* CONTROL_DEBOBS */ + return s->obs; + + case 0x274: /* CONTROL_DEVCONF */ + return s->devconfig; + + case 0x28c: /* CONTROL_EMU_SUPPORT */ + return 0; + + case 0x290: /* CONTROL_MSUSPENDMUX_0 */ + return s->msuspendmux[0]; + case 0x294: /* CONTROL_MSUSPENDMUX_1 */ + return s->msuspendmux[1]; + case 0x298: /* CONTROL_MSUSPENDMUX_2 */ + return s->msuspendmux[2]; + case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ + return s->msuspendmux[3]; + case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ + return s->msuspendmux[4]; + case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ + return 0; + + case 0x2b8: /* CONTROL_PSA_CTRL */ + return s->psaconfig; + case 0x2bc: /* CONTROL_PSA_CMD */ + case 0x2c0: /* CONTROL_PSA_VALUE */ + return 0; + + case 0x2b0: /* CONTROL_SEC_CTRL */ + return 0x800000f1; + case 0x2d0: /* CONTROL_SEC_EMU */ + return 0x80000015; + case 0x2d4: /* CONTROL_SEC_TAP */ + return 0x8000007f; + case 0x2b4: /* CONTROL_SEC_TEST */ + case 0x2f0: /* CONTROL_SEC_STATUS */ + case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ + /* Secure mode is not present on general-pusrpose device. Outside + * secure mode these values cannot be read or written. */ + return 0; + + case 0x2d8: /* CONTROL_OCM_RAM_PERM */ + return 0xff; + case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ + case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ + case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ + /* No secure mode so no Extended Secure RAM present. */ + return 0; + + case 0x2f8: /* CONTROL_STATUS */ + /* Device Type => General-purpose */ + return 0x0300; + case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ + + case 0x300: /* CONTROL_RPUB_KEY_H_0 */ + case 0x304: /* CONTROL_RPUB_KEY_H_1 */ + case 0x308: /* CONTROL_RPUB_KEY_H_2 */ + case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ + return 0xdecafbad; + + case 0x310: /* CONTROL_RAND_KEY_0 */ + case 0x314: /* CONTROL_RAND_KEY_1 */ + case 0x318: /* CONTROL_RAND_KEY_2 */ + case 0x31c: /* CONTROL_RAND_KEY_3 */ + case 0x320: /* CONTROL_CUST_KEY_0 */ + case 0x324: /* CONTROL_CUST_KEY_1 */ + case 0x330: /* CONTROL_TEST_KEY_0 */ + case 0x334: /* CONTROL_TEST_KEY_1 */ + case 0x338: /* CONTROL_TEST_KEY_2 */ + case 0x33c: /* CONTROL_TEST_KEY_3 */ + case 0x340: /* CONTROL_TEST_KEY_4 */ + case 0x344: /* CONTROL_TEST_KEY_5 */ + case 0x348: /* CONTROL_TEST_KEY_6 */ + case 0x34c: /* CONTROL_TEST_KEY_7 */ + case 0x350: /* CONTROL_TEST_KEY_8 */ + case 0x354: /* CONTROL_TEST_KEY_9 */ + /* Can only be accessed in secure mode and when C_FieldAccEnable + * bit is set in CONTROL_SEC_CTRL. + * TODO: otherwise an interconnect access error is generated. */ + return 0; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sysctl_write8(void *opaque, hwaddr addr, + uint32_t value) +{ + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + int pad_offset, byte_offset; + int prev_value; + + switch (addr) { + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + pad_offset = (addr - 0x30) >> 2; + byte_offset = (addr - 0x30) & (4 - 1); + + prev_value = s->padconf[pad_offset]; + prev_value &= ~(0xff << (byte_offset * 8)); + prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f; + s->padconf[pad_offset] = prev_value; + break; + + default: + OMAP_BAD_REG(addr); + break; + } +} + +static void omap_sysctl_write(void *opaque, hwaddr addr, + uint32_t value) +{ + struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + + switch (addr) { + case 0x000: /* CONTROL_REVISION */ + case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ + case 0x2c0: /* CONTROL_PSA_VALUE */ + case 0x2f8: /* CONTROL_STATUS */ + case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ + case 0x300: /* CONTROL_RPUB_KEY_H_0 */ + case 0x304: /* CONTROL_RPUB_KEY_H_1 */ + case 0x308: /* CONTROL_RPUB_KEY_H_2 */ + case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ + case 0x310: /* CONTROL_RAND_KEY_0 */ + case 0x314: /* CONTROL_RAND_KEY_1 */ + case 0x318: /* CONTROL_RAND_KEY_2 */ + case 0x31c: /* CONTROL_RAND_KEY_3 */ + case 0x320: /* CONTROL_CUST_KEY_0 */ + case 0x324: /* CONTROL_CUST_KEY_1 */ + case 0x330: /* CONTROL_TEST_KEY_0 */ + case 0x334: /* CONTROL_TEST_KEY_1 */ + case 0x338: /* CONTROL_TEST_KEY_2 */ + case 0x33c: /* CONTROL_TEST_KEY_3 */ + case 0x340: /* CONTROL_TEST_KEY_4 */ + case 0x344: /* CONTROL_TEST_KEY_5 */ + case 0x348: /* CONTROL_TEST_KEY_6 */ + case 0x34c: /* CONTROL_TEST_KEY_7 */ + case 0x350: /* CONTROL_TEST_KEY_8 */ + case 0x354: /* CONTROL_TEST_KEY_9 */ + OMAP_RO_REG(addr); + return; + + case 0x010: /* CONTROL_SYSCONFIG */ + s->sysconfig = value & 0x1e; + break; + + case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ + /* XXX: should check constant bits */ + s->padconf[(addr - 0x30) >> 2] = value & 0x1f1f1f1f; + break; + + case 0x270: /* CONTROL_DEBOBS */ + s->obs = value & 0xff; + break; + + case 0x274: /* CONTROL_DEVCONF */ + s->devconfig = value & 0xffffc7ff; + break; + + case 0x28c: /* CONTROL_EMU_SUPPORT */ + break; + + case 0x290: /* CONTROL_MSUSPENDMUX_0 */ + s->msuspendmux[0] = value & 0x3fffffff; + break; + case 0x294: /* CONTROL_MSUSPENDMUX_1 */ + s->msuspendmux[1] = value & 0x3fffffff; + break; + case 0x298: /* CONTROL_MSUSPENDMUX_2 */ + s->msuspendmux[2] = value & 0x3fffffff; + break; + case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ + s->msuspendmux[3] = value & 0x3fffffff; + break; + case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ + s->msuspendmux[4] = value & 0x3fffffff; + break; + + case 0x2b8: /* CONTROL_PSA_CTRL */ + s->psaconfig = value & 0x1c; + s->psaconfig |= (value & 0x20) ? 2 : 1; + break; + case 0x2bc: /* CONTROL_PSA_CMD */ + break; + + case 0x2b0: /* CONTROL_SEC_CTRL */ + case 0x2b4: /* CONTROL_SEC_TEST */ + case 0x2d0: /* CONTROL_SEC_EMU */ + case 0x2d4: /* CONTROL_SEC_TAP */ + case 0x2d8: /* CONTROL_OCM_RAM_PERM */ + case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ + case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ + case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ + case 0x2f0: /* CONTROL_SEC_STATUS */ + case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_sysctl_ops = { + .old_mmio = { + .read = { + omap_sysctl_read8, + omap_badwidth_read32, /* TODO */ + omap_sysctl_read, + }, + .write = { + omap_sysctl_write8, + omap_badwidth_write32, /* TODO */ + omap_sysctl_write, + }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void omap_sysctl_reset(struct omap_sysctl_s *s) +{ + /* (power-on reset) */ + s->sysconfig = 0; + s->obs = 0; + s->devconfig = 0x0c000000; + s->msuspendmux[0] = 0x00000000; + s->msuspendmux[1] = 0x00000000; + s->msuspendmux[2] = 0x00000000; + s->msuspendmux[3] = 0x00000000; + s->msuspendmux[4] = 0x00000000; + s->psaconfig = 1; + + s->padconf[0x00] = 0x000f0f0f; + s->padconf[0x01] = 0x00000000; + s->padconf[0x02] = 0x00000000; + s->padconf[0x03] = 0x00000000; + s->padconf[0x04] = 0x00000000; + s->padconf[0x05] = 0x00000000; + s->padconf[0x06] = 0x00000000; + s->padconf[0x07] = 0x00000000; + s->padconf[0x08] = 0x08080800; + s->padconf[0x09] = 0x08080808; + s->padconf[0x0a] = 0x08080808; + s->padconf[0x0b] = 0x08080808; + s->padconf[0x0c] = 0x08080808; + s->padconf[0x0d] = 0x08080800; + s->padconf[0x0e] = 0x08080808; + s->padconf[0x0f] = 0x08080808; + s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */ + s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */ + s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */ + s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */ + s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */ + s->padconf[0x15] = 0x18181818; + s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */ + s->padconf[0x17] = 0x1f001f00; + s->padconf[0x18] = 0x1f1f1f1f; + s->padconf[0x19] = 0x00000000; + s->padconf[0x1a] = 0x1f180000; + s->padconf[0x1b] = 0x00001f1f; + s->padconf[0x1c] = 0x1f001f00; + s->padconf[0x1d] = 0x00000000; + s->padconf[0x1e] = 0x00000000; + s->padconf[0x1f] = 0x08000000; + s->padconf[0x20] = 0x08080808; + s->padconf[0x21] = 0x08080808; + s->padconf[0x22] = 0x0f080808; + s->padconf[0x23] = 0x0f0f0f0f; + s->padconf[0x24] = 0x000f0f0f; + s->padconf[0x25] = 0x1f1f1f0f; + s->padconf[0x26] = 0x080f0f1f; + s->padconf[0x27] = 0x070f1808; + s->padconf[0x28] = 0x0f070707; + s->padconf[0x29] = 0x000f0f1f; + s->padconf[0x2a] = 0x0f0f0f1f; + s->padconf[0x2b] = 0x08000000; + s->padconf[0x2c] = 0x0000001f; + s->padconf[0x2d] = 0x0f0f1f00; + s->padconf[0x2e] = 0x1f1f0f0f; + s->padconf[0x2f] = 0x0f1f1f1f; + s->padconf[0x30] = 0x0f0f0f0f; + s->padconf[0x31] = 0x0f1f0f1f; + s->padconf[0x32] = 0x0f0f0f0f; + s->padconf[0x33] = 0x0f1f0f1f; + s->padconf[0x34] = 0x1f1f0f0f; + s->padconf[0x35] = 0x0f0f1f1f; + s->padconf[0x36] = 0x0f0f1f0f; + s->padconf[0x37] = 0x0f0f0f0f; + s->padconf[0x38] = 0x1f18180f; + s->padconf[0x39] = 0x1f1f1f1f; + s->padconf[0x3a] = 0x00001f1f; + s->padconf[0x3b] = 0x00000000; + s->padconf[0x3c] = 0x00000000; + s->padconf[0x3d] = 0x0f0f0f0f; + s->padconf[0x3e] = 0x18000f0f; + s->padconf[0x3f] = 0x00070000; + s->padconf[0x40] = 0x00000707; + s->padconf[0x41] = 0x0f1f0700; + s->padconf[0x42] = 0x1f1f070f; + s->padconf[0x43] = 0x0008081f; + s->padconf[0x44] = 0x00000800; +} + +static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, + omap_clk iclk, struct omap_mpu_state_s *mpu) +{ + struct omap_sysctl_s *s = (struct omap_sysctl_s *) + g_malloc0(sizeof(struct omap_sysctl_s)); + + s->mpu = mpu; + omap_sysctl_reset(s); + + memory_region_init_io(&s->iomem, &omap_sysctl_ops, s, "omap.sysctl", + omap_l4_region_size(ta, 0)); + omap_l4_attach(ta, 0, &s->iomem); + + return s; +} + +/* General chip reset */ +static void omap2_mpu_reset(void *opaque) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + omap_dma_reset(mpu->dma); + omap_prcm_reset(mpu->prcm); + omap_sysctl_reset(mpu->sysc); + omap_gp_timer_reset(mpu->gptimer[0]); + omap_gp_timer_reset(mpu->gptimer[1]); + omap_gp_timer_reset(mpu->gptimer[2]); + omap_gp_timer_reset(mpu->gptimer[3]); + omap_gp_timer_reset(mpu->gptimer[4]); + omap_gp_timer_reset(mpu->gptimer[5]); + omap_gp_timer_reset(mpu->gptimer[6]); + omap_gp_timer_reset(mpu->gptimer[7]); + omap_gp_timer_reset(mpu->gptimer[8]); + omap_gp_timer_reset(mpu->gptimer[9]); + omap_gp_timer_reset(mpu->gptimer[10]); + omap_gp_timer_reset(mpu->gptimer[11]); + omap_synctimer_reset(mpu->synctimer); + omap_sdrc_reset(mpu->sdrc); + omap_gpmc_reset(mpu->gpmc); + omap_dss_reset(mpu->dss); + omap_uart_reset(mpu->uart[0]); + omap_uart_reset(mpu->uart[1]); + omap_uart_reset(mpu->uart[2]); + omap_mmc_reset(mpu->mmc); + omap_mcspi_reset(mpu->mcspi[0]); + omap_mcspi_reset(mpu->mcspi[1]); + cpu_reset(CPU(mpu->cpu)); +} + +static int omap2_validate_addr(struct omap_mpu_state_s *s, + hwaddr addr) +{ + return 1; +} + +static const struct dma_irq_map omap2_dma_irq_map[] = { + { 0, OMAP_INT_24XX_SDMA_IRQ0 }, + { 0, OMAP_INT_24XX_SDMA_IRQ1 }, + { 0, OMAP_INT_24XX_SDMA_IRQ2 }, + { 0, OMAP_INT_24XX_SDMA_IRQ3 }, +}; + +struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, + unsigned long sdram_size, + const char *core) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) + g_malloc0(sizeof(struct omap_mpu_state_s)); + qemu_irq *cpu_irq; + qemu_irq dma_irqs[4]; + DriveInfo *dinfo; + int i; + SysBusDevice *busdev; + struct omap_target_agent_s *ta; + + /* Core */ + s->mpu_model = omap2420; + s->cpu = cpu_arm_init(core ?: "arm1136-r2"); + if (s->cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + s->sdram_size = sdram_size; + s->sram_size = OMAP242X_SRAM_SIZE; + + s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + + /* Clocks */ + omap_clk_init(s); + + /* Memory-mapped stuff */ + memory_region_init_ram(&s->sdram, "omap2.dram", s->sdram_size); + vmstate_register_ram_global(&s->sdram); + memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram); + memory_region_init_ram(&s->sram, "omap2.sram", s->sram_size); + vmstate_register_ram_global(&s->sram); + memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram); + + s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54); + + /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ + cpu_irq = arm_pic_init_cpu(s->cpu); + s->ih[0] = qdev_create(NULL, "omap2-intc"); + qdev_prop_set_uint8(s->ih[0], "revision", 0x21); + qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk")); + qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk")); + qdev_init_nofail(s->ih[0]); + busdev = SYS_BUS_DEVICE(s->ih[0]); + sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); + sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); + sysbus_mmio_map(busdev, 0, 0x480fe000); + s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3), + qdev_get_gpio_in(s->ih[0], + OMAP_INT_24XX_PRCM_MPU_IRQ), + NULL, NULL, s); + + s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1), + omap_findclk(s, "omapctrl_iclk"), s); + + for (i = 0; i < 4; i++) { + dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih], + omap2_dma_irq_map[i].intr); + } + s->dma = omap_dma4_init(0x48056000, dma_irqs, sysmem, s, 256, 32, + omap_findclk(s, "sdma_iclk"), + omap_findclk(s, "sdma_fclk")); + s->port->addr_valid = omap2_validate_addr; + + /* Register SDRAM and SRAM ports for fast DMA transfers. */ + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sdram), + OMAP2_Q2_BASE, s->sdram_size); + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram), + OMAP2_SRAM_BASE, s->sram_size); + + s->uart[0] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 19), + qdev_get_gpio_in(s->ih[0], + OMAP_INT_24XX_UART1_IRQ), + omap_findclk(s, "uart1_fclk"), + omap_findclk(s, "uart1_iclk"), + s->drq[OMAP24XX_DMA_UART1_TX], + s->drq[OMAP24XX_DMA_UART1_RX], + "uart1", + serial_hds[0]); + s->uart[1] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 20), + qdev_get_gpio_in(s->ih[0], + OMAP_INT_24XX_UART2_IRQ), + omap_findclk(s, "uart2_fclk"), + omap_findclk(s, "uart2_iclk"), + s->drq[OMAP24XX_DMA_UART2_TX], + s->drq[OMAP24XX_DMA_UART2_RX], + "uart2", + serial_hds[0] ? serial_hds[1] : NULL); + s->uart[2] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 21), + qdev_get_gpio_in(s->ih[0], + OMAP_INT_24XX_UART3_IRQ), + omap_findclk(s, "uart3_fclk"), + omap_findclk(s, "uart3_iclk"), + s->drq[OMAP24XX_DMA_UART3_TX], + s->drq[OMAP24XX_DMA_UART3_RX], + "uart3", + serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL); + + s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1), + omap_findclk(s, "wu_gpt1_clk"), + omap_findclk(s, "wu_l4_iclk")); + s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2), + omap_findclk(s, "core_gpt2_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3), + omap_findclk(s, "core_gpt3_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4), + omap_findclk(s, "core_gpt4_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5), + omap_findclk(s, "core_gpt5_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6), + omap_findclk(s, "core_gpt6_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7), + omap_findclk(s, "core_gpt7_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8), + omap_findclk(s, "core_gpt8_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9), + omap_findclk(s, "core_gpt9_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10), + omap_findclk(s, "core_gpt10_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11), + omap_findclk(s, "core_gpt11_clk"), + omap_findclk(s, "core_l4_iclk")); + s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12), + omap_findclk(s, "core_gpt12_clk"), + omap_findclk(s, "core_l4_iclk")); + + omap_tap_init(omap_l4ta(s->l4, 2), s); + + s->synctimer = omap_synctimer_init(omap_l4tao(s->l4, 2), s, + omap_findclk(s, "clk32-kHz"), + omap_findclk(s, "core_l4_iclk")); + + s->i2c[0] = qdev_create(NULL, "omap_i2c"); + qdev_prop_set_uint8(s->i2c[0], "revision", 0x34); + qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk")); + qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk")); + qdev_init_nofail(s->i2c[0]); + busdev = SYS_BUS_DEVICE(s->i2c[0]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ)); + sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]); + sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]); + sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0)); + + s->i2c[1] = qdev_create(NULL, "omap_i2c"); + qdev_prop_set_uint8(s->i2c[1], "revision", 0x34); + qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk")); + qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk")); + qdev_init_nofail(s->i2c[1]); + busdev = SYS_BUS_DEVICE(s->i2c[1]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ)); + sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]); + sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]); + sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0)); + + s->gpio = qdev_create(NULL, "omap2-gpio"); + qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); + qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk")); + qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk")); + qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk")); + qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk")); + qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk")); + if (s->mpu_model == omap2430) { + qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk")); + } + qdev_init_nofail(s->gpio); + busdev = SYS_BUS_DEVICE(s->gpio); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1)); + sysbus_connect_irq(busdev, 3, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2)); + sysbus_connect_irq(busdev, 6, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3)); + sysbus_connect_irq(busdev, 9, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4)); + if (s->mpu_model == omap2430) { + sysbus_connect_irq(busdev, 12, + qdev_get_gpio_in(s->ih[0], + OMAP_INT_243X_GPIO_BANK5)); + } + ta = omap_l4ta(s->l4, 3); + sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1)); + sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0)); + sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2)); + sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4)); + sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5)); + + s->sdrc = omap_sdrc_init(sysmem, 0x68009000); + s->gpmc = omap_gpmc_init(s, 0x6800a000, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ), + s->drq[OMAP24XX_DMA_GPMC]); + + dinfo = drive_get(IF_SD, 0, 0); + if (!dinfo) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ), + &s->drq[OMAP24XX_DMA_MMC1_TX], + omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); + + s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ), + &s->drq[OMAP24XX_DMA_SPI1_TX0], + omap_findclk(s, "spi1_fclk"), + omap_findclk(s, "spi1_iclk")); + s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ), + &s->drq[OMAP24XX_DMA_SPI2_TX0], + omap_findclk(s, "spi2_fclk"), + omap_findclk(s, "spi2_iclk")); + + s->dss = omap_dss_init(omap_l4ta(s->l4, 10), sysmem, 0x68000800, + /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */ + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ), + s->drq[OMAP24XX_DMA_DSS], + omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"), + omap_findclk(s, "dss_54m_clk"), + omap_findclk(s, "dss_l3_iclk"), + omap_findclk(s, "dss_l4_iclk")); + + omap_sti_init(omap_l4ta(s->l4, 18), sysmem, 0x54000000, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI), + omap_findclk(s, "emul_ck"), + serial_hds[0] && serial_hds[1] && serial_hds[2] ? + serial_hds[3] : NULL); + + s->eac = omap_eac_init(omap_l4ta(s->l4, 32), + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ), + /* Ten consecutive lines */ + &s->drq[OMAP24XX_DMA_EAC_AC_RD], + omap_findclk(s, "func_96m_clk"), + omap_findclk(s, "core_l4_iclk")); + + /* All register mappings (includin those not currenlty implemented): + * SystemControlMod 48000000 - 48000fff + * SystemControlL4 48001000 - 48001fff + * 32kHz Timer Mod 48004000 - 48004fff + * 32kHz Timer L4 48005000 - 48005fff + * PRCM ModA 48008000 - 480087ff + * PRCM ModB 48008800 - 48008fff + * PRCM L4 48009000 - 48009fff + * TEST-BCM Mod 48012000 - 48012fff + * TEST-BCM L4 48013000 - 48013fff + * TEST-TAP Mod 48014000 - 48014fff + * TEST-TAP L4 48015000 - 48015fff + * GPIO1 Mod 48018000 - 48018fff + * GPIO Top 48019000 - 48019fff + * GPIO2 Mod 4801a000 - 4801afff + * GPIO L4 4801b000 - 4801bfff + * GPIO3 Mod 4801c000 - 4801cfff + * GPIO4 Mod 4801e000 - 4801efff + * WDTIMER1 Mod 48020000 - 48010fff + * WDTIMER Top 48021000 - 48011fff + * WDTIMER2 Mod 48022000 - 48012fff + * WDTIMER L4 48023000 - 48013fff + * WDTIMER3 Mod 48024000 - 48014fff + * WDTIMER3 L4 48025000 - 48015fff + * WDTIMER4 Mod 48026000 - 48016fff + * WDTIMER4 L4 48027000 - 48017fff + * GPTIMER1 Mod 48028000 - 48018fff + * GPTIMER1 L4 48029000 - 48019fff + * GPTIMER2 Mod 4802a000 - 4801afff + * GPTIMER2 L4 4802b000 - 4801bfff + * L4-Config AP 48040000 - 480407ff + * L4-Config IP 48040800 - 48040fff + * L4-Config LA 48041000 - 48041fff + * ARM11ETB Mod 48048000 - 48049fff + * ARM11ETB L4 4804a000 - 4804afff + * DISPLAY Top 48050000 - 480503ff + * DISPLAY DISPC 48050400 - 480507ff + * DISPLAY RFBI 48050800 - 48050bff + * DISPLAY VENC 48050c00 - 48050fff + * DISPLAY L4 48051000 - 48051fff + * CAMERA Top 48052000 - 480523ff + * CAMERA core 48052400 - 480527ff + * CAMERA DMA 48052800 - 48052bff + * CAMERA MMU 48052c00 - 48052fff + * CAMERA L4 48053000 - 48053fff + * SDMA Mod 48056000 - 48056fff + * SDMA L4 48057000 - 48057fff + * SSI Top 48058000 - 48058fff + * SSI GDD 48059000 - 48059fff + * SSI Port1 4805a000 - 4805afff + * SSI Port2 4805b000 - 4805bfff + * SSI L4 4805c000 - 4805cfff + * USB Mod 4805e000 - 480fefff + * USB L4 4805f000 - 480fffff + * WIN_TRACER1 Mod 48060000 - 48060fff + * WIN_TRACER1 L4 48061000 - 48061fff + * WIN_TRACER2 Mod 48062000 - 48062fff + * WIN_TRACER2 L4 48063000 - 48063fff + * WIN_TRACER3 Mod 48064000 - 48064fff + * WIN_TRACER3 L4 48065000 - 48065fff + * WIN_TRACER4 Top 48066000 - 480660ff + * WIN_TRACER4 ETT 48066100 - 480661ff + * WIN_TRACER4 WT 48066200 - 480662ff + * WIN_TRACER4 L4 48067000 - 48067fff + * XTI Mod 48068000 - 48068fff + * XTI L4 48069000 - 48069fff + * UART1 Mod 4806a000 - 4806afff + * UART1 L4 4806b000 - 4806bfff + * UART2 Mod 4806c000 - 4806cfff + * UART2 L4 4806d000 - 4806dfff + * UART3 Mod 4806e000 - 4806efff + * UART3 L4 4806f000 - 4806ffff + * I2C1 Mod 48070000 - 48070fff + * I2C1 L4 48071000 - 48071fff + * I2C2 Mod 48072000 - 48072fff + * I2C2 L4 48073000 - 48073fff + * McBSP1 Mod 48074000 - 48074fff + * McBSP1 L4 48075000 - 48075fff + * McBSP2 Mod 48076000 - 48076fff + * McBSP2 L4 48077000 - 48077fff + * GPTIMER3 Mod 48078000 - 48078fff + * GPTIMER3 L4 48079000 - 48079fff + * GPTIMER4 Mod 4807a000 - 4807afff + * GPTIMER4 L4 4807b000 - 4807bfff + * GPTIMER5 Mod 4807c000 - 4807cfff + * GPTIMER5 L4 4807d000 - 4807dfff + * GPTIMER6 Mod 4807e000 - 4807efff + * GPTIMER6 L4 4807f000 - 4807ffff + * GPTIMER7 Mod 48080000 - 48080fff + * GPTIMER7 L4 48081000 - 48081fff + * GPTIMER8 Mod 48082000 - 48082fff + * GPTIMER8 L4 48083000 - 48083fff + * GPTIMER9 Mod 48084000 - 48084fff + * GPTIMER9 L4 48085000 - 48085fff + * GPTIMER10 Mod 48086000 - 48086fff + * GPTIMER10 L4 48087000 - 48087fff + * GPTIMER11 Mod 48088000 - 48088fff + * GPTIMER11 L4 48089000 - 48089fff + * GPTIMER12 Mod 4808a000 - 4808afff + * GPTIMER12 L4 4808b000 - 4808bfff + * EAC Mod 48090000 - 48090fff + * EAC L4 48091000 - 48091fff + * FAC Mod 48092000 - 48092fff + * FAC L4 48093000 - 48093fff + * MAILBOX Mod 48094000 - 48094fff + * MAILBOX L4 48095000 - 48095fff + * SPI1 Mod 48098000 - 48098fff + * SPI1 L4 48099000 - 48099fff + * SPI2 Mod 4809a000 - 4809afff + * SPI2 L4 4809b000 - 4809bfff + * MMC/SDIO Mod 4809c000 - 4809cfff + * MMC/SDIO L4 4809d000 - 4809dfff + * MS_PRO Mod 4809e000 - 4809efff + * MS_PRO L4 4809f000 - 4809ffff + * RNG Mod 480a0000 - 480a0fff + * RNG L4 480a1000 - 480a1fff + * DES3DES Mod 480a2000 - 480a2fff + * DES3DES L4 480a3000 - 480a3fff + * SHA1MD5 Mod 480a4000 - 480a4fff + * SHA1MD5 L4 480a5000 - 480a5fff + * AES Mod 480a6000 - 480a6fff + * AES L4 480a7000 - 480a7fff + * PKA Mod 480a8000 - 480a9fff + * PKA L4 480aa000 - 480aafff + * MG Mod 480b0000 - 480b0fff + * MG L4 480b1000 - 480b1fff + * HDQ/1-wire Mod 480b2000 - 480b2fff + * HDQ/1-wire L4 480b3000 - 480b3fff + * MPU interrupt 480fe000 - 480fefff + * STI channel base 54000000 - 5400ffff + * IVA RAM 5c000000 - 5c01ffff + * IVA ROM 5c020000 - 5c027fff + * IMG_BUF_A 5c040000 - 5c040fff + * IMG_BUF_B 5c042000 - 5c042fff + * VLCDS 5c048000 - 5c0487ff + * IMX_COEF 5c049000 - 5c04afff + * IMX_CMD 5c051000 - 5c051fff + * VLCDQ 5c053000 - 5c0533ff + * VLCDH 5c054000 - 5c054fff + * SEQ_CMD 5c055000 - 5c055fff + * IMX_REG 5c056000 - 5c0560ff + * VLCD_REG 5c056100 - 5c0561ff + * SEQ_REG 5c056200 - 5c0562ff + * IMG_BUF_REG 5c056300 - 5c0563ff + * SEQIRQ_REG 5c056400 - 5c0564ff + * OCP_REG 5c060000 - 5c060fff + * SYSC_REG 5c070000 - 5c070fff + * MMU_REG 5d000000 - 5d000fff + * sDMA R 68000400 - 680005ff + * sDMA W 68000600 - 680007ff + * Display Control 68000800 - 680009ff + * DSP subsystem 68000a00 - 68000bff + * MPU subsystem 68000c00 - 68000dff + * IVA subsystem 68001000 - 680011ff + * USB 68001200 - 680013ff + * Camera 68001400 - 680015ff + * VLYNQ (firewall) 68001800 - 68001bff + * VLYNQ 68001e00 - 68001fff + * SSI 68002000 - 680021ff + * L4 68002400 - 680025ff + * DSP (firewall) 68002800 - 68002bff + * DSP subsystem 68002e00 - 68002fff + * IVA (firewall) 68003000 - 680033ff + * IVA 68003600 - 680037ff + * GFX 68003a00 - 68003bff + * CMDWR emulation 68003c00 - 68003dff + * SMS 68004000 - 680041ff + * OCM 68004200 - 680043ff + * GPMC 68004400 - 680045ff + * RAM (firewall) 68005000 - 680053ff + * RAM (err login) 68005400 - 680057ff + * ROM (firewall) 68005800 - 68005bff + * ROM (err login) 68005c00 - 68005fff + * GPMC (firewall) 68006000 - 680063ff + * GPMC (err login) 68006400 - 680067ff + * SMS (err login) 68006c00 - 68006fff + * SMS registers 68008000 - 68008fff + * SDRC registers 68009000 - 68009fff + * GPMC registers 6800a000 6800afff + */ + + qemu_register_reset(omap2_mpu_reset, s); + + return s; +} diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c new file mode 100644 index 0000000000..c0f50c90fe --- /dev/null +++ b/hw/arm/pxa2xx.c @@ -0,0 +1,2291 @@ +/* + * Intel XScale PXA255/270 processor support. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPL. + */ + +#include "hw/sysbus.h" +#include "hw/pxa.h" +#include "sysemu/sysemu.h" +#include "hw/serial.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "char/char.h" +#include "sysemu/blockdev.h" + +static struct { + hwaddr io_base; + int irqn; +} pxa255_serial[] = { + { 0x40100000, PXA2XX_PIC_FFUART }, + { 0x40200000, PXA2XX_PIC_BTUART }, + { 0x40700000, PXA2XX_PIC_STUART }, + { 0x41600000, PXA25X_PIC_HWUART }, + { 0, 0 } +}, pxa270_serial[] = { + { 0x40100000, PXA2XX_PIC_FFUART }, + { 0x40200000, PXA2XX_PIC_BTUART }, + { 0x40700000, PXA2XX_PIC_STUART }, + { 0, 0 } +}; + +typedef struct PXASSPDef { + hwaddr io_base; + int irqn; +} PXASSPDef; + +#if 0 +static PXASSPDef pxa250_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0, 0 } +}; +#endif + +static PXASSPDef pxa255_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0x41400000, PXA25X_PIC_NSSP }, + { 0, 0 } +}; + +#if 0 +static PXASSPDef pxa26x_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0x41400000, PXA25X_PIC_NSSP }, + { 0x41500000, PXA26X_PIC_ASSP }, + { 0, 0 } +}; +#endif + +static PXASSPDef pxa27x_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0x41700000, PXA27X_PIC_SSP2 }, + { 0x41900000, PXA2XX_PIC_SSP3 }, + { 0, 0 } +}; + +#define PMCR 0x00 /* Power Manager Control register */ +#define PSSR 0x04 /* Power Manager Sleep Status register */ +#define PSPR 0x08 /* Power Manager Scratch-Pad register */ +#define PWER 0x0c /* Power Manager Wake-Up Enable register */ +#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */ +#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */ +#define PEDR 0x18 /* Power Manager Edge-Detect Status register */ +#define PCFR 0x1c /* Power Manager General Configuration register */ +#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */ +#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */ +#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */ +#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */ +#define RCSR 0x30 /* Reset Controller Status register */ +#define PSLR 0x34 /* Power Manager Sleep Configuration register */ +#define PTSR 0x38 /* Power Manager Standby Configuration register */ +#define PVCR 0x40 /* Power Manager Voltage Change Control register */ +#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */ +#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */ +#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */ +#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ +#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ + +static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxState *s = (PXA2xxState *) opaque; + + switch (addr) { + case PMCR ... PCMD31: + if (addr & 3) + goto fail; + + return s->pm_regs[addr >> 2]; + default: + fail: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_pm_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + PXA2xxState *s = (PXA2xxState *) opaque; + + switch (addr) { + case PMCR: + /* Clear the write-one-to-clear bits... */ + s->pm_regs[addr >> 2] &= ~(value & 0x2a); + /* ...and set the plain r/w bits */ + s->pm_regs[addr >> 2] &= ~0x15; + s->pm_regs[addr >> 2] |= value & 0x15; + break; + + case PSSR: /* Read-clean registers */ + case RCSR: + case PKSR: + s->pm_regs[addr >> 2] &= ~value; + break; + + default: /* Read-write registers */ + if (!(addr & 3)) { + s->pm_regs[addr >> 2] = value; + break; + } + + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +static const MemoryRegionOps pxa2xx_pm_ops = { + .read = pxa2xx_pm_read, + .write = pxa2xx_pm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_pxa2xx_pm = { + .name = "pxa2xx_pm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40), + VMSTATE_END_OF_LIST() + } +}; + +#define CCCR 0x00 /* Core Clock Configuration register */ +#define CKEN 0x04 /* Clock Enable register */ +#define OSCC 0x08 /* Oscillator Configuration register */ +#define CCSR 0x0c /* Core Clock Status register */ + +static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxState *s = (PXA2xxState *) opaque; + + switch (addr) { + case CCCR: + case CKEN: + case OSCC: + return s->cm_regs[addr >> 2]; + + case CCSR: + return s->cm_regs[CCCR >> 2] | (3 << 28); + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_cm_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + PXA2xxState *s = (PXA2xxState *) opaque; + + switch (addr) { + case CCCR: + case CKEN: + s->cm_regs[addr >> 2] = value; + break; + + case OSCC: + s->cm_regs[addr >> 2] &= ~0x6c; + s->cm_regs[addr >> 2] |= value & 0x6e; + if ((value >> 1) & 1) /* OON */ + s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */ + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +static const MemoryRegionOps pxa2xx_cm_ops = { + .read = pxa2xx_cm_read, + .write = pxa2xx_cm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_pxa2xx_cm = { + .name = "pxa2xx_cm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4), + VMSTATE_UINT32(clkcfg, PXA2xxState), + VMSTATE_UINT32(pmnc, PXA2xxState), + VMSTATE_END_OF_LIST() + } +}; + +static int pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + *value = s->clkcfg; + return 0; +} + +static int pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + s->clkcfg = value & 0xf; + if (value & 2) { + printf("%s: CPU frequency change attempt\n", __func__); + } + return 0; +} + +static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + static const char *pwrmode[8] = { + "Normal", "Idle", "Deep-idle", "Standby", + "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep", + }; + + if (value & 8) { + printf("%s: CPU voltage change attempt\n", __func__); + } + switch (value & 7) { + case 0: + /* Do nothing */ + break; + + case 1: + /* Idle */ + if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + break; + } + /* Fall through. */ + + case 2: + /* Deep-Idle */ + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ + goto message; + + case 3: + s->cpu->env.uncached_cpsr = + ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + s->cpu->env.cp15.c1_sys = 0; + s->cpu->env.cp15.c1_coproc = 0; + s->cpu->env.cp15.c2_base0 = 0; + s->cpu->env.cp15.c3 = 0; + s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ + s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ + + /* + * The scratch-pad register is almost universally used + * for storing the return address on suspend. For the + * lack of a resuming bootloader, perform a jump + * directly to that address. + */ + memset(s->cpu->env.regs, 0, 4 * 15); + s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; + +#if 0 + buffer = 0xe59ff000; /* ldr pc, [pc, #0] */ + cpu_physical_memory_write(0, &buffer, 4); + buffer = s->pm_regs[PSPR >> 2]; + cpu_physical_memory_write(8, &buffer, 4); +#endif + + /* Suspend */ + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); + + goto message; + + default: + message: + printf("%s: machine entered %s mode\n", __func__, + pwrmode[value & 7]); + } + + return 0; +} + +static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + *value = s->pmnc; + return 0; +} + +static int pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + s->pmnc = value; + return 0; +} + +static int pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + if (s->pmnc & 1) { + *value = qemu_get_clock_ns(vm_clock); + } else { + *value = 0; + } + return 0; +} + +static const ARMCPRegInfo pxa_cp_reginfo[] = { + /* cp14 crm==1: perf registers */ + { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write }, + { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore }, + { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* cp14 crm==2: performance count registers */ + { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* cp14 crn==6: CLKCFG */ + { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write }, + /* cp14 crn==7: PWRMODE */ + { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, + REGINFO_SENTINEL +}; + +static void pxa2xx_setup_cp14(PXA2xxState *s) +{ + define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s); +} + +#define MDCNFG 0x00 /* SDRAM Configuration register */ +#define MDREFR 0x04 /* SDRAM Refresh Control register */ +#define MSC0 0x08 /* Static Memory Control register 0 */ +#define MSC1 0x0c /* Static Memory Control register 1 */ +#define MSC2 0x10 /* Static Memory Control register 2 */ +#define MECR 0x14 /* Expansion Memory Bus Config register */ +#define SXCNFG 0x1c /* Synchronous Static Memory Config register */ +#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */ +#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */ +#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */ +#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */ +#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */ +#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */ +#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */ +#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */ +#define ARB_CNTL 0x48 /* Arbiter Control register */ +#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */ +#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */ +#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */ +#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */ +#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */ +#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */ +#define SA1110 0x64 /* SA-1110 Memory Compatibility register */ + +static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxState *s = (PXA2xxState *) opaque; + + switch (addr) { + case MDCNFG ... SA1110: + if ((addr & 3) == 0) + return s->mm_regs[addr >> 2]; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_mm_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + PXA2xxState *s = (PXA2xxState *) opaque; + + switch (addr) { + case MDCNFG ... SA1110: + if ((addr & 3) == 0) { + s->mm_regs[addr >> 2] = value; + break; + } + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +static const MemoryRegionOps pxa2xx_mm_ops = { + .read = pxa2xx_mm_read, + .write = pxa2xx_mm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_pxa2xx_mm = { + .name = "pxa2xx_mm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a), + VMSTATE_END_OF_LIST() + } +}; + +/* Synchronous Serial Ports */ +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq; + int enable; + SSIBus *bus; + + uint32_t sscr[2]; + uint32_t sspsp; + uint32_t ssto; + uint32_t ssitr; + uint32_t sssr; + uint8_t sstsa; + uint8_t ssrsa; + uint8_t ssacd; + + uint32_t rx_fifo[16]; + int rx_level; + int rx_start; +} PXA2xxSSPState; + +#define SSCR0 0x00 /* SSP Control register 0 */ +#define SSCR1 0x04 /* SSP Control register 1 */ +#define SSSR 0x08 /* SSP Status register */ +#define SSITR 0x0c /* SSP Interrupt Test register */ +#define SSDR 0x10 /* SSP Data register */ +#define SSTO 0x28 /* SSP Time-Out register */ +#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */ +#define SSTSA 0x30 /* SSP TX Time Slot Active register */ +#define SSRSA 0x34 /* SSP RX Time Slot Active register */ +#define SSTSS 0x38 /* SSP Time Slot Status register */ +#define SSACD 0x3c /* SSP Audio Clock Divider register */ + +/* Bitfields for above registers */ +#define SSCR0_SPI(x) (((x) & 0x30) == 0x00) +#define SSCR0_SSP(x) (((x) & 0x30) == 0x10) +#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20) +#define SSCR0_PSP(x) (((x) & 0x30) == 0x30) +#define SSCR0_SSE (1 << 7) +#define SSCR0_RIM (1 << 22) +#define SSCR0_TIM (1 << 23) +#define SSCR0_MOD (1 << 31) +#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1) +#define SSCR1_RIE (1 << 0) +#define SSCR1_TIE (1 << 1) +#define SSCR1_LBM (1 << 2) +#define SSCR1_MWDS (1 << 5) +#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1) +#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1) +#define SSCR1_EFWR (1 << 14) +#define SSCR1_PINTE (1 << 18) +#define SSCR1_TINTE (1 << 19) +#define SSCR1_RSRE (1 << 20) +#define SSCR1_TSRE (1 << 21) +#define SSCR1_EBCEI (1 << 29) +#define SSITR_INT (7 << 5) +#define SSSR_TNF (1 << 2) +#define SSSR_RNE (1 << 3) +#define SSSR_TFS (1 << 5) +#define SSSR_RFS (1 << 6) +#define SSSR_ROR (1 << 7) +#define SSSR_PINT (1 << 18) +#define SSSR_TINT (1 << 19) +#define SSSR_EOC (1 << 20) +#define SSSR_TUR (1 << 21) +#define SSSR_BCE (1 << 23) +#define SSSR_RW 0x00bc0080 + +static void pxa2xx_ssp_int_update(PXA2xxSSPState *s) +{ + int level = 0; + + level |= s->ssitr & SSITR_INT; + level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI); + level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM); + level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT)); + level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE); + level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE); + level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM); + level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE); + level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE); + qemu_set_irq(s->irq, !!level); +} + +static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s) +{ + s->sssr &= ~(0xf << 12); /* Clear RFL */ + s->sssr &= ~(0xf << 8); /* Clear TFL */ + s->sssr &= ~SSSR_TFS; + s->sssr &= ~SSSR_TNF; + if (s->enable) { + s->sssr |= ((s->rx_level - 1) & 0xf) << 12; + if (s->rx_level >= SSCR1_RFT(s->sscr[1])) + s->sssr |= SSSR_RFS; + else + s->sssr &= ~SSSR_RFS; + if (s->rx_level) + s->sssr |= SSSR_RNE; + else + s->sssr &= ~SSSR_RNE; + /* TX FIFO is never filled, so it is always in underrun + condition if SSP is enabled */ + s->sssr |= SSSR_TFS; + s->sssr |= SSSR_TNF; + } + + pxa2xx_ssp_int_update(s); +} + +static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; + uint32_t retval; + + switch (addr) { + case SSCR0: + return s->sscr[0]; + case SSCR1: + return s->sscr[1]; + case SSPSP: + return s->sspsp; + case SSTO: + return s->ssto; + case SSITR: + return s->ssitr; + case SSSR: + return s->sssr | s->ssitr; + case SSDR: + if (!s->enable) + return 0xffffffff; + if (s->rx_level < 1) { + printf("%s: SSP Rx Underrun\n", __FUNCTION__); + return 0xffffffff; + } + s->rx_level --; + retval = s->rx_fifo[s->rx_start ++]; + s->rx_start &= 0xf; + pxa2xx_ssp_fifo_update(s); + return retval; + case SSTSA: + return s->sstsa; + case SSRSA: + return s->ssrsa; + case SSTSS: + return 0; + case SSACD: + return s->ssacd; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_ssp_write(void *opaque, hwaddr addr, + uint64_t value64, unsigned size) +{ + PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; + uint32_t value = value64; + + switch (addr) { + case SSCR0: + s->sscr[0] = value & 0xc7ffffff; + s->enable = value & SSCR0_SSE; + if (value & SSCR0_MOD) + printf("%s: Attempt to use network mode\n", __FUNCTION__); + if (s->enable && SSCR0_DSS(value) < 4) + printf("%s: Wrong data size: %i bits\n", __FUNCTION__, + SSCR0_DSS(value)); + if (!(value & SSCR0_SSE)) { + s->sssr = 0; + s->ssitr = 0; + s->rx_level = 0; + } + pxa2xx_ssp_fifo_update(s); + break; + + case SSCR1: + s->sscr[1] = value; + if (value & (SSCR1_LBM | SSCR1_EFWR)) + printf("%s: Attempt to use SSP test mode\n", __FUNCTION__); + pxa2xx_ssp_fifo_update(s); + break; + + case SSPSP: + s->sspsp = value; + break; + + case SSTO: + s->ssto = value; + break; + + case SSITR: + s->ssitr = value & SSITR_INT; + pxa2xx_ssp_int_update(s); + break; + + case SSSR: + s->sssr &= ~(value & SSSR_RW); + pxa2xx_ssp_int_update(s); + break; + + case SSDR: + if (SSCR0_UWIRE(s->sscr[0])) { + if (s->sscr[1] & SSCR1_MWDS) + value &= 0xffff; + else + value &= 0xff; + } else + /* Note how 32bits overflow does no harm here */ + value &= (1 << SSCR0_DSS(s->sscr[0])) - 1; + + /* Data goes from here to the Tx FIFO and is shifted out from + * there directly to the slave, no need to buffer it. + */ + if (s->enable) { + uint32_t readval; + readval = ssi_transfer(s->bus, value); + if (s->rx_level < 0x10) { + s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval; + } else { + s->sssr |= SSSR_ROR; + } + } + pxa2xx_ssp_fifo_update(s); + break; + + case SSTSA: + s->sstsa = value; + break; + + case SSRSA: + s->ssrsa = value; + break; + + case SSACD: + s->ssacd = value; + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +static const MemoryRegionOps pxa2xx_ssp_ops = { + .read = pxa2xx_ssp_read, + .write = pxa2xx_ssp_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) +{ + PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; + int i; + + qemu_put_be32(f, s->enable); + + qemu_put_be32s(f, &s->sscr[0]); + qemu_put_be32s(f, &s->sscr[1]); + qemu_put_be32s(f, &s->sspsp); + qemu_put_be32s(f, &s->ssto); + qemu_put_be32s(f, &s->ssitr); + qemu_put_be32s(f, &s->sssr); + qemu_put_8s(f, &s->sstsa); + qemu_put_8s(f, &s->ssrsa); + qemu_put_8s(f, &s->ssacd); + + qemu_put_byte(f, s->rx_level); + for (i = 0; i < s->rx_level; i ++) + qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]); +} + +static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) +{ + PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; + int i; + + s->enable = qemu_get_be32(f); + + qemu_get_be32s(f, &s->sscr[0]); + qemu_get_be32s(f, &s->sscr[1]); + qemu_get_be32s(f, &s->sspsp); + qemu_get_be32s(f, &s->ssto); + qemu_get_be32s(f, &s->ssitr); + qemu_get_be32s(f, &s->sssr); + qemu_get_8s(f, &s->sstsa); + qemu_get_8s(f, &s->ssrsa); + qemu_get_8s(f, &s->ssacd); + + s->rx_level = qemu_get_byte(f); + s->rx_start = 0; + for (i = 0; i < s->rx_level; i ++) + s->rx_fifo[i] = qemu_get_byte(f); + + return 0; +} + +static int pxa2xx_ssp_init(SysBusDevice *dev) +{ + PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev); + + sysbus_init_irq(dev, &s->irq); + + memory_region_init_io(&s->iomem, &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0, + pxa2xx_ssp_save, pxa2xx_ssp_load, s); + + s->bus = ssi_create_bus(&dev->qdev, "ssi"); + return 0; +} + +/* Real-Time Clock */ +#define RCNR 0x00 /* RTC Counter register */ +#define RTAR 0x04 /* RTC Alarm register */ +#define RTSR 0x08 /* RTC Status register */ +#define RTTR 0x0c /* RTC Timer Trim register */ +#define RDCR 0x10 /* RTC Day Counter register */ +#define RYCR 0x14 /* RTC Year Counter register */ +#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */ +#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */ +#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */ +#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */ +#define SWCR 0x28 /* RTC Stopwatch Counter register */ +#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */ +#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */ +#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */ +#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */ + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t rttr; + uint32_t rtsr; + uint32_t rtar; + uint32_t rdar1; + uint32_t rdar2; + uint32_t ryar1; + uint32_t ryar2; + uint32_t swar1; + uint32_t swar2; + uint32_t piar; + uint32_t last_rcnr; + uint32_t last_rdcr; + uint32_t last_rycr; + uint32_t last_swcr; + uint32_t last_rtcpicr; + int64_t last_hz; + int64_t last_sw; + int64_t last_pi; + QEMUTimer *rtc_hz; + QEMUTimer *rtc_rdal1; + QEMUTimer *rtc_rdal2; + QEMUTimer *rtc_swal1; + QEMUTimer *rtc_swal2; + QEMUTimer *rtc_pi; + qemu_irq rtc_irq; +} PXA2xxRTCState; + +static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s) +{ + qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553)); +} + +static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s) +{ + int64_t rt = qemu_get_clock_ms(rtc_clock); + s->last_rcnr += ((rt - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + s->last_rdcr += ((rt - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + s->last_hz = rt; +} + +static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s) +{ + int64_t rt = qemu_get_clock_ms(rtc_clock); + if (s->rtsr & (1 << 12)) + s->last_swcr += (rt - s->last_sw) / 10; + s->last_sw = rt; +} + +static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s) +{ + int64_t rt = qemu_get_clock_ms(rtc_clock); + if (s->rtsr & (1 << 15)) + s->last_swcr += rt - s->last_pi; + s->last_pi = rt; +} + +static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s, + uint32_t rtsr) +{ + if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0))) + qemu_mod_timer(s->rtc_hz, s->last_hz + + (((s->rtar - s->last_rcnr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); + else + qemu_del_timer(s->rtc_hz); + + if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4))) + qemu_mod_timer(s->rtc_rdal1, s->last_hz + + (((s->rdar1 - s->last_rdcr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_rdal1); + + if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6))) + qemu_mod_timer(s->rtc_rdal2, s->last_hz + + (((s->rdar2 - s->last_rdcr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_rdal2); + + if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8))) + qemu_mod_timer(s->rtc_swal1, s->last_sw + + (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_swal1); + + if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10))) + qemu_mod_timer(s->rtc_swal2, s->last_sw + + (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_swal2); + + if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13))) + qemu_mod_timer(s->rtc_pi, s->last_pi + + (s->piar & 0xffff) - s->last_rtcpicr); + else + qemu_del_timer(s->rtc_pi); +} + +static inline void pxa2xx_rtc_hz_tick(void *opaque) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + s->rtsr |= (1 << 0); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_rdal1_tick(void *opaque) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + s->rtsr |= (1 << 4); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_rdal2_tick(void *opaque) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + s->rtsr |= (1 << 6); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_swal1_tick(void *opaque) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + s->rtsr |= (1 << 8); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_swal2_tick(void *opaque) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + s->rtsr |= (1 << 10); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_pi_tick(void *opaque) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + s->rtsr |= (1 << 13); + pxa2xx_rtc_piupdate(s); + s->last_rtcpicr = 0; + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + + switch (addr) { + case RTTR: + return s->rttr; + case RTSR: + return s->rtsr; + case RTAR: + return s->rtar; + case RDAR1: + return s->rdar1; + case RDAR2: + return s->rdar2; + case RYAR1: + return s->ryar1; + case RYAR2: + return s->ryar2; + case SWAR1: + return s->swar1; + case SWAR2: + return s->swar2; + case PIAR: + return s->piar; + case RCNR: + return s->last_rcnr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + case RDCR: + return s->last_rdcr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + case RYCR: + return s->last_rycr; + case SWCR: + if (s->rtsr & (1 << 12)) + return s->last_swcr + (qemu_get_clock_ms(rtc_clock) - s->last_sw) / 10; + else + return s->last_swcr; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_rtc_write(void *opaque, hwaddr addr, + uint64_t value64, unsigned size) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + uint32_t value = value64; + + switch (addr) { + case RTTR: + if (!(s->rttr & (1 << 31))) { + pxa2xx_rtc_hzupdate(s); + s->rttr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + } + break; + + case RTSR: + if ((s->rtsr ^ value) & (1 << 15)) + pxa2xx_rtc_piupdate(s); + + if ((s->rtsr ^ value) & (1 << 12)) + pxa2xx_rtc_swupdate(s); + + if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac)) + pxa2xx_rtc_alarm_update(s, value); + + s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac)); + pxa2xx_rtc_int_update(s); + break; + + case RTAR: + s->rtar = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RDAR1: + s->rdar1 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RDAR2: + s->rdar2 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RYAR1: + s->ryar1 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RYAR2: + s->ryar2 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case SWAR1: + pxa2xx_rtc_swupdate(s); + s->swar1 = value; + s->last_swcr = 0; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case SWAR2: + s->swar2 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case PIAR: + s->piar = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RCNR: + pxa2xx_rtc_hzupdate(s); + s->last_rcnr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RDCR: + pxa2xx_rtc_hzupdate(s); + s->last_rdcr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RYCR: + s->last_rycr = value; + break; + + case SWCR: + pxa2xx_rtc_swupdate(s); + s->last_swcr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RTCPICR: + pxa2xx_rtc_piupdate(s); + s->last_rtcpicr = value & 0xffff; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static const MemoryRegionOps pxa2xx_rtc_ops = { + .read = pxa2xx_rtc_read, + .write = pxa2xx_rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int pxa2xx_rtc_init(SysBusDevice *dev) +{ + PXA2xxRTCState *s = FROM_SYSBUS(PXA2xxRTCState, dev); + struct tm tm; + int wom; + + s->rttr = 0x7fff; + s->rtsr = 0; + + qemu_get_timedate(&tm, 0); + wom = ((tm.tm_mday - 1) / 7) + 1; + + s->last_rcnr = (uint32_t) mktimegm(&tm); + s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) | + (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec; + s->last_rycr = ((tm.tm_year + 1900) << 9) | + ((tm.tm_mon + 1) << 5) | tm.tm_mday; + s->last_swcr = (tm.tm_hour << 19) | + (tm.tm_min << 13) | (tm.tm_sec << 7); + s->last_rtcpicr = 0; + s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rtc_clock); + + s->rtc_hz = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_hz_tick, s); + s->rtc_rdal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s); + s->rtc_rdal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s); + s->rtc_swal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s); + s->rtc_swal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s); + s->rtc_pi = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_pi_tick, s); + + sysbus_init_irq(dev, &s->rtc_irq); + + memory_region_init_io(&s->iomem, &pxa2xx_rtc_ops, s, "pxa2xx-rtc", 0x10000); + sysbus_init_mmio(dev, &s->iomem); + + return 0; +} + +static void pxa2xx_rtc_pre_save(void *opaque) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + + pxa2xx_rtc_hzupdate(s); + pxa2xx_rtc_piupdate(s); + pxa2xx_rtc_swupdate(s); +} + +static int pxa2xx_rtc_post_load(void *opaque, int version_id) +{ + PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; + + pxa2xx_rtc_alarm_update(s, s->rtsr); + + return 0; +} + +static const VMStateDescription vmstate_pxa2xx_rtc_regs = { + .name = "pxa2xx_rtc", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .pre_save = pxa2xx_rtc_pre_save, + .post_load = pxa2xx_rtc_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(rttr, PXA2xxRTCState), + VMSTATE_UINT32(rtsr, PXA2xxRTCState), + VMSTATE_UINT32(rtar, PXA2xxRTCState), + VMSTATE_UINT32(rdar1, PXA2xxRTCState), + VMSTATE_UINT32(rdar2, PXA2xxRTCState), + VMSTATE_UINT32(ryar1, PXA2xxRTCState), + VMSTATE_UINT32(ryar2, PXA2xxRTCState), + VMSTATE_UINT32(swar1, PXA2xxRTCState), + VMSTATE_UINT32(swar2, PXA2xxRTCState), + VMSTATE_UINT32(piar, PXA2xxRTCState), + VMSTATE_UINT32(last_rcnr, PXA2xxRTCState), + VMSTATE_UINT32(last_rdcr, PXA2xxRTCState), + VMSTATE_UINT32(last_rycr, PXA2xxRTCState), + VMSTATE_UINT32(last_swcr, PXA2xxRTCState), + VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState), + VMSTATE_INT64(last_hz, PXA2xxRTCState), + VMSTATE_INT64(last_sw, PXA2xxRTCState), + VMSTATE_INT64(last_pi, PXA2xxRTCState), + VMSTATE_END_OF_LIST(), + }, +}; + +static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_rtc_init; + dc->desc = "PXA2xx RTC Controller"; + dc->vmsd = &vmstate_pxa2xx_rtc_regs; +} + +static const TypeInfo pxa2xx_rtc_sysbus_info = { + .name = "pxa2xx_rtc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxRTCState), + .class_init = pxa2xx_rtc_sysbus_class_init, +}; + +/* I2C Interface */ +typedef struct { + I2CSlave i2c; + PXA2xxI2CState *host; +} PXA2xxI2CSlaveState; + +struct PXA2xxI2CState { + SysBusDevice busdev; + MemoryRegion iomem; + PXA2xxI2CSlaveState *slave; + i2c_bus *bus; + qemu_irq irq; + uint32_t offset; + uint32_t region_size; + + uint16_t control; + uint16_t status; + uint8_t ibmr; + uint8_t data; +}; + +#define IBMR 0x80 /* I2C Bus Monitor register */ +#define IDBR 0x88 /* I2C Data Buffer register */ +#define ICR 0x90 /* I2C Control register */ +#define ISR 0x98 /* I2C Status register */ +#define ISAR 0xa0 /* I2C Slave Address register */ + +static void pxa2xx_i2c_update(PXA2xxI2CState *s) +{ + uint16_t level = 0; + level |= s->status & s->control & (1 << 10); /* BED */ + level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */ + level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */ + level |= s->status & (1 << 9); /* SAD */ + qemu_set_irq(s->irq, !!level); +} + +/* These are only stubs now. */ +static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) +{ + PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); + PXA2xxI2CState *s = slave->host; + + switch (event) { + case I2C_START_SEND: + s->status |= (1 << 9); /* set SAD */ + s->status &= ~(1 << 0); /* clear RWM */ + break; + case I2C_START_RECV: + s->status |= (1 << 9); /* set SAD */ + s->status |= 1 << 0; /* set RWM */ + break; + case I2C_FINISH: + s->status |= (1 << 4); /* set SSD */ + break; + case I2C_NACK: + s->status |= 1 << 1; /* set ACKNAK */ + break; + } + pxa2xx_i2c_update(s); +} + +static int pxa2xx_i2c_rx(I2CSlave *i2c) +{ + PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); + PXA2xxI2CState *s = slave->host; + if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) + return 0; + + if (s->status & (1 << 0)) { /* RWM */ + s->status |= 1 << 6; /* set ITE */ + } + pxa2xx_i2c_update(s); + + return s->data; +} + +static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data) +{ + PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); + PXA2xxI2CState *s = slave->host; + if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) + return 1; + + if (!(s->status & (1 << 0))) { /* RWM */ + s->status |= 1 << 7; /* set IRF */ + s->data = data; + } + pxa2xx_i2c_update(s); + + return 1; +} + +static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; + + addr -= s->offset; + switch (addr) { + case ICR: + return s->control; + case ISR: + return s->status | (i2c_bus_busy(s->bus) << 2); + case ISAR: + return s->slave->i2c.address; + case IDBR: + return s->data; + case IBMR: + if (s->status & (1 << 2)) + s->ibmr ^= 3; /* Fake SCL and SDA pin changes */ + else + s->ibmr = 0; + return s->ibmr; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_i2c_write(void *opaque, hwaddr addr, + uint64_t value64, unsigned size) +{ + PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; + uint32_t value = value64; + int ack; + + addr -= s->offset; + switch (addr) { + case ICR: + s->control = value & 0xfff7; + if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */ + /* TODO: slave mode */ + if (value & (1 << 0)) { /* START condition */ + if (s->data & 1) + s->status |= 1 << 0; /* set RWM */ + else + s->status &= ~(1 << 0); /* clear RWM */ + ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1); + } else { + if (s->status & (1 << 0)) { /* RWM */ + s->data = i2c_recv(s->bus); + if (value & (1 << 2)) /* ACKNAK */ + i2c_nack(s->bus); + ack = 1; + } else + ack = !i2c_send(s->bus, s->data); + } + + if (value & (1 << 1)) /* STOP condition */ + i2c_end_transfer(s->bus); + + if (ack) { + if (value & (1 << 0)) /* START condition */ + s->status |= 1 << 6; /* set ITE */ + else + if (s->status & (1 << 0)) /* RWM */ + s->status |= 1 << 7; /* set IRF */ + else + s->status |= 1 << 6; /* set ITE */ + s->status &= ~(1 << 1); /* clear ACKNAK */ + } else { + s->status |= 1 << 6; /* set ITE */ + s->status |= 1 << 10; /* set BED */ + s->status |= 1 << 1; /* set ACKNAK */ + } + } + if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */ + if (value & (1 << 4)) /* MA */ + i2c_end_transfer(s->bus); + pxa2xx_i2c_update(s); + break; + + case ISR: + s->status &= ~(value & 0x07f0); + pxa2xx_i2c_update(s); + break; + + case ISAR: + i2c_set_slave_address(&s->slave->i2c, value & 0x7f); + break; + + case IDBR: + s->data = value & 0xff; + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static const MemoryRegionOps pxa2xx_i2c_ops = { + .read = pxa2xx_i2c_read, + .write = pxa2xx_i2c_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_pxa2xx_i2c_slave = { + .name = "pxa2xx_i2c_slave", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_I2C_SLAVE(i2c, PXA2xxI2CSlaveState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_pxa2xx_i2c = { + .name = "pxa2xx_i2c", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT16(control, PXA2xxI2CState), + VMSTATE_UINT16(status, PXA2xxI2CState), + VMSTATE_UINT8(ibmr, PXA2xxI2CState), + VMSTATE_UINT8(data, PXA2xxI2CState), + VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState, + vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState *), + VMSTATE_END_OF_LIST() + } +}; + +static int pxa2xx_i2c_slave_init(I2CSlave *i2c) +{ + /* Nothing to do. */ + return 0; +} + +static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = pxa2xx_i2c_slave_init; + k->event = pxa2xx_i2c_event; + k->recv = pxa2xx_i2c_rx; + k->send = pxa2xx_i2c_tx; +} + +static const TypeInfo pxa2xx_i2c_slave_info = { + .name = "pxa2xx-i2c-slave", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(PXA2xxI2CSlaveState), + .class_init = pxa2xx_i2c_slave_class_init, +}; + +PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, + qemu_irq irq, uint32_t region_size) +{ + DeviceState *dev; + SysBusDevice *i2c_dev; + PXA2xxI2CState *s; + + i2c_dev = SYS_BUS_DEVICE(qdev_create(NULL, "pxa2xx_i2c")); + qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1); + qdev_prop_set_uint32(&i2c_dev->qdev, "offset", base & region_size); + + qdev_init_nofail(&i2c_dev->qdev); + + sysbus_mmio_map(i2c_dev, 0, base & ~region_size); + sysbus_connect_irq(i2c_dev, 0, irq); + + s = FROM_SYSBUS(PXA2xxI2CState, i2c_dev); + /* FIXME: Should the slave device really be on a separate bus? */ + dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0); + s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE(dev)); + s->slave->host = s; + + return s; +} + +static int pxa2xx_i2c_initfn(SysBusDevice *dev) +{ + PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev); + + s->bus = i2c_init_bus(&dev->qdev, "i2c"); + + memory_region_init_io(&s->iomem, &pxa2xx_i2c_ops, s, + "pxa2xx-i2x", s->region_size); + sysbus_init_mmio(dev, &s->iomem); + sysbus_init_irq(dev, &s->irq); + + return 0; +} + +i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s) +{ + return s->bus; +} + +static Property pxa2xx_i2c_properties[] = { + DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000), + DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_i2c_initfn; + dc->desc = "PXA2xx I2C Bus Controller"; + dc->vmsd = &vmstate_pxa2xx_i2c; + dc->props = pxa2xx_i2c_properties; +} + +static const TypeInfo pxa2xx_i2c_info = { + .name = "pxa2xx_i2c", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxI2CState), + .class_init = pxa2xx_i2c_class_init, +}; + +/* PXA Inter-IC Sound Controller */ +static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s) +{ + i2s->rx_len = 0; + i2s->tx_len = 0; + i2s->fifo_len = 0; + i2s->clk = 0x1a; + i2s->control[0] = 0x00; + i2s->control[1] = 0x00; + i2s->status = 0x00; + i2s->mask = 0x00; +} + +#define SACR_TFTH(val) ((val >> 8) & 0xf) +#define SACR_RFTH(val) ((val >> 12) & 0xf) +#define SACR_DREC(val) (val & (1 << 3)) +#define SACR_DPRL(val) (val & (1 << 4)) + +static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s) +{ + int rfs, tfs; + rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len && + !SACR_DREC(i2s->control[1]); + tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) && + i2s->enable && !SACR_DPRL(i2s->control[1]); + + qemu_set_irq(i2s->rx_dma, rfs); + qemu_set_irq(i2s->tx_dma, tfs); + + i2s->status &= 0xe0; + if (i2s->fifo_len < 16 || !i2s->enable) + i2s->status |= 1 << 0; /* TNF */ + if (i2s->rx_len) + i2s->status |= 1 << 1; /* RNE */ + if (i2s->enable) + i2s->status |= 1 << 2; /* BSY */ + if (tfs) + i2s->status |= 1 << 3; /* TFS */ + if (rfs) + i2s->status |= 1 << 4; /* RFS */ + if (!(i2s->tx_len && i2s->enable)) + i2s->status |= i2s->fifo_len << 8; /* TFL */ + i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */ + + qemu_set_irq(i2s->irq, i2s->status & i2s->mask); +} + +#define SACR0 0x00 /* Serial Audio Global Control register */ +#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */ +#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */ +#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */ +#define SAICR 0x18 /* Serial Audio Interrupt Clear register */ +#define SADIV 0x60 /* Serial Audio Clock Divider register */ +#define SADR 0x80 /* Serial Audio Data register */ + +static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; + + switch (addr) { + case SACR0: + return s->control[0]; + case SACR1: + return s->control[1]; + case SASR0: + return s->status; + case SAIMR: + return s->mask; + case SAICR: + return 0; + case SADIV: + return s->clk; + case SADR: + if (s->rx_len > 0) { + s->rx_len --; + pxa2xx_i2s_update(s); + return s->codec_in(s->opaque); + } + return 0; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_i2s_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; + uint32_t *sample; + + switch (addr) { + case SACR0: + if (value & (1 << 3)) /* RST */ + pxa2xx_i2s_reset(s); + s->control[0] = value & 0xff3d; + if (!s->enable && (value & 1) && s->tx_len) { /* ENB */ + for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++) + s->codec_out(s->opaque, *sample); + s->status &= ~(1 << 7); /* I2SOFF */ + } + if (value & (1 << 4)) /* EFWR */ + printf("%s: Attempt to use special function\n", __FUNCTION__); + s->enable = (value & 9) == 1; /* ENB && !RST*/ + pxa2xx_i2s_update(s); + break; + case SACR1: + s->control[1] = value & 0x0039; + if (value & (1 << 5)) /* ENLBF */ + printf("%s: Attempt to use loopback function\n", __FUNCTION__); + if (value & (1 << 4)) /* DPRL */ + s->fifo_len = 0; + pxa2xx_i2s_update(s); + break; + case SAIMR: + s->mask = value & 0x0078; + pxa2xx_i2s_update(s); + break; + case SAICR: + s->status &= ~(value & (3 << 5)); + pxa2xx_i2s_update(s); + break; + case SADIV: + s->clk = value & 0x007f; + break; + case SADR: + if (s->tx_len && s->enable) { + s->tx_len --; + pxa2xx_i2s_update(s); + s->codec_out(s->opaque, value); + } else if (s->fifo_len < 16) { + s->fifo[s->fifo_len ++] = value; + pxa2xx_i2s_update(s); + } + break; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static const MemoryRegionOps pxa2xx_i2s_ops = { + .read = pxa2xx_i2s_read, + .write = pxa2xx_i2s_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_pxa2xx_i2s = { + .name = "pxa2xx_i2s", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2), + VMSTATE_UINT32(status, PXA2xxI2SState), + VMSTATE_UINT32(mask, PXA2xxI2SState), + VMSTATE_UINT32(clk, PXA2xxI2SState), + VMSTATE_INT32(enable, PXA2xxI2SState), + VMSTATE_INT32(rx_len, PXA2xxI2SState), + VMSTATE_INT32(tx_len, PXA2xxI2SState), + VMSTATE_INT32(fifo_len, PXA2xxI2SState), + VMSTATE_END_OF_LIST() + } +}; + +static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) +{ + PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; + uint32_t *sample; + + /* Signal FIFO errors */ + if (s->enable && s->tx_len) + s->status |= 1 << 5; /* TUR */ + if (s->enable && s->rx_len) + s->status |= 1 << 6; /* ROR */ + + /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to + * handle the cases where it makes a difference. */ + s->tx_len = tx - s->fifo_len; + s->rx_len = rx; + /* Note that is s->codec_out wasn't set, we wouldn't get called. */ + if (s->enable) + for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++) + s->codec_out(s->opaque, *sample); + pxa2xx_i2s_update(s); +} + +static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, + hwaddr base, + qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma) +{ + PXA2xxI2SState *s = (PXA2xxI2SState *) + g_malloc0(sizeof(PXA2xxI2SState)); + + s->irq = irq; + s->rx_dma = rx_dma; + s->tx_dma = tx_dma; + s->data_req = pxa2xx_i2s_data_req; + + pxa2xx_i2s_reset(s); + + memory_region_init_io(&s->iomem, &pxa2xx_i2s_ops, s, + "pxa2xx-i2s", 0x100000); + memory_region_add_subregion(sysmem, base, &s->iomem); + + vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s); + + return s; +} + +/* PXA Fast Infra-red Communications Port */ +struct PXA2xxFIrState { + MemoryRegion iomem; + qemu_irq irq; + qemu_irq rx_dma; + qemu_irq tx_dma; + int enable; + CharDriverState *chr; + + uint8_t control[3]; + uint8_t status[2]; + + int rx_len; + int rx_start; + uint8_t rx_fifo[64]; +}; + +static void pxa2xx_fir_reset(PXA2xxFIrState *s) +{ + s->control[0] = 0x00; + s->control[1] = 0x00; + s->control[2] = 0x00; + s->status[0] = 0x00; + s->status[1] = 0x00; + s->enable = 0; +} + +static inline void pxa2xx_fir_update(PXA2xxFIrState *s) +{ + static const int tresh[4] = { 8, 16, 32, 0 }; + int intr = 0; + if ((s->control[0] & (1 << 4)) && /* RXE */ + s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */ + s->status[0] |= 1 << 4; /* RFS */ + else + s->status[0] &= ~(1 << 4); /* RFS */ + if (s->control[0] & (1 << 3)) /* TXE */ + s->status[0] |= 1 << 3; /* TFS */ + else + s->status[0] &= ~(1 << 3); /* TFS */ + if (s->rx_len) + s->status[1] |= 1 << 2; /* RNE */ + else + s->status[1] &= ~(1 << 2); /* RNE */ + if (s->control[0] & (1 << 4)) /* RXE */ + s->status[1] |= 1 << 0; /* RSY */ + else + s->status[1] &= ~(1 << 0); /* RSY */ + + intr |= (s->control[0] & (1 << 5)) && /* RIE */ + (s->status[0] & (1 << 4)); /* RFS */ + intr |= (s->control[0] & (1 << 6)) && /* TIE */ + (s->status[0] & (1 << 3)); /* TFS */ + intr |= (s->control[2] & (1 << 4)) && /* TRAIL */ + (s->status[0] & (1 << 6)); /* EOC */ + intr |= (s->control[0] & (1 << 2)) && /* TUS */ + (s->status[0] & (1 << 1)); /* TUR */ + intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */ + + qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1); + qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1); + + qemu_set_irq(s->irq, intr && s->enable); +} + +#define ICCR0 0x00 /* FICP Control register 0 */ +#define ICCR1 0x04 /* FICP Control register 1 */ +#define ICCR2 0x08 /* FICP Control register 2 */ +#define ICDR 0x0c /* FICP Data register */ +#define ICSR0 0x14 /* FICP Status register 0 */ +#define ICSR1 0x18 /* FICP Status register 1 */ +#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */ + +static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr, + unsigned size) +{ + PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; + uint8_t ret; + + switch (addr) { + case ICCR0: + return s->control[0]; + case ICCR1: + return s->control[1]; + case ICCR2: + return s->control[2]; + case ICDR: + s->status[0] &= ~0x01; + s->status[1] &= ~0x72; + if (s->rx_len) { + s->rx_len --; + ret = s->rx_fifo[s->rx_start ++]; + s->rx_start &= 63; + pxa2xx_fir_update(s); + return ret; + } + printf("%s: Rx FIFO underrun.\n", __FUNCTION__); + break; + case ICSR0: + return s->status[0]; + case ICSR1: + return s->status[1] | (1 << 3); /* TNF */ + case ICFOR: + return s->rx_len; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_fir_write(void *opaque, hwaddr addr, + uint64_t value64, unsigned size) +{ + PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; + uint32_t value = value64; + uint8_t ch; + + switch (addr) { + case ICCR0: + s->control[0] = value; + if (!(value & (1 << 4))) /* RXE */ + s->rx_len = s->rx_start = 0; + if (!(value & (1 << 3))) { /* TXE */ + /* Nop */ + } + s->enable = value & 1; /* ITR */ + if (!s->enable) + s->status[0] = 0; + pxa2xx_fir_update(s); + break; + case ICCR1: + s->control[1] = value; + break; + case ICCR2: + s->control[2] = value & 0x3f; + pxa2xx_fir_update(s); + break; + case ICDR: + if (s->control[2] & (1 << 2)) /* TXP */ + ch = value; + else + ch = ~value; + if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */ + qemu_chr_fe_write(s->chr, &ch, 1); + break; + case ICSR0: + s->status[0] &= ~(value & 0x66); + pxa2xx_fir_update(s); + break; + case ICFOR: + break; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static const MemoryRegionOps pxa2xx_fir_ops = { + .read = pxa2xx_fir_read, + .write = pxa2xx_fir_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int pxa2xx_fir_is_empty(void *opaque) +{ + PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; + return (s->rx_len < 64); +} + +static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size) +{ + PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; + if (!(s->control[0] & (1 << 4))) /* RXE */ + return; + + while (size --) { + s->status[1] |= 1 << 4; /* EOF */ + if (s->rx_len >= 64) { + s->status[1] |= 1 << 6; /* ROR */ + break; + } + + if (s->control[2] & (1 << 3)) /* RXP */ + s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++); + else + s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++); + } + + pxa2xx_fir_update(s); +} + +static void pxa2xx_fir_event(void *opaque, int event) +{ +} + +static void pxa2xx_fir_save(QEMUFile *f, void *opaque) +{ + PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; + int i; + + qemu_put_be32(f, s->enable); + + qemu_put_8s(f, &s->control[0]); + qemu_put_8s(f, &s->control[1]); + qemu_put_8s(f, &s->control[2]); + qemu_put_8s(f, &s->status[0]); + qemu_put_8s(f, &s->status[1]); + + qemu_put_byte(f, s->rx_len); + for (i = 0; i < s->rx_len; i ++) + qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]); +} + +static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) +{ + PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; + int i; + + s->enable = qemu_get_be32(f); + + qemu_get_8s(f, &s->control[0]); + qemu_get_8s(f, &s->control[1]); + qemu_get_8s(f, &s->control[2]); + qemu_get_8s(f, &s->status[0]); + qemu_get_8s(f, &s->status[1]); + + s->rx_len = qemu_get_byte(f); + s->rx_start = 0; + for (i = 0; i < s->rx_len; i ++) + s->rx_fifo[i] = qemu_get_byte(f); + + return 0; +} + +static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + hwaddr base, + qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, + CharDriverState *chr) +{ + PXA2xxFIrState *s = (PXA2xxFIrState *) + g_malloc0(sizeof(PXA2xxFIrState)); + + s->irq = irq; + s->rx_dma = rx_dma; + s->tx_dma = tx_dma; + s->chr = chr; + + pxa2xx_fir_reset(s); + + memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); + memory_region_add_subregion(sysmem, base, &s->iomem); + + if (chr) + qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, + pxa2xx_fir_rx, pxa2xx_fir_event, s); + + register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, + pxa2xx_fir_load, s); + + return s; +} + +static void pxa2xx_reset(void *opaque, int line, int level) +{ + PXA2xxState *s = (PXA2xxState *) opaque; + + if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */ + cpu_reset(CPU(s->cpu)); + /* TODO: reset peripherals */ + } +} + +/* Initialise a PXA270 integrated chip (ARM based core). */ +PXA2xxState *pxa270_init(MemoryRegion *address_space, + unsigned int sdram_size, const char *revision) +{ + PXA2xxState *s; + int i; + DriveInfo *dinfo; + s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); + + if (revision && strncmp(revision, "pxa27", 5)) { + fprintf(stderr, "Machine requires a PXA27x processor.\n"); + exit(1); + } + if (!revision) + revision = "pxa270"; + + s->cpu = cpu_arm_init(revision); + if (s->cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; + + /* SDRAM & Internal Memory Storage */ + memory_region_init_ram(&s->sdram, "pxa270.sdram", sdram_size); + vmstate_register_ram_global(&s->sdram); + memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); + memory_region_init_ram(&s->internal, "pxa270.internal", 0x40000); + vmstate_register_ram_global(&s->internal); + memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, + &s->internal); + + s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); + + s->dma = pxa27x_dma_init(0x40000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); + + sysbus_create_varargs("pxa27x-timer", 0x40a00000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0), + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1), + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2), + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), + qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11), + NULL); + + s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121); + + dinfo = drive_get(IF_SD, 0, 0); + if (!dinfo) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC), + qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI), + qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI)); + + for (i = 0; pxa270_serial[i].io_base; i++) { + if (serial_hds[i]) { + serial_mm_init(address_space, pxa270_serial[i].io_base, 2, + qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn), + 14857000 / 16, serial_hds[i], + DEVICE_NATIVE_ENDIAN); + } else { + break; + } + } + if (serial_hds[i]) + s->fir = pxa2xx_fir_init(address_space, 0x40800000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), + qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), + qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), + serial_hds[i]); + + s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD)); + + s->cm_base = 0x41300000; + s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ + s->clkcfg = 0x00000009; /* Turbo mode active */ + memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); + memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); + vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); + + pxa2xx_setup_cp14(s); + + s->mm_base = 0x48000000; + s->mm_regs[MDMRS >> 2] = 0x00020002; + s->mm_regs[MDREFR >> 2] = 0x03ca4000; + s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ + memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); + memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); + vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); + + s->pm_base = 0x40f00000; + memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); + memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); + vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); + + for (i = 0; pxa27x_ssp[i].io_base; i ++); + s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); + for (i = 0; pxa27x_ssp[i].io_base; i ++) { + DeviceState *dev; + dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base, + qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn)); + s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); + } + + if (usb_enabled(false)) { + sysbus_create_simple("sysbus-ohci", 0x4c000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); + } + + s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); + s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); + + sysbus_create_simple("pxa2xx_rtc", 0x40900000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); + + s->i2c[0] = pxa2xx_i2c_init(0x40301600, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff); + s->i2c[1] = pxa2xx_i2c_init(0x40f00100, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); + + s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), + qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), + qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); + + s->kp = pxa27x_keypad_init(address_space, 0x41500000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD)); + + /* GPIO1 resets the processor */ + /* The handler can be overridden by board-specific code */ + qdev_connect_gpio_out(s->gpio, 1, s->reset); + return s; +} + +/* Initialise a PXA255 integrated chip (ARM based core). */ +PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) +{ + PXA2xxState *s; + int i; + DriveInfo *dinfo; + + s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); + + s->cpu = cpu_arm_init("pxa255"); + if (s->cpu == NULL) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; + + /* SDRAM & Internal Memory Storage */ + memory_region_init_ram(&s->sdram, "pxa255.sdram", sdram_size); + vmstate_register_ram_global(&s->sdram); + memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); + memory_region_init_ram(&s->internal, "pxa255.internal", + PXA2XX_INTERNAL_SIZE); + vmstate_register_ram_global(&s->internal); + memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, + &s->internal); + + s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); + + s->dma = pxa255_dma_init(0x40000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); + + sysbus_create_varargs("pxa25x-timer", 0x40a00000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0), + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1), + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2), + qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), + NULL); + + s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85); + + dinfo = drive_get(IF_SD, 0, 0); + if (!dinfo) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC), + qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI), + qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI)); + + for (i = 0; pxa255_serial[i].io_base; i++) { + if (serial_hds[i]) { + serial_mm_init(address_space, pxa255_serial[i].io_base, 2, + qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn), + 14745600 / 16, serial_hds[i], + DEVICE_NATIVE_ENDIAN); + } else { + break; + } + } + if (serial_hds[i]) + s->fir = pxa2xx_fir_init(address_space, 0x40800000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), + qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), + qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), + serial_hds[i]); + + s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD)); + + s->cm_base = 0x41300000; + s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ + s->clkcfg = 0x00000009; /* Turbo mode active */ + memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); + memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); + vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); + + pxa2xx_setup_cp14(s); + + s->mm_base = 0x48000000; + s->mm_regs[MDMRS >> 2] = 0x00020002; + s->mm_regs[MDREFR >> 2] = 0x03ca4000; + s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ + memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); + memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); + vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); + + s->pm_base = 0x40f00000; + memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); + memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); + vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); + + for (i = 0; pxa255_ssp[i].io_base; i ++); + s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); + for (i = 0; pxa255_ssp[i].io_base; i ++) { + DeviceState *dev; + dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base, + qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn)); + s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); + } + + if (usb_enabled(false)) { + sysbus_create_simple("sysbus-ohci", 0x4c000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); + } + + s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); + s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); + + sysbus_create_simple("pxa2xx_rtc", 0x40900000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); + + s->i2c[0] = pxa2xx_i2c_init(0x40301600, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff); + s->i2c[1] = pxa2xx_i2c_init(0x40f00100, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); + + s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), + qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), + qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); + + /* GPIO1 resets the processor */ + /* The handler can be overridden by board-specific code */ + qdev_connect_gpio_out(s->gpio, 1, s->reset); + return s; +} + +static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pxa2xx_ssp_init; +} + +static const TypeInfo pxa2xx_ssp_info = { + .name = "pxa2xx-ssp", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxSSPState), + .class_init = pxa2xx_ssp_class_init, +}; + +static void pxa2xx_register_types(void) +{ + type_register_static(&pxa2xx_i2c_slave_info); + type_register_static(&pxa2xx_ssp_info); + type_register_static(&pxa2xx_i2c_info); + type_register_static(&pxa2xx_rtc_sysbus_info); +} + +type_init(pxa2xx_register_types) diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c new file mode 100644 index 0000000000..eef8411e86 --- /dev/null +++ b/hw/arm/pxa2xx_gpio.c @@ -0,0 +1,350 @@ +/* + * Intel XScale PXA255/270 GPIO controller emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPL. + */ + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/pxa.h" + +#define PXA2XX_GPIO_BANKS 4 + +typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo; +struct PXA2xxGPIOInfo { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq0, irq1, irqX; + int lines; + int ncpu; + ARMCPU *cpu; + + /* XXX: GNU C vectors are more suitable */ + uint32_t ilevel[PXA2XX_GPIO_BANKS]; + uint32_t olevel[PXA2XX_GPIO_BANKS]; + uint32_t dir[PXA2XX_GPIO_BANKS]; + uint32_t rising[PXA2XX_GPIO_BANKS]; + uint32_t falling[PXA2XX_GPIO_BANKS]; + uint32_t status[PXA2XX_GPIO_BANKS]; + uint32_t gpsr[PXA2XX_GPIO_BANKS]; + uint32_t gafr[PXA2XX_GPIO_BANKS * 2]; + + uint32_t prev_level[PXA2XX_GPIO_BANKS]; + qemu_irq handler[PXA2XX_GPIO_BANKS * 32]; + qemu_irq read_notify; +}; + +static struct { + enum { + GPIO_NONE, + GPLR, + GPSR, + GPCR, + GPDR, + GRER, + GFER, + GEDR, + GAFR_L, + GAFR_U, + } reg; + int bank; +} pxa2xx_gpio_regs[0x200] = { + [0 ... 0x1ff] = { GPIO_NONE, 0 }, +#define PXA2XX_REG(reg, a0, a1, a2, a3) \ + [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, + + PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100) + PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118) + PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124) + PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c) + PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130) + PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c) + PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148) + PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c) + PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070) +}; + +static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s) +{ + if (s->status[0] & (1 << 0)) + qemu_irq_raise(s->irq0); + else + qemu_irq_lower(s->irq0); + + if (s->status[0] & (1 << 1)) + qemu_irq_raise(s->irq1); + else + qemu_irq_lower(s->irq1); + + if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3]) + qemu_irq_raise(s->irqX); + else + qemu_irq_lower(s->irqX); +} + +/* Bitmap of pins used as standby and sleep wake-up sources. */ +static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { + 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f, +}; + +static void pxa2xx_gpio_set(void *opaque, int line, int level) +{ + PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; + int bank; + uint32_t mask; + + if (line >= s->lines) { + printf("%s: No GPIO pin %i\n", __FUNCTION__, line); + return; + } + + bank = line >> 5; + mask = 1 << (line & 31); + + if (level) { + s->status[bank] |= s->rising[bank] & mask & + ~s->ilevel[bank] & ~s->dir[bank]; + s->ilevel[bank] |= mask; + } else { + s->status[bank] |= s->falling[bank] & mask & + s->ilevel[bank] & ~s->dir[bank]; + s->ilevel[bank] &= ~mask; + } + + if (s->status[bank] & mask) + pxa2xx_gpio_irq_update(s); + + /* Wake-up GPIOs */ + if (s->cpu->env.halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + } +} + +static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) { + uint32_t level, diff; + int i, bit, line; + for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) { + level = s->olevel[i] & s->dir[i]; + + for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + line = bit + 32 * i; + qemu_set_irq(s->handler[line], (level >> bit) & 1); + } + + s->prev_level[i] = level; + } +} + +static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset, + unsigned size) +{ + PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; + uint32_t ret; + int bank; + if (offset >= 0x200) + return 0; + + bank = pxa2xx_gpio_regs[offset].bank; + switch (pxa2xx_gpio_regs[offset].reg) { + case GPDR: /* GPIO Pin-Direction registers */ + return s->dir[bank]; + + case GPSR: /* GPIO Pin-Output Set registers */ + printf("%s: Read from a write-only register " REG_FMT "\n", + __FUNCTION__, offset); + return s->gpsr[bank]; /* Return last written value. */ + + case GPCR: /* GPIO Pin-Output Clear registers */ + printf("%s: Read from a write-only register " REG_FMT "\n", + __FUNCTION__, offset); + return 31337; /* Specified as unpredictable in the docs. */ + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + return s->rising[bank]; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + return s->falling[bank]; + + case GAFR_L: /* GPIO Alternate Function registers */ + return s->gafr[bank * 2]; + + case GAFR_U: /* GPIO Alternate Function registers */ + return s->gafr[bank * 2 + 1]; + + case GPLR: /* GPIO Pin-Level registers */ + ret = (s->olevel[bank] & s->dir[bank]) | + (s->ilevel[bank] & ~s->dir[bank]); + qemu_irq_raise(s->read_notify); + return ret; + + case GEDR: /* GPIO Edge Detect Status registers */ + return s->status[bank]; + + default: + hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + } + + return 0; +} + +static void pxa2xx_gpio_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; + int bank; + if (offset >= 0x200) + return; + + bank = pxa2xx_gpio_regs[offset].bank; + switch (pxa2xx_gpio_regs[offset].reg) { + case GPDR: /* GPIO Pin-Direction registers */ + s->dir[bank] = value; + pxa2xx_gpio_handler_update(s); + break; + + case GPSR: /* GPIO Pin-Output Set registers */ + s->olevel[bank] |= value; + pxa2xx_gpio_handler_update(s); + s->gpsr[bank] = value; + break; + + case GPCR: /* GPIO Pin-Output Clear registers */ + s->olevel[bank] &= ~value; + pxa2xx_gpio_handler_update(s); + break; + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + s->rising[bank] = value; + break; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + s->falling[bank] = value; + break; + + case GAFR_L: /* GPIO Alternate Function registers */ + s->gafr[bank * 2] = value; + break; + + case GAFR_U: /* GPIO Alternate Function registers */ + s->gafr[bank * 2 + 1] = value; + break; + + case GEDR: /* GPIO Edge Detect Status registers */ + s->status[bank] &= ~value; + pxa2xx_gpio_irq_update(s); + break; + + default: + hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + } +} + +static const MemoryRegionOps pxa_gpio_ops = { + .read = pxa2xx_gpio_read, + .write = pxa2xx_gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +DeviceState *pxa2xx_gpio_init(hwaddr base, + ARMCPU *cpu, DeviceState *pic, int lines) +{ + CPUState *cs = CPU(cpu); + DeviceState *dev; + + dev = qdev_create(NULL, "pxa2xx-gpio"); + qdev_prop_set_int32(dev, "lines", lines); + qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); + qdev_init_nofail(dev); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0)); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, + qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1)); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, + qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X)); + + return dev; +} + +static int pxa2xx_gpio_initfn(SysBusDevice *dev) +{ + PXA2xxGPIOInfo *s; + + s = FROM_SYSBUS(PXA2xxGPIOInfo, dev); + + s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu)); + + qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines); + qdev_init_gpio_out(&dev->qdev, s->handler, s->lines); + + memory_region_init_io(&s->iomem, &pxa_gpio_ops, s, "pxa2xx-gpio", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + sysbus_init_irq(dev, &s->irq0); + sysbus_init_irq(dev, &s->irq1); + sysbus_init_irq(dev, &s->irqX); + + return 0; +} + +/* + * Registers a callback to notify on GPLR reads. This normally + * shouldn't be needed but it is used for the hack on Spitz machines. + */ +void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler) +{ + PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, SYS_BUS_DEVICE(dev)); + s->read_notify = handler; +} + +static const VMStateDescription vmstate_pxa2xx_gpio_regs = { + .name = "pxa2xx-gpio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32(lines, PXA2xxGPIOInfo), + VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), + VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), + VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), + VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), + VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), + VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), + VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2), + VMSTATE_END_OF_LIST(), + }, +}; + +static Property pxa2xx_gpio_properties[] = { + DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0), + DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_gpio_initfn; + dc->desc = "PXA2xx GPIO controller"; + dc->props = pxa2xx_gpio_properties; +} + +static const TypeInfo pxa2xx_gpio_info = { + .name = "pxa2xx-gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxGPIOInfo), + .class_init = pxa2xx_gpio_class_init, +}; + +static void pxa2xx_gpio_register_types(void) +{ + type_register_static(&pxa2xx_gpio_info); +} + +type_init(pxa2xx_gpio_register_types) diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c new file mode 100644 index 0000000000..145fc78c2f --- /dev/null +++ b/hw/arm/pxa2xx_pic.c @@ -0,0 +1,334 @@ +/* + * Intel XScale PXA Programmable Interrupt Controller. + * + * Copyright (c) 2006 Openedhand Ltd. + * Copyright (c) 2006 Thorsten Zitterell + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPL. + */ + +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/sysbus.h" + +#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ +#define ICMR 0x04 /* Interrupt Controller Mask register */ +#define ICLR 0x08 /* Interrupt Controller Level register */ +#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */ +#define ICPR 0x10 /* Interrupt Controller Pending register */ +#define ICCR 0x14 /* Interrupt Controller Control register */ +#define ICHP 0x18 /* Interrupt Controller Highest Priority register */ +#define IPR0 0x1c /* Interrupt Controller Priority register 0 */ +#define IPR31 0x98 /* Interrupt Controller Priority register 31 */ +#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */ +#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */ +#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */ +#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */ +#define ICPR2 0xac /* Interrupt Controller Pending register 2 */ +#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */ +#define IPR39 0xcc /* Interrupt Controller Priority register 39 */ + +#define PXA2XX_PIC_SRCS 40 + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + ARMCPU *cpu; + uint32_t int_enabled[2]; + uint32_t int_pending[2]; + uint32_t is_fiq[2]; + uint32_t int_idle; + uint32_t priority[PXA2XX_PIC_SRCS]; +} PXA2xxPICState; + +static void pxa2xx_pic_update(void *opaque) +{ + uint32_t mask[2]; + PXA2xxPICState *s = (PXA2xxPICState *) opaque; + + if (s->cpu->env.halted) { + mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); + mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); + if (mask[0] || mask[1]) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + } + } + + mask[0] = s->int_pending[0] & s->int_enabled[0]; + mask[1] = s->int_pending[1] & s->int_enabled[1]; + + if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + } else { + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + } + + if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + } +} + +/* Note: Here level means state of the signal on a pin, not + * IRQ/FIQ distinction as in PXA Developer Manual. */ +static void pxa2xx_pic_set_irq(void *opaque, int irq, int level) +{ + PXA2xxPICState *s = (PXA2xxPICState *) opaque; + int int_set = (irq >= 32); + irq &= 31; + + if (level) + s->int_pending[int_set] |= 1 << irq; + else + s->int_pending[int_set] &= ~(1 << irq); + + pxa2xx_pic_update(opaque); +} + +static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) { + int i, int_set, irq; + uint32_t bit, mask[2]; + uint32_t ichp = 0x003f003f; /* Both IDs invalid */ + + mask[0] = s->int_pending[0] & s->int_enabled[0]; + mask[1] = s->int_pending[1] & s->int_enabled[1]; + + for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) { + irq = s->priority[i] & 0x3f; + if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) { + /* Source peripheral ID is valid. */ + bit = 1 << (irq & 31); + int_set = (irq >= 32); + + if (mask[int_set] & bit & s->is_fiq[int_set]) { + /* FIQ asserted */ + ichp &= 0xffff0000; + ichp |= (1 << 15) | irq; + } + + if (mask[int_set] & bit & ~s->is_fiq[int_set]) { + /* IRQ asserted */ + ichp &= 0x0000ffff; + ichp |= (1 << 31) | (irq << 16); + } + } + } + + return ichp; +} + +static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset, + unsigned size) +{ + PXA2xxPICState *s = (PXA2xxPICState *) opaque; + + switch (offset) { + case ICIP: /* IRQ Pending register */ + return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0]; + case ICIP2: /* IRQ Pending register 2 */ + return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1]; + case ICMR: /* Mask register */ + return s->int_enabled[0]; + case ICMR2: /* Mask register 2 */ + return s->int_enabled[1]; + case ICLR: /* Level register */ + return s->is_fiq[0]; + case ICLR2: /* Level register 2 */ + return s->is_fiq[1]; + case ICCR: /* Idle mask */ + return (s->int_idle == 0); + case ICFP: /* FIQ Pending register */ + return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0]; + case ICFP2: /* FIQ Pending register 2 */ + return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1]; + case ICPR: /* Pending register */ + return s->int_pending[0]; + case ICPR2: /* Pending register 2 */ + return s->int_pending[1]; + case IPR0 ... IPR31: + return s->priority[0 + ((offset - IPR0 ) >> 2)]; + case IPR32 ... IPR39: + return s->priority[32 + ((offset - IPR32) >> 2)]; + case ICHP: /* Highest Priority register */ + return pxa2xx_pic_highest(s); + default: + printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); + return 0; + } +} + +static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PXA2xxPICState *s = (PXA2xxPICState *) opaque; + + switch (offset) { + case ICMR: /* Mask register */ + s->int_enabled[0] = value; + break; + case ICMR2: /* Mask register 2 */ + s->int_enabled[1] = value; + break; + case ICLR: /* Level register */ + s->is_fiq[0] = value; + break; + case ICLR2: /* Level register 2 */ + s->is_fiq[1] = value; + break; + case ICCR: /* Idle mask */ + s->int_idle = (value & 1) ? 0 : ~0; + break; + case IPR0 ... IPR31: + s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f; + break; + case IPR32 ... IPR39: + s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f; + break; + default: + printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); + return; + } + pxa2xx_pic_update(opaque); +} + +/* Interrupt Controller Coprocessor Space Register Mapping */ +static const int pxa2xx_cp_reg_map[0x10] = { + [0x0 ... 0xf] = -1, + [0x0] = ICIP, + [0x1] = ICMR, + [0x2] = ICLR, + [0x3] = ICFP, + [0x4] = ICPR, + [0x5] = ICHP, + [0x6] = ICIP2, + [0x7] = ICMR2, + [0x8] = ICLR2, + [0x9] = ICFP2, + [0xa] = ICPR2, +}; + +static int pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + int offset = pxa2xx_cp_reg_map[ri->crn]; + *value = pxa2xx_pic_mem_read(ri->opaque, offset, 4); + return 0; +} + +static int pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + int offset = pxa2xx_cp_reg_map[ri->crn]; + pxa2xx_pic_mem_write(ri->opaque, offset, value, 4); + return 0; +} + +#define REGINFO_FOR_PIC_CP(NAME, CRN) \ + { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \ + .access = PL1_RW, \ + .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write } + +static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { + REGINFO_FOR_PIC_CP("ICIP", 0), + REGINFO_FOR_PIC_CP("ICMR", 1), + REGINFO_FOR_PIC_CP("ICLR", 2), + REGINFO_FOR_PIC_CP("ICFP", 3), + REGINFO_FOR_PIC_CP("ICPR", 4), + REGINFO_FOR_PIC_CP("ICHP", 5), + REGINFO_FOR_PIC_CP("ICIP2", 6), + REGINFO_FOR_PIC_CP("ICMR2", 7), + REGINFO_FOR_PIC_CP("ICLR2", 8), + REGINFO_FOR_PIC_CP("ICFP2", 9), + REGINFO_FOR_PIC_CP("ICPR2", 0xa), + REGINFO_SENTINEL +}; + +static const MemoryRegionOps pxa2xx_pic_ops = { + .read = pxa2xx_pic_mem_read, + .write = pxa2xx_pic_mem_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int pxa2xx_pic_post_load(void *opaque, int version_id) +{ + pxa2xx_pic_update(opaque); + return 0; +} + +DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) +{ + CPUARMState *env = &cpu->env; + DeviceState *dev = qdev_create(NULL, "pxa2xx_pic"); + PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, SYS_BUS_DEVICE(dev)); + + s->cpu = cpu; + + s->int_pending[0] = 0; + s->int_pending[1] = 0; + s->int_enabled[0] = 0; + s->int_enabled[1] = 0; + s->is_fiq[0] = 0; + s->is_fiq[1] = 0; + + qdev_init_nofail(dev); + + qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS); + + /* Enable IC memory-mapped registers access. */ + memory_region_init_io(&s->iomem, &pxa2xx_pic_ops, s, + "pxa2xx-pic", 0x00100000); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + + /* Enable IC coprocessor access. */ + define_arm_cp_regs_with_opaque(arm_env_get_cpu(env), pxa_pic_cp_reginfo, s); + + return dev; +} + +static VMStateDescription vmstate_pxa2xx_pic_regs = { + .name = "pxa2xx_pic", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = pxa2xx_pic_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2), + VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2), + VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2), + VMSTATE_UINT32(int_idle, PXA2xxPICState), + VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS), + VMSTATE_END_OF_LIST(), + }, +}; + +static int pxa2xx_pic_initfn(SysBusDevice *dev) +{ + return 0; +} + +static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_pic_initfn; + dc->desc = "PXA2xx PIC"; + dc->vmsd = &vmstate_pxa2xx_pic_regs; +} + +static const TypeInfo pxa2xx_pic_info = { + .name = "pxa2xx_pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxPICState), + .class_init = pxa2xx_pic_class_init, +}; + +static void pxa2xx_pic_register_types(void) +{ + type_register_static(&pxa2xx_pic_info); +} + +type_init(pxa2xx_pic_register_types) diff --git a/hw/armv7m.c b/hw/armv7m.c deleted file mode 100644 index 1d5bb592c4..0000000000 --- a/hw/armv7m.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ARMV7M System emulation. - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "hw/loader.h" -#include "elf.h" - -/* Bitbanded IO. Each word corresponds to a single bit. */ - -/* Get the byte address of the real memory for a bitband access. */ -static inline uint32_t bitband_addr(void * opaque, uint32_t addr) -{ - uint32_t res; - - res = *(uint32_t *)opaque; - res |= (addr & 0x1ffffff) >> 5; - return res; - -} - -static uint32_t bitband_readb(void *opaque, hwaddr offset) -{ - uint8_t v; - cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1); - return (v & (1 << ((offset >> 2) & 7))) != 0; -} - -static void bitband_writeb(void *opaque, hwaddr offset, - uint32_t value) -{ - uint32_t addr; - uint8_t mask; - uint8_t v; - addr = bitband_addr(opaque, offset); - mask = (1 << ((offset >> 2) & 7)); - cpu_physical_memory_read(addr, &v, 1); - if (value & 1) - v |= mask; - else - v &= ~mask; - cpu_physical_memory_write(addr, &v, 1); -} - -static uint32_t bitband_readw(void *opaque, hwaddr offset) -{ - uint32_t addr; - uint16_t mask; - uint16_t v; - addr = bitband_addr(opaque, offset) & ~1; - mask = (1 << ((offset >> 2) & 15)); - mask = tswap16(mask); - cpu_physical_memory_read(addr, (uint8_t *)&v, 2); - return (v & mask) != 0; -} - -static void bitband_writew(void *opaque, hwaddr offset, - uint32_t value) -{ - uint32_t addr; - uint16_t mask; - uint16_t v; - addr = bitband_addr(opaque, offset) & ~1; - mask = (1 << ((offset >> 2) & 15)); - mask = tswap16(mask); - cpu_physical_memory_read(addr, (uint8_t *)&v, 2); - if (value & 1) - v |= mask; - else - v &= ~mask; - cpu_physical_memory_write(addr, (uint8_t *)&v, 2); -} - -static uint32_t bitband_readl(void *opaque, hwaddr offset) -{ - uint32_t addr; - uint32_t mask; - uint32_t v; - addr = bitband_addr(opaque, offset) & ~3; - mask = (1 << ((offset >> 2) & 31)); - mask = tswap32(mask); - cpu_physical_memory_read(addr, (uint8_t *)&v, 4); - return (v & mask) != 0; -} - -static void bitband_writel(void *opaque, hwaddr offset, - uint32_t value) -{ - uint32_t addr; - uint32_t mask; - uint32_t v; - addr = bitband_addr(opaque, offset) & ~3; - mask = (1 << ((offset >> 2) & 31)); - mask = tswap32(mask); - cpu_physical_memory_read(addr, (uint8_t *)&v, 4); - if (value & 1) - v |= mask; - else - v &= ~mask; - cpu_physical_memory_write(addr, (uint8_t *)&v, 4); -} - -static const MemoryRegionOps bitband_ops = { - .old_mmio = { - .read = { bitband_readb, bitband_readw, bitband_readl, }, - .write = { bitband_writeb, bitband_writew, bitband_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t base; -} BitBandState; - -static int bitband_init(SysBusDevice *dev) -{ - BitBandState *s = FROM_SYSBUS(BitBandState, dev); - - memory_region_init_io(&s->iomem, &bitband_ops, &s->base, "bitband", - 0x02000000); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static void armv7m_bitband_init(void) -{ - DeviceState *dev; - - dev = qdev_create(NULL, "ARM,bitband-memory"); - qdev_prop_set_uint32(dev, "base", 0x20000000); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000); - - dev = qdev_create(NULL, "ARM,bitband-memory"); - qdev_prop_set_uint32(dev, "base", 0x40000000); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000); -} - -/* Board init. */ - -static void armv7m_reset(void *opaque) -{ - ARMCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -/* Init CPU and memory for a v7-M based board. - flash_size and sram_size are in kb. - Returns the NVIC array. */ - -qemu_irq *armv7m_init(MemoryRegion *address_space_mem, - int flash_size, int sram_size, - const char *kernel_filename, const char *cpu_model) -{ - ARMCPU *cpu; - CPUARMState *env; - DeviceState *nvic; - /* FIXME: make this local state. */ - static qemu_irq pic[64]; - qemu_irq *cpu_pic; - int image_size; - uint64_t entry; - uint64_t lowaddr; - int i; - int big_endian; - MemoryRegion *sram = g_new(MemoryRegion, 1); - MemoryRegion *flash = g_new(MemoryRegion, 1); - MemoryRegion *hack = g_new(MemoryRegion, 1); - - flash_size *= 1024; - sram_size *= 1024; - - if (cpu_model == NULL) { - cpu_model = "cortex-m3"; - } - cpu = cpu_arm_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - -#if 0 - /* > 32Mb SRAM gets complicated because it overlaps the bitband area. - We don't have proper commandline options, so allocate half of memory - as SRAM, up to a maximum of 32Mb, and the rest as code. */ - if (ram_size > (512 + 32) * 1024 * 1024) - ram_size = (512 + 32) * 1024 * 1024; - sram_size = (ram_size / 2) & TARGET_PAGE_MASK; - if (sram_size > 32 * 1024 * 1024) - sram_size = 32 * 1024 * 1024; - code_size = ram_size - sram_size; -#endif - - /* Flash programming is done via the SCU, so pretend it is ROM. */ - memory_region_init_ram(flash, "armv7m.flash", flash_size); - vmstate_register_ram_global(flash); - memory_region_set_readonly(flash, true); - memory_region_add_subregion(address_space_mem, 0, flash); - memory_region_init_ram(sram, "armv7m.sram", sram_size); - vmstate_register_ram_global(sram); - memory_region_add_subregion(address_space_mem, 0x20000000, sram); - armv7m_bitband_init(); - - nvic = qdev_create(NULL, "armv7m_nvic"); - env->nvic = nvic; - qdev_init_nofail(nvic); - cpu_pic = arm_pic_init_cpu(cpu); - sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); - for (i = 0; i < 64; i++) { - pic[i] = qdev_get_gpio_in(nvic, i); - } - -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - - if (!kernel_filename) { - fprintf(stderr, "Guest image must be specified (using -kernel)\n"); - exit(1); - } - - image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr, - NULL, big_endian, ELF_MACHINE, 1); - if (image_size < 0) { - image_size = load_image_targphys(kernel_filename, 0, flash_size); - lowaddr = 0; - } - if (image_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* Hack to map an additional page of ram at the top of the address - space. This stops qemu complaining about executing code outside RAM - when returning from an exception. */ - memory_region_init_ram(hack, "armv7m.hack", 0x1000); - vmstate_register_ram_global(hack); - memory_region_add_subregion(address_space_mem, 0xfffff000, hack); - - qemu_register_reset(armv7m_reset, cpu); - return pic; -} - -static Property bitband_properties[] = { - DEFINE_PROP_UINT32("base", BitBandState, base, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void bitband_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = bitband_init; - dc->props = bitband_properties; -} - -static const TypeInfo bitband_info = { - .name = "ARM,bitband-memory", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(BitBandState), - .class_init = bitband_class_init, -}; - -static void armv7m_register_types(void) -{ - type_register_static(&bitband_info); -} - -type_init(armv7m_register_types) diff --git a/hw/exynos4210.c b/hw/exynos4210.c deleted file mode 100644 index 4592514bb2..0000000000 --- a/hw/exynos4210.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Samsung exynos4210 SoC emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. - * Maksim Kozlov - * Evgeny Voevodin - * Igor Mitsyanko - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - */ - -#include "hw/boards.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "hw/arm-misc.h" -#include "hw/loader.h" -#include "hw/exynos4210.h" -#include "hw/usb/hcd-ehci.h" - -#define EXYNOS4210_CHIPID_ADDR 0x10000000 - -/* PWM */ -#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000 - -/* RTC */ -#define EXYNOS4210_RTC_BASE_ADDR 0x10070000 - -/* MCT */ -#define EXYNOS4210_MCT_BASE_ADDR 0x10050000 - -/* I2C */ -#define EXYNOS4210_I2C_SHIFT 0x00010000 -#define EXYNOS4210_I2C_BASE_ADDR 0x13860000 -/* Interrupt Group of External Interrupt Combiner for I2C */ -#define EXYNOS4210_I2C_INTG 27 -#define EXYNOS4210_HDMI_INTG 16 - -/* UART's definitions */ -#define EXYNOS4210_UART0_BASE_ADDR 0x13800000 -#define EXYNOS4210_UART1_BASE_ADDR 0x13810000 -#define EXYNOS4210_UART2_BASE_ADDR 0x13820000 -#define EXYNOS4210_UART3_BASE_ADDR 0x13830000 -#define EXYNOS4210_UART0_FIFO_SIZE 256 -#define EXYNOS4210_UART1_FIFO_SIZE 64 -#define EXYNOS4210_UART2_FIFO_SIZE 16 -#define EXYNOS4210_UART3_FIFO_SIZE 16 -/* Interrupt Group of External Interrupt Combiner for UART */ -#define EXYNOS4210_UART_INT_GRP 26 - -/* External GIC */ -#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000 -#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000 - -/* Combiner */ -#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000 -#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000 - -/* PMU SFR base address */ -#define EXYNOS4210_PMU_BASE_ADDR 0x10020000 - -/* Display controllers (FIMD) */ -#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 - -/* EHCI */ -#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000 - -static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, - 0x09, 0x00, 0x00, 0x00 }; - -void exynos4210_write_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - int n; - uint32_t smpboot[] = { - 0xe59f3034, /* ldr r3, External gic_cpu_if */ - 0xe59f2034, /* ldr r2, Internal gic_cpu_if */ - 0xe59f0034, /* ldr r0, startaddr */ - 0xe3a01001, /* mov r1, #1 */ - 0xe5821000, /* str r1, [r2] */ - 0xe5831000, /* str r1, [r3] */ - 0xe3a010ff, /* mov r1, #0xff */ - 0xe5821004, /* str r1, [r2, #4] */ - 0xe5831004, /* str r1, [r3, #4] */ - 0xf57ff04f, /* dsb */ - 0xe320f003, /* wfi */ - 0xe5901000, /* ldr r1, [r0] */ - 0xe1110001, /* tst r1, r1 */ - 0x0afffffb, /* beq */ - 0xe12fff11, /* bx r1 */ - EXYNOS4210_EXT_GIC_CPU_BASE_ADDR, - 0, /* gic_cpu_if: base address of Internal GIC CPU interface */ - 0 /* bootreg: Boot register address is held here */ - }; - smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; - smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; - for (n = 0; n < ARRAY_SIZE(smpboot); n++) { - smpboot[n] = tswap32(smpboot[n]); - } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); -} - -Exynos4210State *exynos4210_init(MemoryRegion *system_mem, - unsigned long ram_size) -{ - qemu_irq cpu_irq[EXYNOS4210_NCPUS]; - int i, n; - Exynos4210State *s = g_new(Exynos4210State, 1); - qemu_irq *irqp; - qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; - unsigned long mem_size; - DeviceState *dev; - SysBusDevice *busdev; - - for (n = 0; n < EXYNOS4210_NCPUS; n++) { - s->cpu[n] = cpu_arm_init("cortex-a9"); - if (!s->cpu[n]) { - fprintf(stderr, "Unable to find CPU %d definition\n", n); - exit(1); - } - - /* Create PIC controller for each processor instance */ - irqp = arm_pic_init_cpu(s->cpu[n]); - - /* - * Get GICs gpio_in cpu_irq to connect a combiner to them later. - * Use only IRQ for a while. - */ - cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; - } - - /*** IRQs ***/ - - s->irq_table = exynos4210_init_irq(&s->irqs); - - /* IRQ Gate */ - for (i = 0; i < EXYNOS4210_NCPUS; i++) { - dev = qdev_create(NULL, "exynos4210.irq_gate"); - qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); - qdev_init_nofail(dev); - /* Get IRQ Gate input in gate_irq */ - for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { - gate_irq[i][n] = qdev_get_gpio_in(dev, n); - } - busdev = SYS_BUS_DEVICE(dev); - - /* Connect IRQ Gate output to cpu_irq */ - sysbus_connect_irq(busdev, 0, cpu_irq[i]); - } - - /* Private memory region and Internal GIC */ - dev = qdev_create(NULL, "a9mpcore_priv"); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); - for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][0]); - } - for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) { - s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n); - } - - /* Cache controller */ - sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL); - - /* External GIC */ - dev = qdev_create(NULL, "exynos4210.gic"); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - /* Map CPU interface */ - sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); - /* Map Distributer interface */ - sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR); - for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][1]); - } - for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) { - s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n); - } - - /* Internal Interrupt Combiner */ - dev = qdev_create(NULL, "exynos4210.combiner"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); - } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 0); - sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR); - - /* External Interrupt Combiner */ - dev = qdev_create(NULL, "exynos4210.combiner"); - qdev_prop_set_uint32(dev, "external", 1); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); - } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 1); - sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR); - - /* Initialize board IRQs. */ - exynos4210_init_board_irqs(&s->irqs); - - /*** Memory ***/ - - /* Chip-ID and OMR */ - memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid", - sizeof(chipid_and_omr), chipid_and_omr); - memory_region_set_readonly(&s->chipid_mem, true); - memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR, - &s->chipid_mem); - - /* Internal ROM */ - memory_region_init_ram(&s->irom_mem, "exynos4210.irom", - EXYNOS4210_IROM_SIZE); - memory_region_set_readonly(&s->irom_mem, true); - memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR, - &s->irom_mem); - /* mirror of iROM */ - memory_region_init_alias(&s->irom_alias_mem, "exynos4210.irom_alias", - &s->irom_mem, - 0, - EXYNOS4210_IROM_SIZE); - memory_region_set_readonly(&s->irom_alias_mem, true); - memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR, - &s->irom_alias_mem); - - /* Internal RAM */ - memory_region_init_ram(&s->iram_mem, "exynos4210.iram", - EXYNOS4210_IRAM_SIZE); - vmstate_register_ram_global(&s->iram_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR, - &s->iram_mem); - - /* DRAM */ - mem_size = ram_size; - if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { - memory_region_init_ram(&s->dram1_mem, "exynos4210.dram1", - mem_size - EXYNOS4210_DRAM_MAX_SIZE); - vmstate_register_ram_global(&s->dram1_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, - &s->dram1_mem); - mem_size = EXYNOS4210_DRAM_MAX_SIZE; - } - memory_region_init_ram(&s->dram0_mem, "exynos4210.dram0", mem_size); - vmstate_register_ram_global(&s->dram0_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, - &s->dram0_mem); - - /* PMU. - * The only reason of existence at the moment is that secondary CPU boot - * loader uses PMU INFORM5 register as a holding pen. - */ - sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL); - - /* PWM */ - sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR, - s->irq_table[exynos4210_get_irq(22, 0)], - s->irq_table[exynos4210_get_irq(22, 1)], - s->irq_table[exynos4210_get_irq(22, 2)], - s->irq_table[exynos4210_get_irq(22, 3)], - s->irq_table[exynos4210_get_irq(22, 4)], - NULL); - /* RTC */ - sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR, - s->irq_table[exynos4210_get_irq(23, 0)], - s->irq_table[exynos4210_get_irq(23, 1)], - NULL); - - /* Multi Core Timer */ - dev = qdev_create(NULL, "exynos4210.mct"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - for (n = 0; n < 4; n++) { - /* Connect global timer interrupts to Combiner gpio_in */ - sysbus_connect_irq(busdev, n, - s->irq_table[exynos4210_get_irq(1, 4 + n)]); - } - /* Connect local timer interrupts to Combiner gpio_in */ - sysbus_connect_irq(busdev, 4, - s->irq_table[exynos4210_get_irq(51, 0)]); - sysbus_connect_irq(busdev, 5, - s->irq_table[exynos4210_get_irq(35, 3)]); - sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR); - - /*** I2C ***/ - for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) { - uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n; - qemu_irq i2c_irq; - - if (n < 8) { - i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)]; - } else { - i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)]; - } - - dev = qdev_create(NULL, "exynos4210.i2c"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, i2c_irq); - sysbus_mmio_map(busdev, 0, addr); - s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); - } - - - /*** UARTs ***/ - exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR, - EXYNOS4210_UART0_FIFO_SIZE, 0, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]); - - exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR, - EXYNOS4210_UART1_FIFO_SIZE, 1, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]); - - exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR, - EXYNOS4210_UART2_FIFO_SIZE, 2, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]); - - exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR, - EXYNOS4210_UART3_FIFO_SIZE, 3, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]); - - /*** Display controller (FIMD) ***/ - sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR, - s->irq_table[exynos4210_get_irq(11, 0)], - s->irq_table[exynos4210_get_irq(11, 1)], - s->irq_table[exynos4210_get_irq(11, 2)], - NULL); - - sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR, - s->irq_table[exynos4210_get_irq(28, 3)]); - - return s; -} diff --git a/hw/omap1.c b/hw/omap1.c deleted file mode 100644 index 6f0a8ca074..0000000000 --- a/hw/omap1.c +++ /dev/null @@ -1,4056 +0,0 @@ -/* - * TI OMAP processors emulation. - * - * Copyright (C) 2006-2008 Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "hw/hw.h" -#include "hw/arm-misc.h" -#include "hw/omap.h" -#include "sysemu/sysemu.h" -#include "hw/soc_dma.h" -#include "sysemu/blockdev.h" -#include "qemu/range.h" -#include "hw/sysbus.h" - -/* Should signal the TCMI/GPMC */ -uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) -{ - uint8_t ret; - - OMAP_8B_REG(addr); - cpu_physical_memory_read(addr, (void *) &ret, 1); - return ret; -} - -void omap_badwidth_write8(void *opaque, hwaddr addr, - uint32_t value) -{ - uint8_t val8 = value; - - OMAP_8B_REG(addr); - cpu_physical_memory_write(addr, (void *) &val8, 1); -} - -uint32_t omap_badwidth_read16(void *opaque, hwaddr addr) -{ - uint16_t ret; - - OMAP_16B_REG(addr); - cpu_physical_memory_read(addr, (void *) &ret, 2); - return ret; -} - -void omap_badwidth_write16(void *opaque, hwaddr addr, - uint32_t value) -{ - uint16_t val16 = value; - - OMAP_16B_REG(addr); - cpu_physical_memory_write(addr, (void *) &val16, 2); -} - -uint32_t omap_badwidth_read32(void *opaque, hwaddr addr) -{ - uint32_t ret; - - OMAP_32B_REG(addr); - cpu_physical_memory_read(addr, (void *) &ret, 4); - return ret; -} - -void omap_badwidth_write32(void *opaque, hwaddr addr, - uint32_t value) -{ - OMAP_32B_REG(addr); - cpu_physical_memory_write(addr, (void *) &value, 4); -} - -/* MPU OS timers */ -struct omap_mpu_timer_s { - MemoryRegion iomem; - qemu_irq irq; - omap_clk clk; - uint32_t val; - int64_t time; - QEMUTimer *timer; - QEMUBH *tick; - int64_t rate; - int it_ena; - - int enable; - int ptv; - int ar; - int st; - uint32_t reset_val; -}; - -static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) -{ - uint64_t distance = qemu_get_clock_ns(vm_clock) - timer->time; - - if (timer->st && timer->enable && timer->rate) - return timer->val - muldiv64(distance >> (timer->ptv + 1), - timer->rate, get_ticks_per_sec()); - else - return timer->val; -} - -static inline void omap_timer_sync(struct omap_mpu_timer_s *timer) -{ - timer->val = omap_timer_read(timer); - timer->time = qemu_get_clock_ns(vm_clock); -} - -static inline void omap_timer_update(struct omap_mpu_timer_s *timer) -{ - int64_t expires; - - if (timer->enable && timer->st && timer->rate) { - timer->val = timer->reset_val; /* Should skip this on clk enable */ - expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1), - get_ticks_per_sec(), timer->rate); - - /* If timer expiry would be sooner than in about 1 ms and - * auto-reload isn't set, then fire immediately. This is a hack - * to make systems like PalmOS run in acceptable time. PalmOS - * sets the interval to a very low value and polls the status bit - * in a busy loop when it wants to sleep just a couple of CPU - * ticks. */ - if (expires > (get_ticks_per_sec() >> 10) || timer->ar) - qemu_mod_timer(timer->timer, timer->time + expires); - else - qemu_bh_schedule(timer->tick); - } else - qemu_del_timer(timer->timer); -} - -static void omap_timer_fire(void *opaque) -{ - struct omap_mpu_timer_s *timer = opaque; - - if (!timer->ar) { - timer->val = 0; - timer->st = 0; - } - - if (timer->it_ena) - /* Edge-triggered irq */ - qemu_irq_pulse(timer->irq); -} - -static void omap_timer_tick(void *opaque) -{ - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; - - omap_timer_sync(timer); - omap_timer_fire(timer); - omap_timer_update(timer); -} - -static void omap_timer_clk_update(void *opaque, int line, int on) -{ - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; - - omap_timer_sync(timer); - timer->rate = on ? omap_clk_getrate(timer->clk) : 0; - omap_timer_update(timer); -} - -static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) -{ - omap_clk_adduser(timer->clk, - qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]); - timer->rate = omap_clk_getrate(timer->clk); -} - -static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; - - case 0x04: /* LOAD_TIM */ - break; - - case 0x08: /* READ_TIM */ - return omap_timer_read(s); - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpu_timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - omap_timer_sync(s); - s->enable = (value >> 5) & 1; - s->ptv = (value >> 2) & 7; - s->ar = (value >> 1) & 1; - s->st = value & 1; - omap_timer_update(s); - return; - - case 0x04: /* LOAD_TIM */ - s->reset_val = value; - return; - - case 0x08: /* READ_TIM */ - OMAP_RO_REG(addr); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_mpu_timer_ops = { - .read = omap_mpu_timer_read, - .write = omap_mpu_timer_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) -{ - qemu_del_timer(s->timer); - s->enable = 0; - s->reset_val = 31337; - s->val = 0; - s->ptv = 0; - s->ar = 0; - s->st = 0; - s->it_ena = 1; -} - -static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq irq, omap_clk clk) -{ - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) - g_malloc0(sizeof(struct omap_mpu_timer_s)); - - s->irq = irq; - s->clk = clk; - s->timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, s); - s->tick = qemu_bh_new(omap_timer_fire, s); - omap_mpu_timer_reset(s); - omap_timer_clk_setup(s); - - memory_region_init_io(&s->iomem, &omap_mpu_timer_ops, s, - "omap-mpu-timer", 0x100); - - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -/* Watchdog timer */ -struct omap_watchdog_timer_s { - struct omap_mpu_timer_s timer; - MemoryRegion iomem; - uint8_t last_wr; - int mode; - int free; - int reset; -}; - -static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - return (s->timer.ptv << 9) | (s->timer.ar << 8) | - (s->timer.st << 7) | (s->free << 1); - - case 0x04: /* READ_TIMER */ - return omap_timer_read(&s->timer); - - case 0x08: /* TIMER_MODE */ - return s->mode << 15; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_wd_timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - omap_timer_sync(&s->timer); - s->timer.ptv = (value >> 9) & 7; - s->timer.ar = (value >> 8) & 1; - s->timer.st = (value >> 7) & 1; - s->free = (value >> 1) & 1; - omap_timer_update(&s->timer); - break; - - case 0x04: /* LOAD_TIMER */ - s->timer.reset_val = value & 0xffff; - break; - - case 0x08: /* TIMER_MODE */ - if (!s->mode && ((value >> 15) & 1)) - omap_clk_get(s->timer.clk); - s->mode |= (value >> 15) & 1; - if (s->last_wr == 0xf5) { - if ((value & 0xff) == 0xa0) { - if (s->mode) { - s->mode = 0; - omap_clk_put(s->timer.clk); - } - } else { - /* XXX: on T|E hardware somehow this has no effect, - * on Zire 71 it works as specified. */ - s->reset = 1; - qemu_system_reset_request(); - } - } - s->last_wr = value & 0xff; - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_wd_timer_ops = { - .read = omap_wd_timer_read, - .write = omap_wd_timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) -{ - qemu_del_timer(s->timer.timer); - if (!s->mode) - omap_clk_get(s->timer.clk); - s->mode = 1; - s->free = 1; - s->reset = 0; - s->timer.enable = 1; - s->timer.it_ena = 1; - s->timer.reset_val = 0xffff; - s->timer.val = 0; - s->timer.st = 0; - s->timer.ptv = 0; - s->timer.ar = 0; - omap_timer_update(&s->timer); -} - -static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory, - hwaddr base, - qemu_irq irq, omap_clk clk) -{ - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) - g_malloc0(sizeof(struct omap_watchdog_timer_s)); - - s->timer.irq = irq; - s->timer.clk = clk; - s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer); - omap_wd_timer_reset(s); - omap_timer_clk_setup(&s->timer); - - memory_region_init_io(&s->iomem, &omap_wd_timer_ops, s, - "omap-wd-timer", 0x100); - memory_region_add_subregion(memory, base, &s->iomem); - - return s; -} - -/* 32-kHz timer */ -struct omap_32khz_timer_s { - struct omap_mpu_timer_s timer; - MemoryRegion iomem; -}; - -static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (offset) { - case 0x00: /* TVR */ - return s->timer.reset_val; - - case 0x04: /* TCR */ - return omap_timer_read(&s->timer); - - case 0x08: /* CR */ - return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; - - default: - break; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_os_timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (offset) { - case 0x00: /* TVR */ - s->timer.reset_val = value & 0x00ffffff; - break; - - case 0x04: /* TCR */ - OMAP_RO_REG(addr); - break; - - case 0x08: /* CR */ - s->timer.ar = (value >> 3) & 1; - s->timer.it_ena = (value >> 2) & 1; - if (s->timer.st != (value & 1) || (value & 2)) { - omap_timer_sync(&s->timer); - s->timer.enable = value & 1; - s->timer.st = value & 1; - omap_timer_update(&s->timer); - } - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_os_timer_ops = { - .read = omap_os_timer_read, - .write = omap_os_timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_os_timer_reset(struct omap_32khz_timer_s *s) -{ - qemu_del_timer(s->timer.timer); - s->timer.enable = 0; - s->timer.it_ena = 0; - s->timer.reset_val = 0x00ffffff; - s->timer.val = 0; - s->timer.st = 0; - s->timer.ptv = 0; - s->timer.ar = 1; -} - -static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, - hwaddr base, - qemu_irq irq, omap_clk clk) -{ - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) - g_malloc0(sizeof(struct omap_32khz_timer_s)); - - s->timer.irq = irq; - s->timer.clk = clk; - s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer); - omap_os_timer_reset(s); - omap_timer_clk_setup(&s->timer); - - memory_region_init_io(&s->iomem, &omap_os_timer_ops, s, - "omap-os-timer", 0x800); - memory_region_add_subregion(memory, base, &s->iomem); - - return s; -} - -/* Ultra Low-Power Device Module */ -static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint16_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x14: /* IT_STATUS */ - ret = s->ulpd_pm_regs[addr >> 2]; - s->ulpd_pm_regs[addr >> 2] = 0; - qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); - return ret; - - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ - OMAP_BAD_REG(addr); - /* fall through */ - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x10: /* GAUGING_CTRL */ - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x30: /* CLOCK_CTRL */ - case 0x34: /* SOFT_REQ */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x3c: /* DPLL_CTRL */ - case 0x40: /* STATUS_REQ */ - /* XXX: check clk::usecount state for every clock */ - case 0x48: /* LOCL_TIME */ - case 0x4c: /* APLL_CTRL */ - case 0x50: /* POWER_CTRL */ - return s->ulpd_pm_regs[addr >> 2]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - if (diff & (1 << 4)) /* USB_MCLK_EN */ - omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); - if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ - omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1); -} - -static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ - omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); - if (diff & (1 << 1)) /* SOFT_COM_REQ */ - omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); - if (diff & (1 << 2)) /* SOFT_SDW_REQ */ - omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); - if (diff & (1 << 3)) /* SOFT_USB_REQ */ - omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); -} - -static void omap_ulpd_pm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int64_t now, ticks; - int div, mult; - static const int bypass_div[4] = { 1, 2, 4, 4 }; - uint16_t diff; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x14: /* IT_STATUS */ - case 0x40: /* STATUS_REQ */ - OMAP_RO_REG(addr); - break; - - case 0x10: /* GAUGING_CTRL */ - /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ - if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) { - now = qemu_get_clock_ns(vm_clock); - - if (value & 1) - s->ulpd_gauge_start = now; - else { - now -= s->ulpd_gauge_start; - - /* 32-kHz ticks */ - ticks = muldiv64(now, 32768, get_ticks_per_sec()); - s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; - s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_32K */ - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; - - /* High frequency ticks */ - ticks = muldiv64(now, 12000000, get_ticks_per_sec()); - s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; - s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_HI_FREQ */ - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; - - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ - qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); - } - } - s->ulpd_pm_regs[addr >> 2] = value; - break; - - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ - OMAP_BAD_REG(addr); - /* fall through */ - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x48: /* LOCL_TIME */ - case 0x50: /* POWER_CTRL */ - s->ulpd_pm_regs[addr >> 2] = value; - break; - - case 0x30: /* CLOCK_CTRL */ - diff = s->ulpd_pm_regs[addr >> 2] ^ value; - s->ulpd_pm_regs[addr >> 2] = value & 0x3f; - omap_ulpd_clk_update(s, diff, value); - break; - - case 0x34: /* SOFT_REQ */ - diff = s->ulpd_pm_regs[addr >> 2] ^ value; - s->ulpd_pm_regs[addr >> 2] = value & 0x1f; - omap_ulpd_req_update(s, diff, value); - break; - - case 0x3c: /* DPLL_CTRL */ - /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is - * omitted altogether, probably a typo. */ - /* This register has identical semantics with DPLL(1:3) control - * registers, see omap_dpll_write() */ - diff = s->ulpd_pm_regs[addr >> 2] & value; - s->ulpd_pm_regs[addr >> 2] = value & 0x2fff; - if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ - } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ - mult = 1; - } - omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult); - } - - /* Enter the desired mode. */ - s->ulpd_pm_regs[addr >> 2] = - (s->ulpd_pm_regs[addr >> 2] & 0xfffe) | - ((s->ulpd_pm_regs[addr >> 2] >> 4) & 1); - - /* Act as if the lock is restored. */ - s->ulpd_pm_regs[addr >> 2] |= 2; - break; - - case 0x4c: /* APLL_CTRL */ - diff = s->ulpd_pm_regs[addr >> 2] & value; - s->ulpd_pm_regs[addr >> 2] = value & 0xf; - if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ - omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s, - (value & (1 << 0)) ? "apll" : "dpll4")); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_ulpd_pm_ops = { - .read = omap_ulpd_pm_read, - .write = omap_ulpd_pm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) -{ - mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x18 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x1c >> 2] = 0x01; - mpu->ulpd_pm_regs[0x20 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff; - mpu->ulpd_pm_regs[0x28 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x2c >> 2] = 0x01; - omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000); - mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000; - omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000); - mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211; - mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */ - mpu->ulpd_pm_regs[0x48 >> 2] = 0x960; - mpu->ulpd_pm_regs[0x4c >> 2] = 0x08; - mpu->ulpd_pm_regs[0x50 >> 2] = 0x08; - omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4); - omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4")); -} - -static void omap_ulpd_pm_init(MemoryRegion *system_memory, - hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->ulpd_pm_iomem, &omap_ulpd_pm_ops, mpu, - "omap-ulpd-pm", 0x800); - memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem); - omap_ulpd_pm_reset(mpu); -} - -/* OMAP Pin Configuration */ -static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* FUNC_MUX_CTRL_0 */ - case 0x04: /* FUNC_MUX_CTRL_1 */ - case 0x08: /* FUNC_MUX_CTRL_2 */ - return s->func_mux_ctrl[addr >> 2]; - - case 0x0c: /* COMP_MODE_CTRL_0 */ - return s->comp_mode_ctrl[0]; - - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ - return s->func_mux_ctrl[(addr >> 2) - 1]; - - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ - return s->pull_dwn_ctrl[(addr & 0xf) >> 2]; - - case 0x50: /* GATE_INH_CTRL_0 */ - return s->gate_inh_ctrl[0]; - - case 0x60: /* VOLTAGE_CTRL_0 */ - return s->voltage_ctrl[0]; - - case 0x70: /* TEST_DBG_CTRL_0 */ - return s->test_dbg_ctrl[0]; - - case 0x80: /* MOD_CONF_CTRL_0 */ - return s->mod_conf_ctrl[0]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (s->compat1509) { - if (diff & (1 << 9)) /* BLUETOOTH */ - omap_clk_onoff(omap_findclk(s, "bt_mclk_out"), - (~value >> 9) & 1); - if (diff & (1 << 7)) /* USB.CLKO */ - omap_clk_onoff(omap_findclk(s, "usb.clko"), - (value >> 7) & 1); - } -} - -static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (s->compat1509) { - if (diff & (1 << 31)) /* MCBSP3_CLK_HIZ_DI */ - omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), - (value >> 31) & 1); - if (diff & (1 << 1)) /* CLK32K */ - omap_clk_onoff(omap_findclk(s, "clk32k_out"), - (~value >> 1) & 1); - } -} - -static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (diff & (1 << 31)) /* CONF_MOD_UART3_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart3_ck"), - omap_findclk(s, ((value >> 31) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart2_ck"), - omap_findclk(s, ((value >> 30) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart1_ck"), - omap_findclk(s, ((value >> 29) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ - omap_clk_reparent(omap_findclk(s, "mmc_ck"), - omap_findclk(s, ((value >> 23) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ - omap_clk_reparent(omap_findclk(s, "com_mclk_out"), - omap_findclk(s, ((value >> 12) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ - omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); -} - -static void omap_pin_cfg_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint32_t diff; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* FUNC_MUX_CTRL_0 */ - diff = s->func_mux_ctrl[addr >> 2] ^ value; - s->func_mux_ctrl[addr >> 2] = value; - omap_pin_funcmux0_update(s, diff, value); - return; - - case 0x04: /* FUNC_MUX_CTRL_1 */ - diff = s->func_mux_ctrl[addr >> 2] ^ value; - s->func_mux_ctrl[addr >> 2] = value; - omap_pin_funcmux1_update(s, diff, value); - return; - - case 0x08: /* FUNC_MUX_CTRL_2 */ - s->func_mux_ctrl[addr >> 2] = value; - return; - - case 0x0c: /* COMP_MODE_CTRL_0 */ - s->comp_mode_ctrl[0] = value; - s->compat1509 = (value != 0x0000eaef); - omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]); - omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]); - return; - - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ - s->func_mux_ctrl[(addr >> 2) - 1] = value; - return; - - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ - s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value; - return; - - case 0x50: /* GATE_INH_CTRL_0 */ - s->gate_inh_ctrl[0] = value; - return; - - case 0x60: /* VOLTAGE_CTRL_0 */ - s->voltage_ctrl[0] = value; - return; - - case 0x70: /* TEST_DBG_CTRL_0 */ - s->test_dbg_ctrl[0] = value; - return; - - case 0x80: /* MOD_CONF_CTRL_0 */ - diff = s->mod_conf_ctrl[0] ^ value; - s->mod_conf_ctrl[0] = value; - omap_pin_modconf1_update(s, diff, value); - return; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_pin_cfg_ops = { - .read = omap_pin_cfg_read, - .write = omap_pin_cfg_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) -{ - /* Start in Compatibility Mode. */ - mpu->compat1509 = 1; - omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0); - omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0); - omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0); - memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl)); - memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl)); - memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl)); - memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl)); - memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl)); - memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl)); - memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl)); -} - -static void omap_pin_cfg_init(MemoryRegion *system_memory, - hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->pin_cfg_iomem, &omap_pin_cfg_ops, mpu, - "omap-pin-cfg", 0x800); - memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem); - omap_pin_cfg_reset(mpu); -} - -/* Device Identification, Die Identification */ -static uint64_t omap_id_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0xfffe1800: /* DIE_ID_LSB */ - return 0xc9581f0e; - case 0xfffe1804: /* DIE_ID_MSB */ - return 0xa8858bfa; - - case 0xfffe2000: /* PRODUCT_ID_LSB */ - return 0x00aaaafc; - case 0xfffe2004: /* PRODUCT_ID_MSB */ - return 0xcafeb574; - - case 0xfffed400: /* JTAG_ID_LSB */ - switch (s->mpu_model) { - case omap310: - return 0x03310315; - case omap1510: - return 0x03310115; - default: - hw_error("%s: bad mpu model\n", __FUNCTION__); - } - break; - - case 0xfffed404: /* JTAG_ID_MSB */ - switch (s->mpu_model) { - case omap310: - return 0xfb57402f; - case omap1510: - return 0xfb47002f; - default: - hw_error("%s: bad mpu model\n", __FUNCTION__); - } - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_id_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - OMAP_BAD_REG(addr); -} - -static const MemoryRegionOps omap_id_ops = { - .read = omap_id_read, - .write = omap_id_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->id_iomem, &omap_id_ops, mpu, - "omap-id", 0x100000000ULL); - memory_region_init_alias(&mpu->id_iomem_e18, "omap-id-e18", &mpu->id_iomem, - 0xfffe1800, 0x800); - memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18); - memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-ed4", &mpu->id_iomem, - 0xfffed400, 0x100); - memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4); - if (!cpu_is_omap15xx(mpu)) { - memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-e20", - &mpu->id_iomem, 0xfffe2000, 0x800); - memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20); - } -} - -/* MPUI Control (Dummy) */ -static uint64_t omap_mpui_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* CTRL */ - return s->mpui_ctrl; - case 0x04: /* DEBUG_ADDR */ - return 0x01ffffff; - case 0x08: /* DEBUG_DATA */ - return 0xffffffff; - case 0x0c: /* DEBUG_FLAG */ - return 0x00000800; - case 0x10: /* STATUS */ - return 0x00000000; - - /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ - case 0x18: /* DSP_BOOT_CONFIG */ - return 0x00000000; - case 0x1c: /* DSP_MPUI_CONFIG */ - return 0x0000ffff; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpui_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* CTRL */ - s->mpui_ctrl = value & 0x007fffff; - break; - - case 0x04: /* DEBUG_ADDR */ - case 0x08: /* DEBUG_DATA */ - case 0x0c: /* DEBUG_FLAG */ - case 0x10: /* STATUS */ - /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ - OMAP_RO_REG(addr); - break; - case 0x18: /* DSP_BOOT_CONFIG */ - case 0x1c: /* DSP_MPUI_CONFIG */ - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_mpui_ops = { - .read = omap_mpui_read, - .write = omap_mpui_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_mpui_reset(struct omap_mpu_state_s *s) -{ - s->mpui_ctrl = 0x0003ff1b; -} - -static void omap_mpui_init(MemoryRegion *memory, hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->mpui_iomem, &omap_mpui_ops, mpu, - "omap-mpui", 0x100); - memory_region_add_subregion(memory, base, &mpu->mpui_iomem); - - omap_mpui_reset(mpu); -} - -/* TIPB Bridges */ -struct omap_tipb_bridge_s { - qemu_irq abort; - MemoryRegion iomem; - - int width_intr; - uint16_t control; - uint16_t alloc; - uint16_t buffer; - uint16_t enh_control; -}; - -static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; - - if (size < 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x00: /* TIPB_CNTL */ - return s->control; - case 0x04: /* TIPB_BUS_ALLOC */ - return s->alloc; - case 0x08: /* MPU_TIPB_CNTL */ - return s->buffer; - case 0x0c: /* ENHANCED_TIPB_CNTL */ - return s->enh_control; - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ - return 0xffff; - case 0x1c: /* DEBUG_CNTR_SIG */ - return 0x00f8; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_tipb_bridge_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; - - if (size < 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* TIPB_CNTL */ - s->control = value & 0xffff; - break; - - case 0x04: /* TIPB_BUS_ALLOC */ - s->alloc = value & 0x003f; - break; - - case 0x08: /* MPU_TIPB_CNTL */ - s->buffer = value & 0x0003; - break; - - case 0x0c: /* ENHANCED_TIPB_CNTL */ - s->width_intr = !(value & 2); - s->enh_control = value & 0x000f; - break; - - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ - case 0x1c: /* DEBUG_CNTR_SIG */ - OMAP_RO_REG(addr); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_tipb_bridge_ops = { - .read = omap_tipb_bridge_read, - .write = omap_tipb_bridge_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) -{ - s->control = 0xffff; - s->alloc = 0x0009; - s->buffer = 0x0000; - s->enh_control = 0x000f; -} - -static struct omap_tipb_bridge_s *omap_tipb_bridge_init( - MemoryRegion *memory, hwaddr base, - qemu_irq abort_irq, omap_clk clk) -{ - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) - g_malloc0(sizeof(struct omap_tipb_bridge_s)); - - s->abort = abort_irq; - omap_tipb_bridge_reset(s); - - memory_region_init_io(&s->iomem, &omap_tipb_bridge_ops, s, - "omap-tipb-bridge", 0x100); - memory_region_add_subregion(memory, base, &s->iomem); - - return s; -} - -/* Dummy Traffic Controller's Memory Interface */ -static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint32_t ret; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x0c: /* EMIFS_CONFIG */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ - return s->tcmi_regs[addr >> 2]; - - case 0x20: /* EMIFF_SDRAM_CONFIG */ - ret = s->tcmi_regs[addr >> 2]; - s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ - /* XXX: We can try using the VGA_DIRTY flag for this */ - return ret; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_tcmi_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x20: /* EMIFF_SDRAM_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ - s->tcmi_regs[addr >> 2] = value; - break; - case 0x0c: /* EMIFS_CONFIG */ - s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_tcmi_ops = { - .read = omap_tcmi_read, - .write = omap_tcmi_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) -{ - mpu->tcmi_regs[0x00 >> 2] = 0x00000000; - mpu->tcmi_regs[0x04 >> 2] = 0x00000000; - mpu->tcmi_regs[0x08 >> 2] = 0x00000000; - mpu->tcmi_regs[0x0c >> 2] = 0x00000010; - mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x20 >> 2] = 0x00618800; - mpu->tcmi_regs[0x24 >> 2] = 0x00000037; - mpu->tcmi_regs[0x28 >> 2] = 0x00000000; - mpu->tcmi_regs[0x2c >> 2] = 0x00000000; - mpu->tcmi_regs[0x30 >> 2] = 0x00000000; - mpu->tcmi_regs[0x3c >> 2] = 0x00000003; - mpu->tcmi_regs[0x40 >> 2] = 0x00000000; -} - -static void omap_tcmi_init(MemoryRegion *memory, hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->tcmi_iomem, &omap_tcmi_ops, mpu, - "omap-tcmi", 0x100); - memory_region_add_subregion(memory, base, &mpu->tcmi_iomem); - omap_tcmi_reset(mpu); -} - -/* Digital phase-locked loops control */ -struct dpll_ctl_s { - MemoryRegion iomem; - uint16_t mode; - omap_clk dpll; -}; - -static uint64_t omap_dpll_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - if (addr == 0x00) /* CTL_REG */ - return s->mode; - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_dpll_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; - uint16_t diff; - static const int bypass_div[4] = { 1, 2, 4, 4 }; - int div, mult; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - if (addr == 0x00) { /* CTL_REG */ - /* See omap_ulpd_pm_write() too */ - diff = s->mode & value; - s->mode = value & 0x2fff; - if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ - } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ - mult = 1; - } - omap_clk_setrate(s->dpll, div, mult); - } - - /* Enter the desired mode. */ - s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1); - - /* Act as if the lock is restored. */ - s->mode |= 2; - } else { - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_dpll_ops = { - .read = omap_dpll_read, - .write = omap_dpll_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_dpll_reset(struct dpll_ctl_s *s) -{ - s->mode = 0x2002; - omap_clk_setrate(s->dpll, 1, 1); -} - -static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory, - hwaddr base, omap_clk clk) -{ - struct dpll_ctl_s *s = g_malloc0(sizeof(*s)); - memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100); - - s->dpll = clk; - omap_dpll_reset(s); - - memory_region_add_subregion(memory, base, &s->iomem); - return s; -} - -/* MPU Clock/Reset/Power Mode Control */ -static uint64_t omap_clkm_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x00: /* ARM_CKCTL */ - return s->clkm.arm_ckctl; - - case 0x04: /* ARM_IDLECT1 */ - return s->clkm.arm_idlect1; - - case 0x08: /* ARM_IDLECT2 */ - return s->clkm.arm_idlect2; - - case 0x0c: /* ARM_EWUPCT */ - return s->clkm.arm_ewupct; - - case 0x10: /* ARM_RSTCT1 */ - return s->clkm.arm_rstct1; - - case 0x14: /* ARM_RSTCT2 */ - return s->clkm.arm_rstct2; - - case 0x18: /* ARM_SYSST */ - return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; - - case 0x1c: /* ARM_CKOUT1 */ - return s->clkm.arm_ckout1; - - case 0x20: /* ARM_CKOUT2 */ - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ - if (value & (1 << 14)) - /* Reserved */; - else { - clk = omap_findclk(s, "arminth_ck"); - omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); - } - } - if (diff & (1 << 12)) { /* ARM_TIMXO */ - clk = omap_findclk(s, "armtim_ck"); - if (value & (1 << 12)) - omap_clk_reparent(clk, omap_findclk(s, "clkin")); - else - omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); - } - /* XXX: en_dspck */ - if (diff & (3 << 10)) { /* DSPMMUDIV */ - clk = omap_findclk(s, "dspmmu_ck"); - omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1); - } - if (diff & (3 << 8)) { /* TCDIV */ - clk = omap_findclk(s, "tc_ck"); - omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1); - } - if (diff & (3 << 6)) { /* DSPDIV */ - clk = omap_findclk(s, "dsp_ck"); - omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1); - } - if (diff & (3 << 4)) { /* ARMDIV */ - clk = omap_findclk(s, "arm_ck"); - omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1); - } - if (diff & (3 << 2)) { /* LCDDIV */ - clk = omap_findclk(s, "lcd_ck"); - omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1); - } - if (diff & (3 << 0)) { /* PERDIV */ - clk = omap_findclk(s, "armper_ck"); - omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1); - } -} - -static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (value & (1 << 11)) { /* SETARM_IDLE */ - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); - } - if (!(value & (1 << 10))) /* WKUP_MODE */ - qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ - -#define SET_CANIDLE(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_canidle(clk, (value >> bit) & 1); \ - } - SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ - SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ - SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ - SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ - SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ - SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ - SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ - SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ -} - -static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - -#define SET_ONOFF(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_onoff(clk, (value >> bit) & 1); \ - } - SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ - SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ - SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ - SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ - SET_ONOFF("lb_ck", 4) /* EN_LBCK */ - SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ - SET_ONOFF("mpui_ck", 6) /* EN_APICK */ - SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ - SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ - SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ - SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ -} - -static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (diff & (3 << 4)) { /* TCLKOUT */ - clk = omap_findclk(s, "tclk_out"); - switch ((value >> 4) & 3) { - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen3")); - omap_clk_onoff(clk, 1); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); - omap_clk_onoff(clk, 1); - break; - default: - omap_clk_onoff(clk, 0); - } - } - if (diff & (3 << 2)) { /* DCLKOUT */ - clk = omap_findclk(s, "dclk_out"); - switch ((value >> 2) & 3) { - case 0: - omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck")); - break; - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen2")); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "dsp_ck")); - break; - case 3: - omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); - break; - } - } - if (diff & (3 << 0)) { /* ACLKOUT */ - clk = omap_findclk(s, "aclk_out"); - switch ((value >> 0) & 3) { - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); - omap_clk_onoff(clk, 1); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "arm_ck")); - omap_clk_onoff(clk, 1); - break; - case 3: - omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); - omap_clk_onoff(clk, 1); - break; - default: - omap_clk_onoff(clk, 0); - } - } -} - -static void omap_clkm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint16_t diff; - omap_clk clk; - static const char *clkschemename[8] = { - "fully synchronous", "fully asynchronous", "synchronous scalable", - "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4", - }; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* ARM_CKCTL */ - diff = s->clkm.arm_ckctl ^ value; - s->clkm.arm_ckctl = value & 0x7fff; - omap_clkm_ckctl_update(s, diff, value); - return; - - case 0x04: /* ARM_IDLECT1 */ - diff = s->clkm.arm_idlect1 ^ value; - s->clkm.arm_idlect1 = value & 0x0fff; - omap_clkm_idlect1_update(s, diff, value); - return; - - case 0x08: /* ARM_IDLECT2 */ - diff = s->clkm.arm_idlect2 ^ value; - s->clkm.arm_idlect2 = value & 0x07ff; - omap_clkm_idlect2_update(s, diff, value); - return; - - case 0x0c: /* ARM_EWUPCT */ - s->clkm.arm_ewupct = value & 0x003f; - return; - - case 0x10: /* ARM_RSTCT1 */ - diff = s->clkm.arm_rstct1 ^ value; - s->clkm.arm_rstct1 = value & 0x0007; - if (value & 9) { - qemu_system_reset_request(); - s->clkm.cold_start = 0xa; - } - if (diff & ~value & 4) { /* DSP_RST */ - omap_mpui_reset(s); - omap_tipb_bridge_reset(s->private_tipb); - omap_tipb_bridge_reset(s->public_tipb); - } - if (diff & 2) { /* DSP_EN */ - clk = omap_findclk(s, "dsp_ck"); - omap_clk_canidle(clk, (~value >> 1) & 1); - } - return; - - case 0x14: /* ARM_RSTCT2 */ - s->clkm.arm_rstct2 = value & 0x0001; - return; - - case 0x18: /* ARM_SYSST */ - if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) { - s->clkm.clocking_scheme = (value >> 11) & 7; - printf("%s: clocking scheme set to %s\n", __FUNCTION__, - clkschemename[s->clkm.clocking_scheme]); - } - s->clkm.cold_start &= value & 0x3f; - return; - - case 0x1c: /* ARM_CKOUT1 */ - diff = s->clkm.arm_ckout1 ^ value; - s->clkm.arm_ckout1 = value & 0x003f; - omap_clkm_ckout1_update(s, diff, value); - return; - - case 0x20: /* ARM_CKOUT2 */ - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_clkm_ops = { - .read = omap_clkm_read, - .write = omap_clkm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x04: /* DSP_IDLECT1 */ - return s->clkm.dsp_idlect1; - - case 0x08: /* DSP_IDLECT2 */ - return s->clkm.dsp_idlect2; - - case 0x14: /* DSP_RSTCT2 */ - return s->clkm.dsp_rstct2; - - case 0x18: /* DSP_SYSST */ - return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | - (s->cpu->env.halted << 6); /* Quite useless... */ - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ -} - -static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ -} - -static void omap_clkdsp_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint16_t diff; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (addr) { - case 0x04: /* DSP_IDLECT1 */ - diff = s->clkm.dsp_idlect1 ^ value; - s->clkm.dsp_idlect1 = value & 0x01f7; - omap_clkdsp_idlect1_update(s, diff, value); - break; - - case 0x08: /* DSP_IDLECT2 */ - s->clkm.dsp_idlect2 = value & 0x0037; - diff = s->clkm.dsp_idlect1 ^ value; - omap_clkdsp_idlect2_update(s, diff, value); - break; - - case 0x14: /* DSP_RSTCT2 */ - s->clkm.dsp_rstct2 = value & 0x0001; - break; - - case 0x18: /* DSP_SYSST */ - s->clkm.cold_start &= value & 0x3f; - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_clkdsp_ops = { - .read = omap_clkdsp_read, - .write = omap_clkdsp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_clkm_reset(struct omap_mpu_state_s *s) -{ - if (s->wdt && s->wdt->reset) - s->clkm.cold_start = 0x6; - s->clkm.clocking_scheme = 0; - omap_clkm_ckctl_update(s, ~0, 0x3000); - s->clkm.arm_ckctl = 0x3000; - omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400); - s->clkm.arm_idlect1 = 0x0400; - omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100); - s->clkm.arm_idlect2 = 0x0100; - s->clkm.arm_ewupct = 0x003f; - s->clkm.arm_rstct1 = 0x0000; - s->clkm.arm_rstct2 = 0x0000; - s->clkm.arm_ckout1 = 0x0015; - s->clkm.dpll1_mode = 0x2002; - omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040); - s->clkm.dsp_idlect1 = 0x0040; - omap_clkdsp_idlect2_update(s, ~0, 0x0000); - s->clkm.dsp_idlect2 = 0x0000; - s->clkm.dsp_rstct2 = 0x0000; -} - -static void omap_clkm_init(MemoryRegion *memory, hwaddr mpu_base, - hwaddr dsp_base, struct omap_mpu_state_s *s) -{ - memory_region_init_io(&s->clkm_iomem, &omap_clkm_ops, s, - "omap-clkm", 0x100); - memory_region_init_io(&s->clkdsp_iomem, &omap_clkdsp_ops, s, - "omap-clkdsp", 0x1000); - - s->clkm.arm_idlect1 = 0x03ff; - s->clkm.arm_idlect2 = 0x0100; - s->clkm.dsp_idlect1 = 0x0002; - omap_clkm_reset(s); - s->clkm.cold_start = 0x3a; - - memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem); - memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem); -} - -/* MPU I/O */ -struct omap_mpuio_s { - qemu_irq irq; - qemu_irq kbd_irq; - qemu_irq *in; - qemu_irq handler[16]; - qemu_irq wakeup; - MemoryRegion iomem; - - uint16_t inputs; - uint16_t outputs; - uint16_t dir; - uint16_t edge; - uint16_t mask; - uint16_t ints; - - uint16_t debounce; - uint16_t latch; - uint8_t event; - - uint8_t buttons[5]; - uint8_t row_latch; - uint8_t cols; - int kbd_mask; - int clk; -}; - -static void omap_mpuio_set(void *opaque, int line, int level) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - uint16_t prev = s->inputs; - - if (level) - s->inputs |= 1 << line; - else - s->inputs &= ~(1 << line); - - if (((1 << line) & s->dir & ~s->mask) && s->clk) { - if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) { - s->ints |= 1 << line; - qemu_irq_raise(s->irq); - /* TODO: wakeup */ - } - if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ - (s->event >> 1) == line) /* PIN_SELECT */ - s->latch = s->inputs; - } -} - -static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) -{ - int i; - uint8_t *row, rows = 0, cols = ~s->cols; - - for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1) - if (*row & cols) - rows |= i; - - qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk); - s->row_latch = ~rows; -} - -static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (offset) { - case 0x00: /* INPUT_LATCH */ - return s->inputs; - - case 0x04: /* OUTPUT_REG */ - return s->outputs; - - case 0x08: /* IO_CNTL */ - return s->dir; - - case 0x10: /* KBR_LATCH */ - return s->row_latch; - - case 0x14: /* KBC_REG */ - return s->cols; - - case 0x18: /* GPIO_EVENT_MODE_REG */ - return s->event; - - case 0x1c: /* GPIO_INT_EDGE_REG */ - return s->edge; - - case 0x20: /* KBD_INT */ - return (~s->row_latch & 0x1f) && !s->kbd_mask; - - case 0x24: /* GPIO_INT */ - ret = s->ints; - s->ints &= s->mask; - if (ret) - qemu_irq_lower(s->irq); - return ret; - - case 0x28: /* KBD_MASKIT */ - return s->kbd_mask; - - case 0x2c: /* GPIO_MASKIT */ - return s->mask; - - case 0x30: /* GPIO_DEBOUNCING_REG */ - return s->debounce; - - case 0x34: /* GPIO_LATCH_REG */ - return s->latch; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpuio_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t diff; - int ln; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (offset) { - case 0x04: /* OUTPUT_REG */ - diff = (s->outputs ^ value) & ~s->dir; - s->outputs = value; - while ((ln = ffs(diff))) { - ln --; - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x08: /* IO_CNTL */ - diff = s->outputs & (s->dir ^ value); - s->dir = value; - - value = s->outputs & ~s->dir; - while ((ln = ffs(diff))) { - ln --; - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x14: /* KBC_REG */ - s->cols = value; - omap_mpuio_kbd_update(s); - break; - - case 0x18: /* GPIO_EVENT_MODE_REG */ - s->event = value & 0x1f; - break; - - case 0x1c: /* GPIO_INT_EDGE_REG */ - s->edge = value; - break; - - case 0x28: /* KBD_MASKIT */ - s->kbd_mask = value & 1; - omap_mpuio_kbd_update(s); - break; - - case 0x2c: /* GPIO_MASKIT */ - s->mask = value; - break; - - case 0x30: /* GPIO_DEBOUNCING_REG */ - s->debounce = value & 0x1ff; - break; - - case 0x00: /* INPUT_LATCH */ - case 0x10: /* KBR_LATCH */ - case 0x20: /* KBD_INT */ - case 0x24: /* GPIO_INT */ - case 0x34: /* GPIO_LATCH_REG */ - OMAP_RO_REG(addr); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_mpuio_ops = { - .read = omap_mpuio_read, - .write = omap_mpuio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_mpuio_reset(struct omap_mpuio_s *s) -{ - s->inputs = 0; - s->outputs = 0; - s->dir = ~0; - s->event = 0; - s->edge = 0; - s->kbd_mask = 0; - s->mask = 0; - s->debounce = 0; - s->latch = 0; - s->ints = 0; - s->row_latch = 0x1f; - s->clk = 1; -} - -static void omap_mpuio_onoff(void *opaque, int line, int on) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - - s->clk = on; - if (on) - omap_mpuio_kbd_update(s); -} - -static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory, - hwaddr base, - qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, - omap_clk clk) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) - g_malloc0(sizeof(struct omap_mpuio_s)); - - s->irq = gpio_int; - s->kbd_irq = kbd_int; - s->wakeup = wakeup; - s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); - omap_mpuio_reset(s); - - memory_region_init_io(&s->iomem, &omap_mpuio_ops, s, - "omap-mpuio", 0x800); - memory_region_add_subregion(memory, base, &s->iomem); - - omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); - - return s; -} - -qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s) -{ - return s->in; -} - -void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler) -{ - if (line >= 16 || line < 0) - hw_error("%s: No GPIO line %i\n", __FUNCTION__, line); - s->handler[line] = handler; -} - -void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) -{ - if (row >= 5 || row < 0) - hw_error("%s: No key %i-%i\n", __FUNCTION__, col, row); - - if (down) - s->buttons[row] |= 1 << col; - else - s->buttons[row] &= ~(1 << col); - - omap_mpuio_kbd_update(s); -} - -/* MicroWire Interface */ -struct omap_uwire_s { - MemoryRegion iomem; - qemu_irq txirq; - qemu_irq rxirq; - qemu_irq txdrq; - - uint16_t txbuf; - uint16_t rxbuf; - uint16_t control; - uint16_t setup[5]; - - uWireSlave *chip[4]; -}; - -static void omap_uwire_transfer_start(struct omap_uwire_s *s) -{ - int chipselect = (s->control >> 10) & 3; /* INDEX */ - uWireSlave *slave = s->chip[chipselect]; - - if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ - if (s->control & (1 << 12)) /* CS_CMD */ - if (slave && slave->send) - slave->send(slave->opaque, - s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); - s->control &= ~(1 << 14); /* CSRB */ - /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or - * a DRQ. When is the level IRQ supposed to be reset? */ - } - - if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ - if (s->control & (1 << 12)) /* CS_CMD */ - if (slave && slave->receive) - s->rxbuf = slave->receive(slave->opaque); - s->control |= 1 << 15; /* RDRB */ - /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or - * a DRQ. When is the level IRQ supposed to be reset? */ - } -} - -static uint64_t omap_uwire_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (offset) { - case 0x00: /* RDR */ - s->control &= ~(1 << 15); /* RDRB */ - return s->rxbuf; - - case 0x04: /* CSR */ - return s->control; - - case 0x08: /* SR1 */ - return s->setup[0]; - case 0x0c: /* SR2 */ - return s->setup[1]; - case 0x10: /* SR3 */ - return s->setup[2]; - case 0x14: /* SR4 */ - return s->setup[3]; - case 0x18: /* SR5 */ - return s->setup[4]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_uwire_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (offset) { - case 0x00: /* TDR */ - s->txbuf = value; /* TD */ - if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ - ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ - (s->control & (1 << 12)))) { /* CS_CMD */ - s->control |= 1 << 14; /* CSRB */ - omap_uwire_transfer_start(s); - } - break; - - case 0x04: /* CSR */ - s->control = value & 0x1fff; - if (value & (1 << 13)) /* START */ - omap_uwire_transfer_start(s); - break; - - case 0x08: /* SR1 */ - s->setup[0] = value & 0x003f; - break; - - case 0x0c: /* SR2 */ - s->setup[1] = value & 0x0fc0; - break; - - case 0x10: /* SR3 */ - s->setup[2] = value & 0x0003; - break; - - case 0x14: /* SR4 */ - s->setup[3] = value & 0x0001; - break; - - case 0x18: /* SR5 */ - s->setup[4] = value & 0x000f; - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_uwire_ops = { - .read = omap_uwire_read, - .write = omap_uwire_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_uwire_reset(struct omap_uwire_s *s) -{ - s->control = 0; - s->setup[0] = 0; - s->setup[1] = 0; - s->setup[2] = 0; - s->setup[3] = 0; - s->setup[4] = 0; -} - -static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq txirq, qemu_irq rxirq, - qemu_irq dma, - omap_clk clk) -{ - struct omap_uwire_s *s = (struct omap_uwire_s *) - g_malloc0(sizeof(struct omap_uwire_s)); - - s->txirq = txirq; - s->rxirq = rxirq; - s->txdrq = dma; - omap_uwire_reset(s); - - memory_region_init_io(&s->iomem, &omap_uwire_ops, s, "omap-uwire", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -void omap_uwire_attach(struct omap_uwire_s *s, - uWireSlave *slave, int chipselect) -{ - if (chipselect < 0 || chipselect > 3) { - fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect); - exit(-1); - } - - s->chip[chipselect] = slave; -} - -/* Pseudonoise Pulse-Width Light Modulator */ -struct omap_pwl_s { - MemoryRegion iomem; - uint8_t output; - uint8_t level; - uint8_t enable; - int clk; -}; - -static void omap_pwl_update(struct omap_pwl_s *s) -{ - int output = (s->clk && s->enable) ? s->level : 0; - - if (output != s->output) { - s->output = output; - printf("%s: Backlight now at %i/256\n", __FUNCTION__, output); - } -} - -static uint64_t omap_pwl_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* PWL_LEVEL */ - return s->level; - case 0x04: /* PWL_CTRL */ - return s->enable; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_pwl_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_write8(opaque, addr, value); - } - - switch (offset) { - case 0x00: /* PWL_LEVEL */ - s->level = value; - omap_pwl_update(s); - break; - case 0x04: /* PWL_CTRL */ - s->enable = value & 1; - omap_pwl_update(s); - break; - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_pwl_ops = { - .read = omap_pwl_read, - .write = omap_pwl_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_pwl_reset(struct omap_pwl_s *s) -{ - s->output = 0; - s->level = 0; - s->enable = 0; - s->clk = 1; - omap_pwl_update(s); -} - -static void omap_pwl_clk_update(void *opaque, int line, int on) -{ - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; - - s->clk = on; - omap_pwl_update(s); -} - -static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory, - hwaddr base, - omap_clk clk) -{ - struct omap_pwl_s *s = g_malloc0(sizeof(*s)); - - omap_pwl_reset(s); - - memory_region_init_io(&s->iomem, &omap_pwl_ops, s, - "omap-pwl", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); - return s; -} - -/* Pulse-Width Tone module */ -struct omap_pwt_s { - MemoryRegion iomem; - uint8_t frc; - uint8_t vrc; - uint8_t gcr; - omap_clk clk; -}; - -static uint64_t omap_pwt_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* FRC */ - return s->frc; - case 0x04: /* VCR */ - return s->vrc; - case 0x08: /* GCR */ - return s->gcr; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_pwt_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_write8(opaque, addr, value); - } - - switch (offset) { - case 0x00: /* FRC */ - s->frc = value & 0x3f; - break; - case 0x04: /* VRC */ - if ((value ^ s->vrc) & 1) { - if (value & 1) - printf("%s: %iHz buzz on\n", __FUNCTION__, (int) - /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */ - ((omap_clk_getrate(s->clk) >> 3) / - /* Pre-multiplexer divider */ - ((s->gcr & 2) ? 1 : 154) / - /* Octave multiplexer */ - (2 << (value & 3)) * - /* 101/107 divider */ - ((value & (1 << 2)) ? 101 : 107) * - /* 49/55 divider */ - ((value & (1 << 3)) ? 49 : 55) * - /* 50/63 divider */ - ((value & (1 << 4)) ? 50 : 63) * - /* 80/127 divider */ - ((value & (1 << 5)) ? 80 : 127) / - (107 * 55 * 63 * 127))); - else - printf("%s: silence!\n", __FUNCTION__); - } - s->vrc = value & 0x7f; - break; - case 0x08: /* GCR */ - s->gcr = value & 3; - break; - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_pwt_ops = { - .read =omap_pwt_read, - .write = omap_pwt_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_pwt_reset(struct omap_pwt_s *s) -{ - s->frc = 0; - s->vrc = 0; - s->gcr = 0; -} - -static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory, - hwaddr base, - omap_clk clk) -{ - struct omap_pwt_s *s = g_malloc0(sizeof(*s)); - s->clk = clk; - omap_pwt_reset(s); - - memory_region_init_io(&s->iomem, &omap_pwt_ops, s, - "omap-pwt", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - return s; -} - -/* Real-time Clock module */ -struct omap_rtc_s { - MemoryRegion iomem; - qemu_irq irq; - qemu_irq alarm; - QEMUTimer *clk; - - uint8_t interrupts; - uint8_t status; - int16_t comp_reg; - int running; - int pm_am; - int auto_comp; - int round; - struct tm alarm_tm; - time_t alarm_ti; - - struct tm current_tm; - time_t ti; - uint64_t tick; -}; - -static void omap_rtc_interrupts_update(struct omap_rtc_s *s) -{ - /* s->alarm is level-triggered */ - qemu_set_irq(s->alarm, (s->status >> 6) & 1); -} - -static void omap_rtc_alarm_update(struct omap_rtc_s *s) -{ - s->alarm_ti = mktimegm(&s->alarm_tm); - if (s->alarm_ti == -1) - printf("%s: conversion failed\n", __FUNCTION__); -} - -static uint64_t omap_rtc_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint8_t i; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* SECONDS_REG */ - return to_bcd(s->current_tm.tm_sec); - - case 0x04: /* MINUTES_REG */ - return to_bcd(s->current_tm.tm_min); - - case 0x08: /* HOURS_REG */ - if (s->pm_am) - return ((s->current_tm.tm_hour > 11) << 7) | - to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); - else - return to_bcd(s->current_tm.tm_hour); - - case 0x0c: /* DAYS_REG */ - return to_bcd(s->current_tm.tm_mday); - - case 0x10: /* MONTHS_REG */ - return to_bcd(s->current_tm.tm_mon + 1); - - case 0x14: /* YEARS_REG */ - return to_bcd(s->current_tm.tm_year % 100); - - case 0x18: /* WEEK_REG */ - return s->current_tm.tm_wday; - - case 0x20: /* ALARM_SECONDS_REG */ - return to_bcd(s->alarm_tm.tm_sec); - - case 0x24: /* ALARM_MINUTES_REG */ - return to_bcd(s->alarm_tm.tm_min); - - case 0x28: /* ALARM_HOURS_REG */ - if (s->pm_am) - return ((s->alarm_tm.tm_hour > 11) << 7) | - to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); - else - return to_bcd(s->alarm_tm.tm_hour); - - case 0x2c: /* ALARM_DAYS_REG */ - return to_bcd(s->alarm_tm.tm_mday); - - case 0x30: /* ALARM_MONTHS_REG */ - return to_bcd(s->alarm_tm.tm_mon + 1); - - case 0x34: /* ALARM_YEARS_REG */ - return to_bcd(s->alarm_tm.tm_year % 100); - - case 0x40: /* RTC_CTRL_REG */ - return (s->pm_am << 3) | (s->auto_comp << 2) | - (s->round << 1) | s->running; - - case 0x44: /* RTC_STATUS_REG */ - i = s->status; - s->status &= ~0x3d; - return i; - - case 0x48: /* RTC_INTERRUPTS_REG */ - return s->interrupts; - - case 0x4c: /* RTC_COMP_LSB_REG */ - return ((uint16_t) s->comp_reg) & 0xff; - - case 0x50: /* RTC_COMP_MSB_REG */ - return ((uint16_t) s->comp_reg) >> 8; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_rtc_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - struct tm new_tm; - time_t ti[2]; - - if (size != 1) { - return omap_badwidth_write8(opaque, addr, value); - } - - switch (offset) { - case 0x00: /* SECONDS_REG */ -#ifdef ALMDEBUG - printf("RTC SEC_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_sec; - s->ti += from_bcd(value); - return; - - case 0x04: /* MINUTES_REG */ -#ifdef ALMDEBUG - printf("RTC MIN_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_min * 60; - s->ti += from_bcd(value) * 60; - return; - - case 0x08: /* HOURS_REG */ -#ifdef ALMDEBUG - printf("RTC HRS_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_hour * 3600; - if (s->pm_am) { - s->ti += (from_bcd(value & 0x3f) & 12) * 3600; - s->ti += ((value >> 7) & 1) * 43200; - } else - s->ti += from_bcd(value & 0x3f) * 3600; - return; - - case 0x0c: /* DAYS_REG */ -#ifdef ALMDEBUG - printf("RTC DAY_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_mday * 86400; - s->ti += from_bcd(value) * 86400; - return; - - case 0x10: /* MONTHS_REG */ -#ifdef ALMDEBUG - printf("RTC MTH_REG <-- %02x\n", value); -#endif - memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_mon = from_bcd(value); - ti[0] = mktimegm(&s->current_tm); - ti[1] = mktimegm(&new_tm); - - if (ti[0] != -1 && ti[1] != -1) { - s->ti -= ti[0]; - s->ti += ti[1]; - } else { - /* A less accurate version */ - s->ti -= s->current_tm.tm_mon * 2592000; - s->ti += from_bcd(value) * 2592000; - } - return; - - case 0x14: /* YEARS_REG */ -#ifdef ALMDEBUG - printf("RTC YRS_REG <-- %02x\n", value); -#endif - memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100); - ti[0] = mktimegm(&s->current_tm); - ti[1] = mktimegm(&new_tm); - - if (ti[0] != -1 && ti[1] != -1) { - s->ti -= ti[0]; - s->ti += ti[1]; - } else { - /* A less accurate version */ - s->ti -= (s->current_tm.tm_year % 100) * 31536000; - s->ti += from_bcd(value) * 31536000; - } - return; - - case 0x18: /* WEEK_REG */ - return; /* Ignored */ - - case 0x20: /* ALARM_SECONDS_REG */ -#ifdef ALMDEBUG - printf("ALM SEC_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_sec = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x24: /* ALARM_MINUTES_REG */ -#ifdef ALMDEBUG - printf("ALM MIN_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_min = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x28: /* ALARM_HOURS_REG */ -#ifdef ALMDEBUG - printf("ALM HRS_REG <-- %02x\n", value); -#endif - if (s->pm_am) - s->alarm_tm.tm_hour = - ((from_bcd(value & 0x3f)) % 12) + - ((value >> 7) & 1) * 12; - else - s->alarm_tm.tm_hour = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x2c: /* ALARM_DAYS_REG */ -#ifdef ALMDEBUG - printf("ALM DAY_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_mday = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x30: /* ALARM_MONTHS_REG */ -#ifdef ALMDEBUG - printf("ALM MON_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_mon = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x34: /* ALARM_YEARS_REG */ -#ifdef ALMDEBUG - printf("ALM YRS_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_year = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x40: /* RTC_CTRL_REG */ -#ifdef ALMDEBUG - printf("RTC CONTROL <-- %02x\n", value); -#endif - s->pm_am = (value >> 3) & 1; - s->auto_comp = (value >> 2) & 1; - s->round = (value >> 1) & 1; - s->running = value & 1; - s->status &= 0xfd; - s->status |= s->running << 1; - return; - - case 0x44: /* RTC_STATUS_REG */ -#ifdef ALMDEBUG - printf("RTC STATUSL <-- %02x\n", value); -#endif - s->status &= ~((value & 0xc0) ^ 0x80); - omap_rtc_interrupts_update(s); - return; - - case 0x48: /* RTC_INTERRUPTS_REG */ -#ifdef ALMDEBUG - printf("RTC INTRS <-- %02x\n", value); -#endif - s->interrupts = value; - return; - - case 0x4c: /* RTC_COMP_LSB_REG */ -#ifdef ALMDEBUG - printf("RTC COMPLSB <-- %02x\n", value); -#endif - s->comp_reg &= 0xff00; - s->comp_reg |= 0x00ff & value; - return; - - case 0x50: /* RTC_COMP_MSB_REG */ -#ifdef ALMDEBUG - printf("RTC COMPMSB <-- %02x\n", value); -#endif - s->comp_reg &= 0x00ff; - s->comp_reg |= 0xff00 & (value << 8); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_rtc_ops = { - .read = omap_rtc_read, - .write = omap_rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_rtc_tick(void *opaque) -{ - struct omap_rtc_s *s = opaque; - - if (s->round) { - /* Round to nearest full minute. */ - if (s->current_tm.tm_sec < 30) - s->ti -= s->current_tm.tm_sec; - else - s->ti += 60 - s->current_tm.tm_sec; - - s->round = 0; - } - - localtime_r(&s->ti, &s->current_tm); - - if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { - s->status |= 0x40; - omap_rtc_interrupts_update(s); - } - - if (s->interrupts & 0x04) - switch (s->interrupts & 3) { - case 0: - s->status |= 0x04; - qemu_irq_pulse(s->irq); - break; - case 1: - if (s->current_tm.tm_sec) - break; - s->status |= 0x08; - qemu_irq_pulse(s->irq); - break; - case 2: - if (s->current_tm.tm_sec || s->current_tm.tm_min) - break; - s->status |= 0x10; - qemu_irq_pulse(s->irq); - break; - case 3: - if (s->current_tm.tm_sec || - s->current_tm.tm_min || s->current_tm.tm_hour) - break; - s->status |= 0x20; - qemu_irq_pulse(s->irq); - break; - } - - /* Move on */ - if (s->running) - s->ti ++; - s->tick += 1000; - - /* - * Every full hour add a rough approximation of the compensation - * register to the 32kHz Timer (which drives the RTC) value. - */ - if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) - s->tick += s->comp_reg * 1000 / 32768; - - qemu_mod_timer(s->clk, s->tick); -} - -static void omap_rtc_reset(struct omap_rtc_s *s) -{ - struct tm tm; - - s->interrupts = 0; - s->comp_reg = 0; - s->running = 0; - s->pm_am = 0; - s->auto_comp = 0; - s->round = 0; - s->tick = qemu_get_clock_ms(rtc_clock); - memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); - s->alarm_tm.tm_mday = 0x01; - s->status = 1 << 7; - qemu_get_timedate(&tm, 0); - s->ti = mktimegm(&tm); - - omap_rtc_alarm_update(s); - omap_rtc_tick(s); -} - -static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq timerirq, qemu_irq alarmirq, - omap_clk clk) -{ - struct omap_rtc_s *s = (struct omap_rtc_s *) - g_malloc0(sizeof(struct omap_rtc_s)); - - s->irq = timerirq; - s->alarm = alarmirq; - s->clk = qemu_new_timer_ms(rtc_clock, omap_rtc_tick, s); - - omap_rtc_reset(s); - - memory_region_init_io(&s->iomem, &omap_rtc_ops, s, - "omap-rtc", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -/* Multi-channel Buffered Serial Port interfaces */ -struct omap_mcbsp_s { - MemoryRegion iomem; - qemu_irq txirq; - qemu_irq rxirq; - qemu_irq txdrq; - qemu_irq rxdrq; - - uint16_t spcr[2]; - uint16_t rcr[2]; - uint16_t xcr[2]; - uint16_t srgr[2]; - uint16_t mcr[2]; - uint16_t pcr; - uint16_t rcer[8]; - uint16_t xcer[8]; - int tx_rate; - int rx_rate; - int tx_req; - int rx_req; - - I2SCodec *codec; - QEMUTimer *source_timer; - QEMUTimer *sink_timer; -}; - -static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) -{ - int irq; - - switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ - case 0: - irq = (s->spcr[0] >> 1) & 1; /* RRDY */ - break; - case 3: - irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ - break; - default: - irq = 0; - break; - } - - if (irq) - qemu_irq_pulse(s->rxirq); - - switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ - case 0: - irq = (s->spcr[1] >> 1) & 1; /* XRDY */ - break; - case 3: - irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ - break; - default: - irq = 0; - break; - } - - if (irq) - qemu_irq_pulse(s->txirq); -} - -static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) -{ - if ((s->spcr[0] >> 1) & 1) /* RRDY */ - s->spcr[0] |= 1 << 2; /* RFULL */ - s->spcr[0] |= 1 << 1; /* RRDY */ - qemu_irq_raise(s->rxdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_source_tick(void *opaque) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; - - if (!s->rx_rate) - return; - if (s->rx_req) - printf("%s: Rx FIFO overrun\n", __FUNCTION__); - - s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; - - omap_mcbsp_rx_newdata(s); - qemu_mod_timer(s->source_timer, qemu_get_clock_ns(vm_clock) + - get_ticks_per_sec()); -} - -static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) -{ - if (!s->codec || !s->codec->rts) - omap_mcbsp_source_tick(s); - else if (s->codec->in.len) { - s->rx_req = s->codec->in.len; - omap_mcbsp_rx_newdata(s); - } -} - -static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) -{ - qemu_del_timer(s->source_timer); -} - -static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) -{ - s->spcr[0] &= ~(1 << 1); /* RRDY */ - qemu_irq_lower(s->rxdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) -{ - s->spcr[1] |= 1 << 1; /* XRDY */ - qemu_irq_raise(s->txdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_sink_tick(void *opaque) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; - - if (!s->tx_rate) - return; - if (s->tx_req) - printf("%s: Tx FIFO underrun\n", __FUNCTION__); - - s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; - - omap_mcbsp_tx_newdata(s); - qemu_mod_timer(s->sink_timer, qemu_get_clock_ns(vm_clock) + - get_ticks_per_sec()); -} - -static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) -{ - if (!s->codec || !s->codec->cts) - omap_mcbsp_sink_tick(s); - else if (s->codec->out.size) { - s->tx_req = s->codec->out.size; - omap_mcbsp_tx_newdata(s); - } -} - -static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) -{ - s->spcr[1] &= ~(1 << 1); /* XRDY */ - qemu_irq_lower(s->txdrq); - omap_mcbsp_intr_update(s); - if (s->codec && s->codec->cts) - s->codec->tx_swallow(s->codec->opaque); -} - -static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) -{ - s->tx_req = 0; - omap_mcbsp_tx_done(s); - qemu_del_timer(s->sink_timer); -} - -static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) -{ - int prev_rx_rate, prev_tx_rate; - int rx_rate = 0, tx_rate = 0; - int cpu_rate = 1500000; /* XXX */ - - /* TODO: check CLKSTP bit */ - if (s->spcr[1] & (1 << 6)) { /* GRST */ - if (s->spcr[0] & (1 << 0)) { /* RRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 8))) { /* CLKRM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - rx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - } else - if (s->codec) - rx_rate = s->codec->rx_rate; - } - - if (s->spcr[1] & (1 << 0)) { /* XRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 9))) { /* CLKXM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - tx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - } else - if (s->codec) - tx_rate = s->codec->tx_rate; - } - } - prev_tx_rate = s->tx_rate; - prev_rx_rate = s->rx_rate; - s->tx_rate = tx_rate; - s->rx_rate = rx_rate; - - if (s->codec) - s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); - - if (!prev_tx_rate && tx_rate) - omap_mcbsp_tx_start(s); - else if (s->tx_rate && !tx_rate) - omap_mcbsp_tx_stop(s); - - if (!prev_rx_rate && rx_rate) - omap_mcbsp_rx_start(s); - else if (prev_tx_rate && !tx_rate) - omap_mcbsp_rx_stop(s); -} - -static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (offset) { - case 0x00: /* DRR2 */ - if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ - return 0x0000; - /* Fall through. */ - case 0x02: /* DRR1 */ - if (s->rx_req < 2) { - printf("%s: Rx FIFO underrun\n", __FUNCTION__); - omap_mcbsp_rx_done(s); - } else { - s->tx_req -= 2; - if (s->codec && s->codec->in.len >= 2) { - ret = s->codec->in.fifo[s->codec->in.start ++] << 8; - ret |= s->codec->in.fifo[s->codec->in.start ++]; - s->codec->in.len -= 2; - } else - ret = 0x0000; - if (!s->tx_req) - omap_mcbsp_rx_done(s); - return ret; - } - return 0x0000; - - case 0x04: /* DXR2 */ - case 0x06: /* DXR1 */ - return 0x0000; - - case 0x08: /* SPCR2 */ - return s->spcr[1]; - case 0x0a: /* SPCR1 */ - return s->spcr[0]; - case 0x0c: /* RCR2 */ - return s->rcr[1]; - case 0x0e: /* RCR1 */ - return s->rcr[0]; - case 0x10: /* XCR2 */ - return s->xcr[1]; - case 0x12: /* XCR1 */ - return s->xcr[0]; - case 0x14: /* SRGR2 */ - return s->srgr[1]; - case 0x16: /* SRGR1 */ - return s->srgr[0]; - case 0x18: /* MCR2 */ - return s->mcr[1]; - case 0x1a: /* MCR1 */ - return s->mcr[0]; - case 0x1c: /* RCERA */ - return s->rcer[0]; - case 0x1e: /* RCERB */ - return s->rcer[1]; - case 0x20: /* XCERA */ - return s->xcer[0]; - case 0x22: /* XCERB */ - return s->xcer[1]; - case 0x24: /* PCR0 */ - return s->pcr; - case 0x26: /* RCERC */ - return s->rcer[2]; - case 0x28: /* RCERD */ - return s->rcer[3]; - case 0x2a: /* XCERC */ - return s->xcer[2]; - case 0x2c: /* XCERD */ - return s->xcer[3]; - case 0x2e: /* RCERE */ - return s->rcer[4]; - case 0x30: /* RCERF */ - return s->rcer[5]; - case 0x32: /* XCERE */ - return s->xcer[4]; - case 0x34: /* XCERF */ - return s->xcer[5]; - case 0x36: /* RCERG */ - return s->rcer[6]; - case 0x38: /* RCERH */ - return s->rcer[7]; - case 0x3a: /* XCERG */ - return s->xcer[6]; - case 0x3c: /* XCERH */ - return s->xcer[7]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mcbsp_writeh(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* DRR2 */ - case 0x02: /* DRR1 */ - OMAP_RO_REG(addr); - return; - - case 0x04: /* DXR2 */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ - return; - /* Fall through. */ - case 0x06: /* DXR1 */ - if (s->tx_req > 1) { - s->tx_req -= 2; - if (s->codec && s->codec->cts) { - s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; - } - if (s->tx_req < 2) - omap_mcbsp_tx_done(s); - } else - printf("%s: Tx FIFO overrun\n", __FUNCTION__); - return; - - case 0x08: /* SPCR2 */ - s->spcr[1] &= 0x0002; - s->spcr[1] |= 0x03f9 & value; - s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ - if (~value & 1) /* XRST */ - s->spcr[1] &= ~6; - omap_mcbsp_req_update(s); - return; - case 0x0a: /* SPCR1 */ - s->spcr[0] &= 0x0006; - s->spcr[0] |= 0xf8f9 & value; - if (value & (1 << 15)) /* DLB */ - printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); - if (~value & 1) { /* RRST */ - s->spcr[0] &= ~6; - s->rx_req = 0; - omap_mcbsp_rx_done(s); - } - omap_mcbsp_req_update(s); - return; - - case 0x0c: /* RCR2 */ - s->rcr[1] = value & 0xffff; - return; - case 0x0e: /* RCR1 */ - s->rcr[0] = value & 0x7fe0; - return; - case 0x10: /* XCR2 */ - s->xcr[1] = value & 0xffff; - return; - case 0x12: /* XCR1 */ - s->xcr[0] = value & 0x7fe0; - return; - case 0x14: /* SRGR2 */ - s->srgr[1] = value & 0xffff; - omap_mcbsp_req_update(s); - return; - case 0x16: /* SRGR1 */ - s->srgr[0] = value & 0xffff; - omap_mcbsp_req_update(s); - return; - case 0x18: /* MCR2 */ - s->mcr[1] = value & 0x03e3; - if (value & 3) /* XMCM */ - printf("%s: Tx channel selection mode enable attempt\n", - __FUNCTION__); - return; - case 0x1a: /* MCR1 */ - s->mcr[0] = value & 0x03e1; - if (value & 1) /* RMCM */ - printf("%s: Rx channel selection mode enable attempt\n", - __FUNCTION__); - return; - case 0x1c: /* RCERA */ - s->rcer[0] = value & 0xffff; - return; - case 0x1e: /* RCERB */ - s->rcer[1] = value & 0xffff; - return; - case 0x20: /* XCERA */ - s->xcer[0] = value & 0xffff; - return; - case 0x22: /* XCERB */ - s->xcer[1] = value & 0xffff; - return; - case 0x24: /* PCR0 */ - s->pcr = value & 0x7faf; - return; - case 0x26: /* RCERC */ - s->rcer[2] = value & 0xffff; - return; - case 0x28: /* RCERD */ - s->rcer[3] = value & 0xffff; - return; - case 0x2a: /* XCERC */ - s->xcer[2] = value & 0xffff; - return; - case 0x2c: /* XCERD */ - s->xcer[3] = value & 0xffff; - return; - case 0x2e: /* RCERE */ - s->rcer[4] = value & 0xffff; - return; - case 0x30: /* RCERF */ - s->rcer[5] = value & 0xffff; - return; - case 0x32: /* XCERE */ - s->xcer[4] = value & 0xffff; - return; - case 0x34: /* XCERF */ - s->xcer[5] = value & 0xffff; - return; - case 0x36: /* RCERG */ - s->rcer[6] = value & 0xffff; - return; - case 0x38: /* RCERH */ - s->rcer[7] = value & 0xffff; - return; - case 0x3a: /* XCERG */ - s->xcer[6] = value & 0xffff; - return; - case 0x3c: /* XCERH */ - s->xcer[7] = value & 0xffff; - return; - } - - OMAP_BAD_REG(addr); -} - -static void omap_mcbsp_writew(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (offset == 0x04) { /* DXR */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ - return; - if (s->tx_req > 3) { - s->tx_req -= 4; - if (s->codec && s->codec->cts) { - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 24) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 16) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 8) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 0) & 0xff; - } - if (s->tx_req < 4) - omap_mcbsp_tx_done(s); - } else - printf("%s: Tx FIFO overrun\n", __FUNCTION__); - return; - } - - omap_badwidth_write16(opaque, addr, value); -} - -static void omap_mcbsp_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - switch (size) { - case 2: return omap_mcbsp_writeh(opaque, addr, value); - case 4: return omap_mcbsp_writew(opaque, addr, value); - default: return omap_badwidth_write16(opaque, addr, value); - } -} - -static const MemoryRegionOps omap_mcbsp_ops = { - .read = omap_mcbsp_read, - .write = omap_mcbsp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_mcbsp_reset(struct omap_mcbsp_s *s) -{ - memset(&s->spcr, 0, sizeof(s->spcr)); - memset(&s->rcr, 0, sizeof(s->rcr)); - memset(&s->xcr, 0, sizeof(s->xcr)); - s->srgr[0] = 0x0001; - s->srgr[1] = 0x2000; - memset(&s->mcr, 0, sizeof(s->mcr)); - memset(&s->pcr, 0, sizeof(s->pcr)); - memset(&s->rcer, 0, sizeof(s->rcer)); - memset(&s->xcer, 0, sizeof(s->xcer)); - s->tx_req = 0; - s->rx_req = 0; - s->tx_rate = 0; - s->rx_rate = 0; - qemu_del_timer(s->source_timer); - qemu_del_timer(s->sink_timer); -} - -static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq txirq, qemu_irq rxirq, - qemu_irq *dma, omap_clk clk) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) - g_malloc0(sizeof(struct omap_mcbsp_s)); - - s->txirq = txirq; - s->rxirq = rxirq; - s->txdrq = dma[0]; - s->rxdrq = dma[1]; - s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s); - s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s); - omap_mcbsp_reset(s); - - memory_region_init_io(&s->iomem, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - - if (s->rx_rate) { - s->rx_req = s->codec->in.len; - omap_mcbsp_rx_newdata(s); - } -} - -static void omap_mcbsp_i2s_start(void *opaque, int line, int level) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - - if (s->tx_rate) { - s->tx_req = s->codec->out.size; - omap_mcbsp_tx_newdata(s); - } -} - -void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave) -{ - s->codec = slave; - slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0]; - slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; -} - -/* LED Pulse Generators */ -struct omap_lpg_s { - MemoryRegion iomem; - QEMUTimer *tm; - - uint8_t control; - uint8_t power; - int64_t on; - int64_t period; - int clk; - int cycle; -}; - -static void omap_lpg_tick(void *opaque) -{ - struct omap_lpg_s *s = opaque; - - if (s->cycle) - qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->period - s->on); - else - qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->on); - - s->cycle = !s->cycle; - printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); -} - -static void omap_lpg_update(struct omap_lpg_s *s) -{ - int64_t on, period = 1, ticks = 1000; - static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 }; - - if (~s->control & (1 << 6)) /* LPGRES */ - on = 0; - else if (s->control & (1 << 7)) /* PERM_ON */ - on = period; - else { - period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ - 256 / 32); - on = (s->clk && s->power) ? muldiv64(ticks, - per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ - } - - qemu_del_timer(s->tm); - if (on == period && s->on < s->period) - printf("%s: LED is on\n", __FUNCTION__); - else if (on == 0 && s->on) - printf("%s: LED is off\n", __FUNCTION__); - else if (on && (on != s->on || period != s->period)) { - s->cycle = 0; - s->on = on; - s->period = period; - omap_lpg_tick(s); - return; - } - - s->on = on; - s->period = period; -} - -static void omap_lpg_reset(struct omap_lpg_s *s) -{ - s->control = 0x00; - s->power = 0x00; - s->clk = 1; - omap_lpg_update(s); -} - -static uint64_t omap_lpg_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* LCR */ - return s->control; - - case 0x04: /* PMR */ - return s->power; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_lpg_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_write8(opaque, addr, value); - } - - switch (offset) { - case 0x00: /* LCR */ - if (~value & (1 << 6)) /* LPGRES */ - omap_lpg_reset(s); - s->control = value & 0xff; - omap_lpg_update(s); - return; - - case 0x04: /* PMR */ - s->power = value & 0x01; - omap_lpg_update(s); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_lpg_ops = { - .read = omap_lpg_read, - .write = omap_lpg_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_lpg_clk_update(void *opaque, int line, int on) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - - s->clk = on; - omap_lpg_update(s); -} - -static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, - hwaddr base, omap_clk clk) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) - g_malloc0(sizeof(struct omap_lpg_s)); - - s->tm = qemu_new_timer_ms(vm_clock, omap_lpg_tick, s); - - omap_lpg_reset(s); - - memory_region_init_io(&s->iomem, &omap_lpg_ops, s, "omap-lpg", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]); - - return s; -} - -/* MPUI Peripheral Bridge configuration */ -static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr, - unsigned size) -{ - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - if (addr == OMAP_MPUI_BASE) /* CMR */ - return 0xfe4d; - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpui_io_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - /* FIXME: infinite loop */ - omap_badwidth_write16(opaque, addr, value); -} - -static const MemoryRegionOps omap_mpui_io_ops = { - .read = omap_mpui_io_read, - .write = omap_mpui_io_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_setup_mpui_io(MemoryRegion *system_memory, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->mpui_io_iomem, &omap_mpui_io_ops, mpu, - "omap-mpui-io", 0x7fff); - memory_region_add_subregion(system_memory, OMAP_MPUI_BASE, - &mpu->mpui_io_iomem); -} - -/* General chip reset */ -static void omap1_mpu_reset(void *opaque) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - - omap_dma_reset(mpu->dma); - omap_mpu_timer_reset(mpu->timer[0]); - omap_mpu_timer_reset(mpu->timer[1]); - omap_mpu_timer_reset(mpu->timer[2]); - omap_wd_timer_reset(mpu->wdt); - omap_os_timer_reset(mpu->os_timer); - omap_lcdc_reset(mpu->lcd); - omap_ulpd_pm_reset(mpu); - omap_pin_cfg_reset(mpu); - omap_mpui_reset(mpu); - omap_tipb_bridge_reset(mpu->private_tipb); - omap_tipb_bridge_reset(mpu->public_tipb); - omap_dpll_reset(mpu->dpll[0]); - omap_dpll_reset(mpu->dpll[1]); - omap_dpll_reset(mpu->dpll[2]); - omap_uart_reset(mpu->uart[0]); - omap_uart_reset(mpu->uart[1]); - omap_uart_reset(mpu->uart[2]); - omap_mmc_reset(mpu->mmc); - omap_mpuio_reset(mpu->mpuio); - omap_uwire_reset(mpu->microwire); - omap_pwl_reset(mpu->pwl); - omap_pwt_reset(mpu->pwt); - omap_rtc_reset(mpu->rtc); - omap_mcbsp_reset(mpu->mcbsp1); - omap_mcbsp_reset(mpu->mcbsp2); - omap_mcbsp_reset(mpu->mcbsp3); - omap_lpg_reset(mpu->led[0]); - omap_lpg_reset(mpu->led[1]); - omap_clkm_reset(mpu); - cpu_reset(CPU(mpu->cpu)); -} - -static const struct omap_map_s { - hwaddr phys_dsp; - hwaddr phys_mpu; - uint32_t size; - const char *name; -} omap15xx_dsp_mm[] = { - /* Strobe 0 */ - { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ - { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ - { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ - { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ - { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ - { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ - { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ - { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ - { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ - { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ - { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ - { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ - { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ - { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ - { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ - { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ - { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ - /* Strobe 1 */ - { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ - - { 0 } -}; - -static void omap_setup_dsp_mapping(MemoryRegion *system_memory, - const struct omap_map_s *map) -{ - MemoryRegion *io; - - for (; map->phys_dsp; map ++) { - io = g_new(MemoryRegion, 1); - memory_region_init_alias(io, map->name, - system_memory, map->phys_mpu, map->size); - memory_region_add_subregion(system_memory, map->phys_dsp, io); - } -} - -void omap_mpu_wakeup(void *opaque, int irq, int req) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - - if (mpu->cpu->env.halted) { - cpu_interrupt(&mpu->cpu->env, CPU_INTERRUPT_EXITTB); - } -} - -static const struct dma_irq_map omap1_dma_irq_map[] = { - { 0, OMAP_INT_DMA_CH0_6 }, - { 0, OMAP_INT_DMA_CH1_7 }, - { 0, OMAP_INT_DMA_CH2_8 }, - { 0, OMAP_INT_DMA_CH3 }, - { 0, OMAP_INT_DMA_CH4 }, - { 0, OMAP_INT_DMA_CH5 }, - { 1, OMAP_INT_1610_DMA_CH6 }, - { 1, OMAP_INT_1610_DMA_CH7 }, - { 1, OMAP_INT_1610_DMA_CH8 }, - { 1, OMAP_INT_1610_DMA_CH9 }, - { 1, OMAP_INT_1610_DMA_CH10 }, - { 1, OMAP_INT_1610_DMA_CH11 }, - { 1, OMAP_INT_1610_DMA_CH12 }, - { 1, OMAP_INT_1610_DMA_CH13 }, - { 1, OMAP_INT_1610_DMA_CH14 }, - { 1, OMAP_INT_1610_DMA_CH15 } -}; - -/* DMA ports for OMAP1 */ -static int omap_validate_emiff_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr); -} - -static int omap_validate_emifs_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE, - addr); -} - -static int omap_validate_imif_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr); -} - -static int omap_validate_tipb_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr); -} - -static int omap_validate_local_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr); -} - -static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr); -} - -struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, - unsigned long sdram_size, - const char *core) -{ - int i; - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) - g_malloc0(sizeof(struct omap_mpu_state_s)); - qemu_irq *cpu_irq; - qemu_irq dma_irqs[6]; - DriveInfo *dinfo; - SysBusDevice *busdev; - - if (!core) - core = "ti925t"; - - /* Core */ - s->mpu_model = omap310; - s->cpu = cpu_arm_init(core); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->sdram_size = sdram_size; - s->sram_size = OMAP15XX_SRAM_SIZE; - - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; - - /* Clocks */ - omap_clk_init(s); - - /* Memory-mapped stuff */ - memory_region_init_ram(&s->emiff_ram, "omap1.dram", s->sdram_size); - vmstate_register_ram_global(&s->emiff_ram); - memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram); - memory_region_init_ram(&s->imif_ram, "omap1.sram", s->sram_size); - vmstate_register_ram_global(&s->imif_ram); - memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram); - - omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); - - cpu_irq = arm_pic_init_cpu(s->cpu); - s->ih[0] = qdev_create(NULL, "omap-intc"); - qdev_prop_set_uint32(s->ih[0], "size", 0x100); - qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck")); - qdev_init_nofail(s->ih[0]); - busdev = SYS_BUS_DEVICE(s->ih[0]); - sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); - sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); - sysbus_mmio_map(busdev, 0, 0xfffecb00); - s->ih[1] = qdev_create(NULL, "omap-intc"); - qdev_prop_set_uint32(s->ih[1], "size", 0x800); - qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck")); - qdev_init_nofail(s->ih[1]); - busdev = SYS_BUS_DEVICE(s->ih[1]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ)); - /* The second interrupt controller's FIQ output is not wired up */ - sysbus_mmio_map(busdev, 0, 0xfffe0000); - - for (i = 0; i < 6; i++) { - dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih], - omap1_dma_irq_map[i].intr); - } - s->dma = omap_dma_init(0xfffed800, dma_irqs, system_memory, - qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD), - s, omap_findclk(s, "dma_ck"), omap_dma_3_1); - - s->port[emiff ].addr_valid = omap_validate_emiff_addr; - s->port[emifs ].addr_valid = omap_validate_emifs_addr; - s->port[imif ].addr_valid = omap_validate_imif_addr; - s->port[tipb ].addr_valid = omap_validate_tipb_addr; - s->port[local ].addr_valid = omap_validate_local_addr; - s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; - - /* Register SDRAM and SRAM DMA ports for fast transfers. */ - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram), - OMAP_EMIFF_BASE, s->sdram_size); - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram), - OMAP_IMIF_BASE, s->sram_size); - - s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500, - qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1), - omap_findclk(s, "mputim_ck")); - s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600, - qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2), - omap_findclk(s, "mputim_ck")); - s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700, - qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3), - omap_findclk(s, "mputim_ck")); - - s->wdt = omap_wd_timer_init(system_memory, 0xfffec800, - qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER), - omap_findclk(s, "armwdt_ck")); - - s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER), - omap_findclk(s, "clk32-kHz")); - - s->lcd = omap_lcdc_init(system_memory, 0xfffec000, - qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL), - omap_dma_get_lcdch(s->dma), - omap_findclk(s, "lcd_ck")); - - omap_ulpd_pm_init(system_memory, 0xfffe0800, s); - omap_pin_cfg_init(system_memory, 0xfffe1000, s); - omap_id_init(system_memory, s); - - omap_mpui_init(system_memory, 0xfffec900, s); - - s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00, - qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV), - omap_findclk(s, "tipb_ck")); - s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300, - qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB), - omap_findclk(s, "tipb_ck")); - - omap_tcmi_init(system_memory, 0xfffecc00, s); - - s->uart[0] = omap_uart_init(0xfffb0000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1), - omap_findclk(s, "uart1_ck"), - omap_findclk(s, "uart1_ck"), - s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX], - "uart1", - serial_hds[0]); - s->uart[1] = omap_uart_init(0xfffb0800, - qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2), - omap_findclk(s, "uart2_ck"), - omap_findclk(s, "uart2_ck"), - s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX], - "uart2", - serial_hds[0] ? serial_hds[1] : NULL); - s->uart[2] = omap_uart_init(0xfffb9800, - qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3), - omap_findclk(s, "uart3_ck"), - omap_findclk(s, "uart3_ck"), - s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX], - "uart3", - serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL); - - s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00, - omap_findclk(s, "dpll1")); - s->dpll[1] = omap_dpll_init(system_memory, 0xfffed000, - omap_findclk(s, "dpll2")); - s->dpll[2] = omap_dpll_init(system_memory, 0xfffed100, - omap_findclk(s, "dpll3")); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = omap_mmc_init(0xfffb7800, system_memory, dinfo->bdrv, - qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN), - &s->drq[OMAP_DMA_MMC_TX], - omap_findclk(s, "mmc_ck")); - - s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD), - qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO), - s->wakeup, omap_findclk(s, "clk32-kHz")); - - s->gpio = qdev_create(NULL, "omap-gpio"); - qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); - qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck")); - qdev_init_nofail(s->gpio); - sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1)); - sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000); - - s->microwire = omap_uwire_init(system_memory, 0xfffb3000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX), - qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX), - s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); - - s->pwl = omap_pwl_init(system_memory, 0xfffb5800, - omap_findclk(s, "armxor_ck")); - s->pwt = omap_pwt_init(system_memory, 0xfffb6000, - omap_findclk(s, "armxor_ck")); - - s->i2c[0] = qdev_create(NULL, "omap_i2c"); - qdev_prop_set_uint8(s->i2c[0], "revision", 0x11); - qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck")); - qdev_init_nofail(s->i2c[0]); - busdev = SYS_BUS_DEVICE(s->i2c[0]); - sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C)); - sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]); - sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]); - sysbus_mmio_map(busdev, 0, 0xfffb3800); - - s->rtc = omap_rtc_init(system_memory, 0xfffb4800, - qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER), - qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM), - omap_findclk(s, "clk32-kHz")); - - s->mcbsp1 = omap_mcbsp_init(system_memory, 0xfffb1800, - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX), - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX), - &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); - s->mcbsp2 = omap_mcbsp_init(system_memory, 0xfffb1000, - qdev_get_gpio_in(s->ih[0], - OMAP_INT_310_McBSP2_TX), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_310_McBSP2_RX), - &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); - s->mcbsp3 = omap_mcbsp_init(system_memory, 0xfffb7000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX), - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX), - &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); - - s->led[0] = omap_lpg_init(system_memory, - 0xfffbd000, omap_findclk(s, "clk32-kHz")); - s->led[1] = omap_lpg_init(system_memory, - 0xfffbd800, omap_findclk(s, "clk32-kHz")); - - /* Register mappings not currenlty implemented: - * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) - * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) - * USB W2FC fffb4000 - fffb47ff - * Camera Interface fffb6800 - fffb6fff - * USB Host fffba000 - fffba7ff - * FAC fffba800 - fffbafff - * HDQ/1-Wire fffbc000 - fffbc7ff - * TIPB switches fffbc800 - fffbcfff - * Mailbox fffcf000 - fffcf7ff - * Local bus IF fffec100 - fffec1ff - * Local bus MMU fffec200 - fffec2ff - * DSP MMU fffed200 - fffed2ff - */ - - omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm); - omap_setup_mpui_io(system_memory, s); - - qemu_register_reset(omap1_mpu_reset, s); - - return s; -} diff --git a/hw/omap2.c b/hw/omap2.c deleted file mode 100644 index 0a2cd7bab6..0000000000 --- a/hw/omap2.c +++ /dev/null @@ -1,2684 +0,0 @@ -/* - * TI OMAP processors emulation. - * - * Copyright (C) 2007-2008 Nokia Corporation - * Written by Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "sysemu/blockdev.h" -#include "hw/hw.h" -#include "hw/arm-misc.h" -#include "hw/omap.h" -#include "sysemu/sysemu.h" -#include "qemu/timer.h" -#include "char/char.h" -#include "hw/flash.h" -#include "hw/soc_dma.h" -#include "hw/sysbus.h" -#include "audio/audio.h" - -/* Enhanced Audio Controller (CODEC only) */ -struct omap_eac_s { - qemu_irq irq; - MemoryRegion iomem; - - uint16_t sysconfig; - uint8_t config[4]; - uint8_t control; - uint8_t address; - uint16_t data; - uint8_t vtol; - uint8_t vtsl; - uint16_t mixer; - uint16_t gain[4]; - uint8_t att; - uint16_t max[7]; - - struct { - qemu_irq txdrq; - qemu_irq rxdrq; - uint32_t (*txrx)(void *opaque, uint32_t, int); - void *opaque; - -#define EAC_BUF_LEN 1024 - uint32_t rxbuf[EAC_BUF_LEN]; - int rxoff; - int rxlen; - int rxavail; - uint32_t txbuf[EAC_BUF_LEN]; - int txlen; - int txavail; - - int enable; - int rate; - - uint16_t config[4]; - - /* These need to be moved to the actual codec */ - QEMUSoundCard card; - SWVoiceIn *in_voice; - SWVoiceOut *out_voice; - int hw_enable; - } codec; - - struct { - uint8_t control; - uint16_t config; - } modem, bt; -}; - -static inline void omap_eac_interrupt_update(struct omap_eac_s *s) -{ - qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */ -} - -static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s) -{ - qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) && - ((s->codec.config[1] >> 12) & 1)); /* DMAREN */ -} - -static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s) -{ - qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail && - ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */ -} - -static inline void omap_eac_in_refill(struct omap_eac_s *s) -{ - int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2; - int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2; - int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start); - int recv = 1; - uint8_t *buf = (uint8_t *) s->codec.rxbuf + start; - - left -= leftwrap; - start = 0; - while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start, - leftwrap)) > 0) { /* Be defensive */ - start += recv; - leftwrap -= recv; - } - if (recv <= 0) - s->codec.rxavail = 0; - else - s->codec.rxavail -= start >> 2; - s->codec.rxlen += start >> 2; - - if (recv > 0 && left > 0) { - start = 0; - while (left && (recv = AUD_read(s->codec.in_voice, - (uint8_t *) s->codec.rxbuf + start, - left)) > 0) { /* Be defensive */ - start += recv; - left -= recv; - } - if (recv <= 0) - s->codec.rxavail = 0; - else - s->codec.rxavail -= start >> 2; - s->codec.rxlen += start >> 2; - } -} - -static inline void omap_eac_out_empty(struct omap_eac_s *s) -{ - int left = s->codec.txlen << 2; - int start = 0; - int sent = 1; - - while (left && (sent = AUD_write(s->codec.out_voice, - (uint8_t *) s->codec.txbuf + start, - left)) > 0) { /* Be defensive */ - start += sent; - left -= sent; - } - - if (!sent) { - s->codec.txavail = 0; - omap_eac_out_dmarequest_update(s); - } - - if (start) - s->codec.txlen = 0; -} - -static void omap_eac_in_cb(void *opaque, int avail_b) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - - s->codec.rxavail = avail_b >> 2; - omap_eac_in_refill(s); - /* TODO: possibly discard current buffer if overrun */ - omap_eac_in_dmarequest_update(s); -} - -static void omap_eac_out_cb(void *opaque, int free_b) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - - s->codec.txavail = free_b >> 2; - if (s->codec.txlen) - omap_eac_out_empty(s); - else - omap_eac_out_dmarequest_update(s); -} - -static void omap_eac_enable_update(struct omap_eac_s *s) -{ - s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */ - (s->codec.config[1] & 2) && /* AUDEN */ - s->codec.hw_enable; -} - -static const int omap_eac_fsint[4] = { - 8000, - 11025, - 22050, - 44100, -}; - -static const int omap_eac_fsint2[8] = { - 8000, - 11025, - 22050, - 44100, - 48000, - 0, 0, 0, -}; - -static const int omap_eac_fsint3[16] = { - 8000, - 11025, - 16000, - 22050, - 24000, - 32000, - 44100, - 48000, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static void omap_eac_rate_update(struct omap_eac_s *s) -{ - int fsint[3]; - - fsint[2] = (s->codec.config[3] >> 9) & 0xf; - fsint[1] = (s->codec.config[2] >> 0) & 0x7; - fsint[0] = (s->codec.config[0] >> 6) & 0x3; - if (fsint[2] < 0xf) - s->codec.rate = omap_eac_fsint3[fsint[2]]; - else if (fsint[1] < 0x7) - s->codec.rate = omap_eac_fsint2[fsint[1]]; - else - s->codec.rate = omap_eac_fsint[fsint[0]]; -} - -static void omap_eac_volume_update(struct omap_eac_s *s) -{ - /* TODO */ -} - -static void omap_eac_format_update(struct omap_eac_s *s) -{ - struct audsettings fmt; - - /* The hardware buffers at most one sample */ - if (s->codec.rxlen) - s->codec.rxlen = 1; - - if (s->codec.in_voice) { - AUD_set_active_in(s->codec.in_voice, 0); - AUD_close_in(&s->codec.card, s->codec.in_voice); - s->codec.in_voice = NULL; - } - if (s->codec.out_voice) { - omap_eac_out_empty(s); - AUD_set_active_out(s->codec.out_voice, 0); - AUD_close_out(&s->codec.card, s->codec.out_voice); - s->codec.out_voice = NULL; - s->codec.txavail = 0; - } - /* Discard what couldn't be written */ - s->codec.txlen = 0; - - omap_eac_enable_update(s); - if (!s->codec.enable) - return; - - omap_eac_rate_update(s); - fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */ - fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */ - fmt.freq = s->codec.rate; - /* TODO: signedness possibly depends on the CODEC hardware - or - * does I2S specify it? */ - /* All register writes are 16 bits so we we store 16-bit samples - * in the buffers regardless of AGCFR[B8_16] value. */ - fmt.fmt = AUD_FMT_U16; - - s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice, - "eac.codec.in", s, omap_eac_in_cb, &fmt); - s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice, - "eac.codec.out", s, omap_eac_out_cb, &fmt); - - omap_eac_volume_update(s); - - AUD_set_active_in(s->codec.in_voice, 1); - AUD_set_active_out(s->codec.out_voice, 1); -} - -static void omap_eac_reset(struct omap_eac_s *s) -{ - s->sysconfig = 0; - s->config[0] = 0x0c; - s->config[1] = 0x09; - s->config[2] = 0xab; - s->config[3] = 0x03; - s->control = 0x00; - s->address = 0x00; - s->data = 0x0000; - s->vtol = 0x00; - s->vtsl = 0x00; - s->mixer = 0x0000; - s->gain[0] = 0xe7e7; - s->gain[1] = 0x6767; - s->gain[2] = 0x6767; - s->gain[3] = 0x6767; - s->att = 0xce; - s->max[0] = 0; - s->max[1] = 0; - s->max[2] = 0; - s->max[3] = 0; - s->max[4] = 0; - s->max[5] = 0; - s->max[6] = 0; - - s->modem.control = 0x00; - s->modem.config = 0x0000; - s->bt.control = 0x00; - s->bt.config = 0x0000; - s->codec.config[0] = 0x0649; - s->codec.config[1] = 0x0000; - s->codec.config[2] = 0x0007; - s->codec.config[3] = 0x1ffc; - s->codec.rxoff = 0; - s->codec.rxlen = 0; - s->codec.txlen = 0; - s->codec.rxavail = 0; - s->codec.txavail = 0; - - omap_eac_format_update(s); - omap_eac_interrupt_update(s); -} - -static uint64_t omap_eac_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - uint32_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x000: /* CPCFR1 */ - return s->config[0]; - case 0x004: /* CPCFR2 */ - return s->config[1]; - case 0x008: /* CPCFR3 */ - return s->config[2]; - case 0x00c: /* CPCFR4 */ - return s->config[3]; - - case 0x010: /* CPTCTL */ - return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) | - ((s->codec.txlen < s->codec.txavail) << 5); - - case 0x014: /* CPTTADR */ - return s->address; - case 0x018: /* CPTDATL */ - return s->data & 0xff; - case 0x01c: /* CPTDATH */ - return s->data >> 8; - case 0x020: /* CPTVSLL */ - return s->vtol; - case 0x024: /* CPTVSLH */ - return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */ - case 0x040: /* MPCTR */ - return s->modem.control; - case 0x044: /* MPMCCFR */ - return s->modem.config; - case 0x060: /* BPCTR */ - return s->bt.control; - case 0x064: /* BPMCCFR */ - return s->bt.config; - case 0x080: /* AMSCFR */ - return s->mixer; - case 0x084: /* AMVCTR */ - return s->gain[0]; - case 0x088: /* AM1VCTR */ - return s->gain[1]; - case 0x08c: /* AM2VCTR */ - return s->gain[2]; - case 0x090: /* AM3VCTR */ - return s->gain[3]; - case 0x094: /* ASTCTR */ - return s->att; - case 0x098: /* APD1LCR */ - return s->max[0]; - case 0x09c: /* APD1RCR */ - return s->max[1]; - case 0x0a0: /* APD2LCR */ - return s->max[2]; - case 0x0a4: /* APD2RCR */ - return s->max[3]; - case 0x0a8: /* APD3LCR */ - return s->max[4]; - case 0x0ac: /* APD3RCR */ - return s->max[5]; - case 0x0b0: /* APD4R */ - return s->max[6]; - case 0x0b4: /* ADWR */ - /* This should be write-only? Docs list it as read-only. */ - return 0x0000; - case 0x0b8: /* ADRDR */ - if (likely(s->codec.rxlen > 1)) { - ret = s->codec.rxbuf[s->codec.rxoff ++]; - s->codec.rxlen --; - s->codec.rxoff &= EAC_BUF_LEN - 1; - return ret; - } else if (s->codec.rxlen) { - ret = s->codec.rxbuf[s->codec.rxoff ++]; - s->codec.rxlen --; - s->codec.rxoff &= EAC_BUF_LEN - 1; - if (s->codec.rxavail) - omap_eac_in_refill(s); - omap_eac_in_dmarequest_update(s); - return ret; - } - return 0x0000; - case 0x0bc: /* AGCFR */ - return s->codec.config[0]; - case 0x0c0: /* AGCTR */ - return s->codec.config[1] | ((s->codec.config[1] & 2) << 14); - case 0x0c4: /* AGCFR2 */ - return s->codec.config[2]; - case 0x0c8: /* AGCFR3 */ - return s->codec.config[3]; - case 0x0cc: /* MBPDMACTR */ - case 0x0d0: /* MPDDMARR */ - case 0x0d8: /* MPUDMARR */ - case 0x0e4: /* BPDDMARR */ - case 0x0ec: /* BPUDMARR */ - return 0x0000; - - case 0x100: /* VERSION_NUMBER */ - return 0x0010; - - case 0x104: /* SYSCONFIG */ - return s->sysconfig; - - case 0x108: /* SYSSTATUS */ - return 1 | 0xe; /* RESETDONE | stuff */ - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_eac_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - - if (size != 2) { - return omap_badwidth_write16(opaque, addr, value); - } - - switch (addr) { - case 0x098: /* APD1LCR */ - case 0x09c: /* APD1RCR */ - case 0x0a0: /* APD2LCR */ - case 0x0a4: /* APD2RCR */ - case 0x0a8: /* APD3LCR */ - case 0x0ac: /* APD3RCR */ - case 0x0b0: /* APD4R */ - case 0x0b8: /* ADRDR */ - case 0x0d0: /* MPDDMARR */ - case 0x0d8: /* MPUDMARR */ - case 0x0e4: /* BPDDMARR */ - case 0x0ec: /* BPUDMARR */ - case 0x100: /* VERSION_NUMBER */ - case 0x108: /* SYSSTATUS */ - OMAP_RO_REG(addr); - return; - - case 0x000: /* CPCFR1 */ - s->config[0] = value & 0xff; - omap_eac_format_update(s); - break; - case 0x004: /* CPCFR2 */ - s->config[1] = value & 0xff; - omap_eac_format_update(s); - break; - case 0x008: /* CPCFR3 */ - s->config[2] = value & 0xff; - omap_eac_format_update(s); - break; - case 0x00c: /* CPCFR4 */ - s->config[3] = value & 0xff; - omap_eac_format_update(s); - break; - - case 0x010: /* CPTCTL */ - /* Assuming TXF and TXE bits are read-only... */ - s->control = value & 0x5f; - omap_eac_interrupt_update(s); - break; - - case 0x014: /* CPTTADR */ - s->address = value & 0xff; - break; - case 0x018: /* CPTDATL */ - s->data &= 0xff00; - s->data |= value & 0xff; - break; - case 0x01c: /* CPTDATH */ - s->data &= 0x00ff; - s->data |= value << 8; - break; - case 0x020: /* CPTVSLL */ - s->vtol = value & 0xf8; - break; - case 0x024: /* CPTVSLH */ - s->vtsl = value & 0x9f; - break; - case 0x040: /* MPCTR */ - s->modem.control = value & 0x8f; - break; - case 0x044: /* MPMCCFR */ - s->modem.config = value & 0x7fff; - break; - case 0x060: /* BPCTR */ - s->bt.control = value & 0x8f; - break; - case 0x064: /* BPMCCFR */ - s->bt.config = value & 0x7fff; - break; - case 0x080: /* AMSCFR */ - s->mixer = value & 0x0fff; - break; - case 0x084: /* AMVCTR */ - s->gain[0] = value & 0xffff; - break; - case 0x088: /* AM1VCTR */ - s->gain[1] = value & 0xff7f; - break; - case 0x08c: /* AM2VCTR */ - s->gain[2] = value & 0xff7f; - break; - case 0x090: /* AM3VCTR */ - s->gain[3] = value & 0xff7f; - break; - case 0x094: /* ASTCTR */ - s->att = value & 0xff; - break; - - case 0x0b4: /* ADWR */ - s->codec.txbuf[s->codec.txlen ++] = value; - if (unlikely(s->codec.txlen == EAC_BUF_LEN || - s->codec.txlen == s->codec.txavail)) { - if (s->codec.txavail) - omap_eac_out_empty(s); - /* Discard what couldn't be written */ - s->codec.txlen = 0; - } - break; - - case 0x0bc: /* AGCFR */ - s->codec.config[0] = value & 0x07ff; - omap_eac_format_update(s); - break; - case 0x0c0: /* AGCTR */ - s->codec.config[1] = value & 0x780f; - omap_eac_format_update(s); - break; - case 0x0c4: /* AGCFR2 */ - s->codec.config[2] = value & 0x003f; - omap_eac_format_update(s); - break; - case 0x0c8: /* AGCFR3 */ - s->codec.config[3] = value & 0xffff; - omap_eac_format_update(s); - break; - case 0x0cc: /* MBPDMACTR */ - case 0x0d4: /* MPDDMAWR */ - case 0x0e0: /* MPUDMAWR */ - case 0x0e8: /* BPDDMAWR */ - case 0x0f0: /* BPUDMAWR */ - break; - - case 0x104: /* SYSCONFIG */ - if (value & (1 << 1)) /* SOFTRESET */ - omap_eac_reset(s); - s->sysconfig = value & 0x31d; - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_eac_ops = { - .read = omap_eac_read, - .write = omap_eac_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, - qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) -{ - struct omap_eac_s *s = (struct omap_eac_s *) - g_malloc0(sizeof(struct omap_eac_s)); - - s->irq = irq; - s->codec.rxdrq = *drq ++; - s->codec.txdrq = *drq; - omap_eac_reset(s); - - AUD_register_card("OMAP EAC", &s->codec.card); - - memory_region_init_io(&s->iomem, &omap_eac_ops, s, "omap.eac", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - return s; -} - -/* STI/XTI (emulation interface) console - reverse engineered only */ -struct omap_sti_s { - qemu_irq irq; - MemoryRegion iomem; - MemoryRegion iomem_fifo; - CharDriverState *chr; - - uint32_t sysconfig; - uint32_t systest; - uint32_t irqst; - uint32_t irqen; - uint32_t clkcontrol; - uint32_t serial_config; -}; - -#define STI_TRACE_CONSOLE_CHANNEL 239 -#define STI_TRACE_CONTROL_CHANNEL 253 - -static inline void omap_sti_interrupt_update(struct omap_sti_s *s) -{ - qemu_set_irq(s->irq, s->irqst & s->irqen); -} - -static void omap_sti_reset(struct omap_sti_s *s) -{ - s->sysconfig = 0; - s->irqst = 0; - s->irqen = 0; - s->clkcontrol = 0; - s->serial_config = 0; - - omap_sti_interrupt_update(s); -} - -static uint64_t omap_sti_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_sti_s *s = (struct omap_sti_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* STI_REVISION */ - return 0x10; - - case 0x10: /* STI_SYSCONFIG */ - return s->sysconfig; - - case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ - return 0x00; - - case 0x18: /* STI_IRQSTATUS */ - return s->irqst; - - case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ - return s->irqen; - - case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ - case 0x28: /* STI_RX_DR / XTI_RXDATA */ - /* TODO */ - return 0; - - case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ - return s->clkcontrol; - - case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ - return s->serial_config; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_sti_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_sti_s *s = (struct omap_sti_s *) opaque; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* STI_REVISION */ - case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ - OMAP_RO_REG(addr); - return; - - case 0x10: /* STI_SYSCONFIG */ - if (value & (1 << 1)) /* SOFTRESET */ - omap_sti_reset(s); - s->sysconfig = value & 0xfe; - break; - - case 0x18: /* STI_IRQSTATUS */ - s->irqst &= ~value; - omap_sti_interrupt_update(s); - break; - - case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ - s->irqen = value & 0xffff; - omap_sti_interrupt_update(s); - break; - - case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ - s->clkcontrol = value & 0xff; - break; - - case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ - s->serial_config = value & 0xff; - break; - - case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ - case 0x28: /* STI_RX_DR / XTI_RXDATA */ - /* TODO */ - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_sti_ops = { - .read = omap_sti_read, - .write = omap_sti_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, - unsigned size) -{ - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_sti_fifo_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_sti_s *s = (struct omap_sti_s *) opaque; - int ch = addr >> 6; - uint8_t byte = value; - - if (size != 1) { - return omap_badwidth_write8(opaque, addr, size); - } - - if (ch == STI_TRACE_CONTROL_CHANNEL) { - /* Flush channel value. */ - qemu_chr_fe_write(s->chr, (const uint8_t *) "\r", 1); - } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) { - if (value == 0xc0 || value == 0xc3) { - /* Open channel ch. */ - } else if (value == 0x00) - qemu_chr_fe_write(s->chr, (const uint8_t *) "\n", 1); - else - qemu_chr_fe_write(s->chr, &byte, 1); - } -} - -static const MemoryRegionOps omap_sti_fifo_ops = { - .read = omap_sti_fifo_read, - .write = omap_sti_fifo_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta, - MemoryRegion *sysmem, - hwaddr channel_base, qemu_irq irq, omap_clk clk, - CharDriverState *chr) -{ - struct omap_sti_s *s = (struct omap_sti_s *) - g_malloc0(sizeof(struct omap_sti_s)); - - s->irq = irq; - omap_sti_reset(s); - - s->chr = chr ?: qemu_chr_new("null", "null", NULL); - - memory_region_init_io(&s->iomem, &omap_sti_ops, s, "omap.sti", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - memory_region_init_io(&s->iomem_fifo, &omap_sti_fifo_ops, s, - "omap.sti.fifo", 0x10000); - memory_region_add_subregion(sysmem, channel_base, &s->iomem_fifo); - - return s; -} - -/* L4 Interconnect */ -#define L4TA(n) (n) -#define L4TAO(n) ((n) + 39) - -static const struct omap_l4_region_s omap_l4_region[125] = { - [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */ - [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */ - [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */ - [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */ - [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */ - [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */ - [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */ - [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */ - [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */ - [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */ - [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */ - [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */ - [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */ - [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */ - [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */ - [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */ - [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */ - [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */ - [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */ - [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */ - [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */ - [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */ - [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */ - [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */ - [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */ - [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */ - [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */ - [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */ - [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */ - [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */ - [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */ - [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */ - [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */ - [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */ - [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */ - [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */ - [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */ - [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */ - [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */ - [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */ - [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */ - [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */ - [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */ - [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */ - [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */ - [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */ - [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */ - [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */ - [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */ - [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */ - [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */ - [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */ - [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */ - [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */ - [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */ - [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */ - [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */ - [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */ - [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */ - [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */ - [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */ - [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */ - [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */ - [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */ - [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */ - [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */ - [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */ - [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */ - [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */ - [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */ - [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */ - [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */ - [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */ - [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */ - [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */ - [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */ - [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */ - [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */ - [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */ - [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */ - [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */ - [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */ - [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */ - [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */ - [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */ - [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */ - [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */ - [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */ - [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */ - [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */ - [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */ - [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */ - [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */ - [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */ - [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */ - [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */ - [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */ - [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */ - [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */ - [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */ - [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */ - [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */ - [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */ - [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */ - [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */ - [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */ - [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */ - [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */ - [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */ - [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */ - [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */ - [111] = { 0xa0000, 0x1000, 32 }, /* RNG */ - [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */ - [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */ - [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */ - [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */ - [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */ - [117] = { 0xa6000, 0x1000, 32 }, /* AES */ - [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */ - [119] = { 0xa8000, 0x2000, 32 }, /* PKA */ - [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */ - [121] = { 0xb0000, 0x1000, 32 }, /* MG */ - [122] = { 0xb1000, 0x1000, 32 | 16 | 8 }, - [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */ - [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */ -}; - -static const struct omap_l4_agent_info_s omap_l4_agent_info[54] = { - { 0, 0, 3, 2 }, /* L4IA initiatior agent */ - { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */ - { L4TAO(2), 5, 2, 1 }, /* 32K timer */ - { L4TAO(3), 7, 3, 2 }, /* PRCM */ - { L4TA(1), 10, 2, 1 }, /* BCM */ - { L4TA(2), 12, 2, 1 }, /* Test JTAG */ - { L4TA(3), 14, 6, 3 }, /* Quad GPIO */ - { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */ - { L4TA(7), 24, 2, 1 }, /* GP timer 1 */ - { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */ - { L4TA(10), 28, 5, 4 }, /* Display subsystem */ - { L4TA(11), 33, 5, 4 }, /* Camera subsystem */ - { L4TA(12), 38, 2, 1 }, /* sDMA */ - { L4TA(13), 40, 5, 4 }, /* SSI */ - { L4TAO(4), 45, 2, 1 }, /* USB */ - { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */ - { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */ - { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */ - { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */ - { L4TA(18), 55, 2, 1 }, /* XTI */ - { L4TA(19), 57, 2, 1 }, /* UART1 */ - { L4TA(20), 59, 2, 1 }, /* UART2 */ - { L4TA(21), 61, 2, 1 }, /* UART3 */ - { L4TAO(5), 63, 2, 1 }, /* I2C1 */ - { L4TAO(6), 65, 2, 1 }, /* I2C2 */ - { L4TAO(7), 67, 2, 1 }, /* McBSP1 */ - { L4TAO(8), 69, 2, 1 }, /* McBSP2 */ - { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */ - { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */ - { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */ - { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */ - { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */ - { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */ - { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */ - { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */ - { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */ - { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */ - { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */ - { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */ - { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */ - { L4TA(32), 97, 2, 1 }, /* EAC */ - { L4TA(33), 99, 2, 1 }, /* FAC */ - { L4TA(34), 101, 2, 1 }, /* IPC */ - { L4TA(35), 103, 2, 1 }, /* SPI1 */ - { L4TA(36), 105, 2, 1 }, /* SPI2 */ - { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */ - { L4TAO(10), 109, 2, 1 }, - { L4TAO(11), 111, 2, 1 }, /* RNG */ - { L4TAO(12), 113, 2, 1 }, /* DES3DES */ - { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */ - { L4TA(37), 117, 2, 1 }, /* AES */ - { L4TA(38), 119, 2, 1 }, /* PKA */ - { -1, 121, 2, 1 }, - { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */ -}; - -#define omap_l4ta(bus, cs) \ - omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TA(cs)) -#define omap_l4tao(bus, cs) \ - omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TAO(cs)) - -/* Power, Reset, and Clock Management */ -struct omap_prcm_s { - qemu_irq irq[3]; - struct omap_mpu_state_s *mpu; - MemoryRegion iomem0; - MemoryRegion iomem1; - - uint32_t irqst[3]; - uint32_t irqen[3]; - - uint32_t sysconfig; - uint32_t voltctrl; - uint32_t scratch[20]; - - uint32_t clksrc[1]; - uint32_t clkout[1]; - uint32_t clkemul[1]; - uint32_t clkpol[1]; - uint32_t clksel[8]; - uint32_t clken[12]; - uint32_t clkctrl[4]; - uint32_t clkidle[7]; - uint32_t setuptime[2]; - - uint32_t wkup[3]; - uint32_t wken[3]; - uint32_t wkst[3]; - uint32_t rst[4]; - uint32_t rstctrl[1]; - uint32_t power[4]; - uint32_t rsttime_wkup; - - uint32_t ev; - uint32_t evtime[2]; - - int dpll_lock, apll_lock[2]; -}; - -static void omap_prcm_int_update(struct omap_prcm_s *s, int dom) -{ - qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]); - /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */ -} - -static uint64_t omap_prcm_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; - uint32_t ret; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x000: /* PRCM_REVISION */ - return 0x10; - - case 0x010: /* PRCM_SYSCONFIG */ - return s->sysconfig; - - case 0x018: /* PRCM_IRQSTATUS_MPU */ - return s->irqst[0]; - - case 0x01c: /* PRCM_IRQENABLE_MPU */ - return s->irqen[0]; - - case 0x050: /* PRCM_VOLTCTRL */ - return s->voltctrl; - case 0x054: /* PRCM_VOLTST */ - return s->voltctrl & 3; - - case 0x060: /* PRCM_CLKSRC_CTRL */ - return s->clksrc[0]; - case 0x070: /* PRCM_CLKOUT_CTRL */ - return s->clkout[0]; - case 0x078: /* PRCM_CLKEMUL_CTRL */ - return s->clkemul[0]; - case 0x080: /* PRCM_CLKCFG_CTRL */ - case 0x084: /* PRCM_CLKCFG_STATUS */ - return 0; - - case 0x090: /* PRCM_VOLTSETUP */ - return s->setuptime[0]; - - case 0x094: /* PRCM_CLKSSETUP */ - return s->setuptime[1]; - - case 0x098: /* PRCM_POLCTRL */ - return s->clkpol[0]; - - case 0x0b0: /* GENERAL_PURPOSE1 */ - case 0x0b4: /* GENERAL_PURPOSE2 */ - case 0x0b8: /* GENERAL_PURPOSE3 */ - case 0x0bc: /* GENERAL_PURPOSE4 */ - case 0x0c0: /* GENERAL_PURPOSE5 */ - case 0x0c4: /* GENERAL_PURPOSE6 */ - case 0x0c8: /* GENERAL_PURPOSE7 */ - case 0x0cc: /* GENERAL_PURPOSE8 */ - case 0x0d0: /* GENERAL_PURPOSE9 */ - case 0x0d4: /* GENERAL_PURPOSE10 */ - case 0x0d8: /* GENERAL_PURPOSE11 */ - case 0x0dc: /* GENERAL_PURPOSE12 */ - case 0x0e0: /* GENERAL_PURPOSE13 */ - case 0x0e4: /* GENERAL_PURPOSE14 */ - case 0x0e8: /* GENERAL_PURPOSE15 */ - case 0x0ec: /* GENERAL_PURPOSE16 */ - case 0x0f0: /* GENERAL_PURPOSE17 */ - case 0x0f4: /* GENERAL_PURPOSE18 */ - case 0x0f8: /* GENERAL_PURPOSE19 */ - case 0x0fc: /* GENERAL_PURPOSE20 */ - return s->scratch[(addr - 0xb0) >> 2]; - - case 0x140: /* CM_CLKSEL_MPU */ - return s->clksel[0]; - case 0x148: /* CM_CLKSTCTRL_MPU */ - return s->clkctrl[0]; - - case 0x158: /* RM_RSTST_MPU */ - return s->rst[0]; - case 0x1c8: /* PM_WKDEP_MPU */ - return s->wkup[0]; - case 0x1d4: /* PM_EVGENCTRL_MPU */ - return s->ev; - case 0x1d8: /* PM_EVEGENONTIM_MPU */ - return s->evtime[0]; - case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ - return s->evtime[1]; - case 0x1e0: /* PM_PWSTCTRL_MPU */ - return s->power[0]; - case 0x1e4: /* PM_PWSTST_MPU */ - return 0; - - case 0x200: /* CM_FCLKEN1_CORE */ - return s->clken[0]; - case 0x204: /* CM_FCLKEN2_CORE */ - return s->clken[1]; - case 0x210: /* CM_ICLKEN1_CORE */ - return s->clken[2]; - case 0x214: /* CM_ICLKEN2_CORE */ - return s->clken[3]; - case 0x21c: /* CM_ICLKEN4_CORE */ - return s->clken[4]; - - case 0x220: /* CM_IDLEST1_CORE */ - /* TODO: check the actual iclk status */ - return 0x7ffffff9; - case 0x224: /* CM_IDLEST2_CORE */ - /* TODO: check the actual iclk status */ - return 0x00000007; - case 0x22c: /* CM_IDLEST4_CORE */ - /* TODO: check the actual iclk status */ - return 0x0000001f; - - case 0x230: /* CM_AUTOIDLE1_CORE */ - return s->clkidle[0]; - case 0x234: /* CM_AUTOIDLE2_CORE */ - return s->clkidle[1]; - case 0x238: /* CM_AUTOIDLE3_CORE */ - return s->clkidle[2]; - case 0x23c: /* CM_AUTOIDLE4_CORE */ - return s->clkidle[3]; - - case 0x240: /* CM_CLKSEL1_CORE */ - return s->clksel[1]; - case 0x244: /* CM_CLKSEL2_CORE */ - return s->clksel[2]; - - case 0x248: /* CM_CLKSTCTRL_CORE */ - return s->clkctrl[1]; - - case 0x2a0: /* PM_WKEN1_CORE */ - return s->wken[0]; - case 0x2a4: /* PM_WKEN2_CORE */ - return s->wken[1]; - - case 0x2b0: /* PM_WKST1_CORE */ - return s->wkst[0]; - case 0x2b4: /* PM_WKST2_CORE */ - return s->wkst[1]; - case 0x2c8: /* PM_WKDEP_CORE */ - return 0x1e; - - case 0x2e0: /* PM_PWSTCTRL_CORE */ - return s->power[1]; - case 0x2e4: /* PM_PWSTST_CORE */ - return 0x000030 | (s->power[1] & 0xfc00); - - case 0x300: /* CM_FCLKEN_GFX */ - return s->clken[5]; - case 0x310: /* CM_ICLKEN_GFX */ - return s->clken[6]; - case 0x320: /* CM_IDLEST_GFX */ - /* TODO: check the actual iclk status */ - return 0x00000001; - case 0x340: /* CM_CLKSEL_GFX */ - return s->clksel[3]; - case 0x348: /* CM_CLKSTCTRL_GFX */ - return s->clkctrl[2]; - case 0x350: /* RM_RSTCTRL_GFX */ - return s->rstctrl[0]; - case 0x358: /* RM_RSTST_GFX */ - return s->rst[1]; - case 0x3c8: /* PM_WKDEP_GFX */ - return s->wkup[1]; - - case 0x3e0: /* PM_PWSTCTRL_GFX */ - return s->power[2]; - case 0x3e4: /* PM_PWSTST_GFX */ - return s->power[2] & 3; - - case 0x400: /* CM_FCLKEN_WKUP */ - return s->clken[7]; - case 0x410: /* CM_ICLKEN_WKUP */ - return s->clken[8]; - case 0x420: /* CM_IDLEST_WKUP */ - /* TODO: check the actual iclk status */ - return 0x0000003f; - case 0x430: /* CM_AUTOIDLE_WKUP */ - return s->clkidle[4]; - case 0x440: /* CM_CLKSEL_WKUP */ - return s->clksel[4]; - case 0x450: /* RM_RSTCTRL_WKUP */ - return 0; - case 0x454: /* RM_RSTTIME_WKUP */ - return s->rsttime_wkup; - case 0x458: /* RM_RSTST_WKUP */ - return s->rst[2]; - case 0x4a0: /* PM_WKEN_WKUP */ - return s->wken[2]; - case 0x4b0: /* PM_WKST_WKUP */ - return s->wkst[2]; - - case 0x500: /* CM_CLKEN_PLL */ - return s->clken[9]; - case 0x520: /* CM_IDLEST_CKGEN */ - ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8); - if (!(s->clksel[6] & 3)) - /* Core uses 32-kHz clock */ - ret |= 3 << 0; - else if (!s->dpll_lock) - /* DPLL not locked, core uses ref_clk */ - ret |= 1 << 0; - else - /* Core uses DPLL */ - ret |= 2 << 0; - return ret; - case 0x530: /* CM_AUTOIDLE_PLL */ - return s->clkidle[5]; - case 0x540: /* CM_CLKSEL1_PLL */ - return s->clksel[5]; - case 0x544: /* CM_CLKSEL2_PLL */ - return s->clksel[6]; - - case 0x800: /* CM_FCLKEN_DSP */ - return s->clken[10]; - case 0x810: /* CM_ICLKEN_DSP */ - return s->clken[11]; - case 0x820: /* CM_IDLEST_DSP */ - /* TODO: check the actual iclk status */ - return 0x00000103; - case 0x830: /* CM_AUTOIDLE_DSP */ - return s->clkidle[6]; - case 0x840: /* CM_CLKSEL_DSP */ - return s->clksel[7]; - case 0x848: /* CM_CLKSTCTRL_DSP */ - return s->clkctrl[3]; - case 0x850: /* RM_RSTCTRL_DSP */ - return 0; - case 0x858: /* RM_RSTST_DSP */ - return s->rst[3]; - case 0x8c8: /* PM_WKDEP_DSP */ - return s->wkup[2]; - case 0x8e0: /* PM_PWSTCTRL_DSP */ - return s->power[3]; - case 0x8e4: /* PM_PWSTST_DSP */ - return 0x008030 | (s->power[3] & 0x3003); - - case 0x8f0: /* PRCM_IRQSTATUS_DSP */ - return s->irqst[1]; - case 0x8f4: /* PRCM_IRQENABLE_DSP */ - return s->irqen[1]; - - case 0x8f8: /* PRCM_IRQSTATUS_IVA */ - return s->irqst[2]; - case 0x8fc: /* PRCM_IRQENABLE_IVA */ - return s->irqen[2]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_prcm_apll_update(struct omap_prcm_s *s) -{ - int mode[2]; - - mode[0] = (s->clken[9] >> 6) & 3; - s->apll_lock[0] = (mode[0] == 3); - mode[1] = (s->clken[9] >> 2) & 3; - s->apll_lock[1] = (mode[1] == 3); - /* TODO: update clocks */ - - if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[1] == 2) - fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n", - __FUNCTION__); -} - -static void omap_prcm_dpll_update(struct omap_prcm_s *s) -{ - omap_clk dpll = omap_findclk(s->mpu, "dpll"); - omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll"); - omap_clk core = omap_findclk(s->mpu, "core_clk"); - int mode = (s->clken[9] >> 0) & 3; - int mult, div; - - mult = (s->clksel[5] >> 12) & 0x3ff; - div = (s->clksel[5] >> 8) & 0xf; - if (mult == 0 || mult == 1) - mode = 1; /* Bypass */ - - s->dpll_lock = 0; - switch (mode) { - case 0: - fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__); - break; - case 1: /* Low-power bypass mode (Default) */ - case 2: /* Fast-relock bypass mode */ - omap_clk_setrate(dpll, 1, 1); - omap_clk_setrate(dpll_x2, 1, 1); - break; - case 3: /* Lock mode */ - s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */ - - omap_clk_setrate(dpll, div + 1, mult); - omap_clk_setrate(dpll_x2, div + 1, mult * 2); - break; - } - - switch ((s->clksel[6] >> 0) & 3) { - case 0: - omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz")); - break; - case 1: - omap_clk_reparent(core, dpll); - break; - case 2: - /* Default */ - omap_clk_reparent(core, dpll_x2); - break; - case 3: - fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__); - break; - } -} - -static void omap_prcm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x000: /* PRCM_REVISION */ - case 0x054: /* PRCM_VOLTST */ - case 0x084: /* PRCM_CLKCFG_STATUS */ - case 0x1e4: /* PM_PWSTST_MPU */ - case 0x220: /* CM_IDLEST1_CORE */ - case 0x224: /* CM_IDLEST2_CORE */ - case 0x22c: /* CM_IDLEST4_CORE */ - case 0x2c8: /* PM_WKDEP_CORE */ - case 0x2e4: /* PM_PWSTST_CORE */ - case 0x320: /* CM_IDLEST_GFX */ - case 0x3e4: /* PM_PWSTST_GFX */ - case 0x420: /* CM_IDLEST_WKUP */ - case 0x520: /* CM_IDLEST_CKGEN */ - case 0x820: /* CM_IDLEST_DSP */ - case 0x8e4: /* PM_PWSTST_DSP */ - OMAP_RO_REG(addr); - return; - - case 0x010: /* PRCM_SYSCONFIG */ - s->sysconfig = value & 1; - break; - - case 0x018: /* PRCM_IRQSTATUS_MPU */ - s->irqst[0] &= ~value; - omap_prcm_int_update(s, 0); - break; - case 0x01c: /* PRCM_IRQENABLE_MPU */ - s->irqen[0] = value & 0x3f; - omap_prcm_int_update(s, 0); - break; - - case 0x050: /* PRCM_VOLTCTRL */ - s->voltctrl = value & 0xf1c3; - break; - - case 0x060: /* PRCM_CLKSRC_CTRL */ - s->clksrc[0] = value & 0xdb; - /* TODO update clocks */ - break; - - case 0x070: /* PRCM_CLKOUT_CTRL */ - s->clkout[0] = value & 0xbbbb; - /* TODO update clocks */ - break; - - case 0x078: /* PRCM_CLKEMUL_CTRL */ - s->clkemul[0] = value & 1; - /* TODO update clocks */ - break; - - case 0x080: /* PRCM_CLKCFG_CTRL */ - break; - - case 0x090: /* PRCM_VOLTSETUP */ - s->setuptime[0] = value & 0xffff; - break; - case 0x094: /* PRCM_CLKSSETUP */ - s->setuptime[1] = value & 0xffff; - break; - - case 0x098: /* PRCM_POLCTRL */ - s->clkpol[0] = value & 0x701; - break; - - case 0x0b0: /* GENERAL_PURPOSE1 */ - case 0x0b4: /* GENERAL_PURPOSE2 */ - case 0x0b8: /* GENERAL_PURPOSE3 */ - case 0x0bc: /* GENERAL_PURPOSE4 */ - case 0x0c0: /* GENERAL_PURPOSE5 */ - case 0x0c4: /* GENERAL_PURPOSE6 */ - case 0x0c8: /* GENERAL_PURPOSE7 */ - case 0x0cc: /* GENERAL_PURPOSE8 */ - case 0x0d0: /* GENERAL_PURPOSE9 */ - case 0x0d4: /* GENERAL_PURPOSE10 */ - case 0x0d8: /* GENERAL_PURPOSE11 */ - case 0x0dc: /* GENERAL_PURPOSE12 */ - case 0x0e0: /* GENERAL_PURPOSE13 */ - case 0x0e4: /* GENERAL_PURPOSE14 */ - case 0x0e8: /* GENERAL_PURPOSE15 */ - case 0x0ec: /* GENERAL_PURPOSE16 */ - case 0x0f0: /* GENERAL_PURPOSE17 */ - case 0x0f4: /* GENERAL_PURPOSE18 */ - case 0x0f8: /* GENERAL_PURPOSE19 */ - case 0x0fc: /* GENERAL_PURPOSE20 */ - s->scratch[(addr - 0xb0) >> 2] = value; - break; - - case 0x140: /* CM_CLKSEL_MPU */ - s->clksel[0] = value & 0x1f; - /* TODO update clocks */ - break; - case 0x148: /* CM_CLKSTCTRL_MPU */ - s->clkctrl[0] = value & 0x1f; - break; - - case 0x158: /* RM_RSTST_MPU */ - s->rst[0] &= ~value; - break; - case 0x1c8: /* PM_WKDEP_MPU */ - s->wkup[0] = value & 0x15; - break; - - case 0x1d4: /* PM_EVGENCTRL_MPU */ - s->ev = value & 0x1f; - break; - case 0x1d8: /* PM_EVEGENONTIM_MPU */ - s->evtime[0] = value; - break; - case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ - s->evtime[1] = value; - break; - - case 0x1e0: /* PM_PWSTCTRL_MPU */ - s->power[0] = value & 0xc0f; - break; - - case 0x200: /* CM_FCLKEN1_CORE */ - s->clken[0] = value & 0xbfffffff; - /* TODO update clocks */ - /* The EN_EAC bit only gets/puts func_96m_clk. */ - break; - case 0x204: /* CM_FCLKEN2_CORE */ - s->clken[1] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x210: /* CM_ICLKEN1_CORE */ - s->clken[2] = value & 0xfffffff9; - /* TODO update clocks */ - /* The EN_EAC bit only gets/puts core_l4_iclk. */ - break; - case 0x214: /* CM_ICLKEN2_CORE */ - s->clken[3] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x21c: /* CM_ICLKEN4_CORE */ - s->clken[4] = value & 0x0000001f; - /* TODO update clocks */ - break; - - case 0x230: /* CM_AUTOIDLE1_CORE */ - s->clkidle[0] = value & 0xfffffff9; - /* TODO update clocks */ - break; - case 0x234: /* CM_AUTOIDLE2_CORE */ - s->clkidle[1] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x238: /* CM_AUTOIDLE3_CORE */ - s->clkidle[2] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x23c: /* CM_AUTOIDLE4_CORE */ - s->clkidle[3] = value & 0x0000001f; - /* TODO update clocks */ - break; - - case 0x240: /* CM_CLKSEL1_CORE */ - s->clksel[1] = value & 0x0fffbf7f; - /* TODO update clocks */ - break; - - case 0x244: /* CM_CLKSEL2_CORE */ - s->clksel[2] = value & 0x00fffffc; - /* TODO update clocks */ - break; - - case 0x248: /* CM_CLKSTCTRL_CORE */ - s->clkctrl[1] = value & 0x7; - break; - - case 0x2a0: /* PM_WKEN1_CORE */ - s->wken[0] = value & 0x04667ff8; - break; - case 0x2a4: /* PM_WKEN2_CORE */ - s->wken[1] = value & 0x00000005; - break; - - case 0x2b0: /* PM_WKST1_CORE */ - s->wkst[0] &= ~value; - break; - case 0x2b4: /* PM_WKST2_CORE */ - s->wkst[1] &= ~value; - break; - - case 0x2e0: /* PM_PWSTCTRL_CORE */ - s->power[1] = (value & 0x00fc3f) | (1 << 2); - break; - - case 0x300: /* CM_FCLKEN_GFX */ - s->clken[5] = value & 6; - /* TODO update clocks */ - break; - case 0x310: /* CM_ICLKEN_GFX */ - s->clken[6] = value & 1; - /* TODO update clocks */ - break; - case 0x340: /* CM_CLKSEL_GFX */ - s->clksel[3] = value & 7; - /* TODO update clocks */ - break; - case 0x348: /* CM_CLKSTCTRL_GFX */ - s->clkctrl[2] = value & 1; - break; - case 0x350: /* RM_RSTCTRL_GFX */ - s->rstctrl[0] = value & 1; - /* TODO: reset */ - break; - case 0x358: /* RM_RSTST_GFX */ - s->rst[1] &= ~value; - break; - case 0x3c8: /* PM_WKDEP_GFX */ - s->wkup[1] = value & 0x13; - break; - case 0x3e0: /* PM_PWSTCTRL_GFX */ - s->power[2] = (value & 0x00c0f) | (3 << 2); - break; - - case 0x400: /* CM_FCLKEN_WKUP */ - s->clken[7] = value & 0xd; - /* TODO update clocks */ - break; - case 0x410: /* CM_ICLKEN_WKUP */ - s->clken[8] = value & 0x3f; - /* TODO update clocks */ - break; - case 0x430: /* CM_AUTOIDLE_WKUP */ - s->clkidle[4] = value & 0x0000003f; - /* TODO update clocks */ - break; - case 0x440: /* CM_CLKSEL_WKUP */ - s->clksel[4] = value & 3; - /* TODO update clocks */ - break; - case 0x450: /* RM_RSTCTRL_WKUP */ - /* TODO: reset */ - if (value & 2) - qemu_system_reset_request(); - break; - case 0x454: /* RM_RSTTIME_WKUP */ - s->rsttime_wkup = value & 0x1fff; - break; - case 0x458: /* RM_RSTST_WKUP */ - s->rst[2] &= ~value; - break; - case 0x4a0: /* PM_WKEN_WKUP */ - s->wken[2] = value & 0x00000005; - break; - case 0x4b0: /* PM_WKST_WKUP */ - s->wkst[2] &= ~value; - break; - - case 0x500: /* CM_CLKEN_PLL */ - if (value & 0xffffff30) - fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for " - "future compatibility\n", __FUNCTION__); - if ((s->clken[9] ^ value) & 0xcc) { - s->clken[9] &= ~0xcc; - s->clken[9] |= value & 0xcc; - omap_prcm_apll_update(s); - } - if ((s->clken[9] ^ value) & 3) { - s->clken[9] &= ~3; - s->clken[9] |= value & 3; - omap_prcm_dpll_update(s); - } - break; - case 0x530: /* CM_AUTOIDLE_PLL */ - s->clkidle[5] = value & 0x000000cf; - /* TODO update clocks */ - break; - case 0x540: /* CM_CLKSEL1_PLL */ - if (value & 0xfc4000d7) - fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for " - "future compatibility\n", __FUNCTION__); - if ((s->clksel[5] ^ value) & 0x003fff00) { - s->clksel[5] = value & 0x03bfff28; - omap_prcm_dpll_update(s); - } - /* TODO update the other clocks */ - - s->clksel[5] = value & 0x03bfff28; - break; - case 0x544: /* CM_CLKSEL2_PLL */ - if (value & ~3) - fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for " - "future compatibility\n", __FUNCTION__); - if (s->clksel[6] != (value & 3)) { - s->clksel[6] = value & 3; - omap_prcm_dpll_update(s); - } - break; - - case 0x800: /* CM_FCLKEN_DSP */ - s->clken[10] = value & 0x501; - /* TODO update clocks */ - break; - case 0x810: /* CM_ICLKEN_DSP */ - s->clken[11] = value & 0x2; - /* TODO update clocks */ - break; - case 0x830: /* CM_AUTOIDLE_DSP */ - s->clkidle[6] = value & 0x2; - /* TODO update clocks */ - break; - case 0x840: /* CM_CLKSEL_DSP */ - s->clksel[7] = value & 0x3fff; - /* TODO update clocks */ - break; - case 0x848: /* CM_CLKSTCTRL_DSP */ - s->clkctrl[3] = value & 0x101; - break; - case 0x850: /* RM_RSTCTRL_DSP */ - /* TODO: reset */ - break; - case 0x858: /* RM_RSTST_DSP */ - s->rst[3] &= ~value; - break; - case 0x8c8: /* PM_WKDEP_DSP */ - s->wkup[2] = value & 0x13; - break; - case 0x8e0: /* PM_PWSTCTRL_DSP */ - s->power[3] = (value & 0x03017) | (3 << 2); - break; - - case 0x8f0: /* PRCM_IRQSTATUS_DSP */ - s->irqst[1] &= ~value; - omap_prcm_int_update(s, 1); - break; - case 0x8f4: /* PRCM_IRQENABLE_DSP */ - s->irqen[1] = value & 0x7; - omap_prcm_int_update(s, 1); - break; - - case 0x8f8: /* PRCM_IRQSTATUS_IVA */ - s->irqst[2] &= ~value; - omap_prcm_int_update(s, 2); - break; - case 0x8fc: /* PRCM_IRQENABLE_IVA */ - s->irqen[2] = value & 0x7; - omap_prcm_int_update(s, 2); - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_prcm_ops = { - .read = omap_prcm_read, - .write = omap_prcm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_prcm_reset(struct omap_prcm_s *s) -{ - s->sysconfig = 0; - s->irqst[0] = 0; - s->irqst[1] = 0; - s->irqst[2] = 0; - s->irqen[0] = 0; - s->irqen[1] = 0; - s->irqen[2] = 0; - s->voltctrl = 0x1040; - s->ev = 0x14; - s->evtime[0] = 0; - s->evtime[1] = 0; - s->clkctrl[0] = 0; - s->clkctrl[1] = 0; - s->clkctrl[2] = 0; - s->clkctrl[3] = 0; - s->clken[1] = 7; - s->clken[3] = 7; - s->clken[4] = 0; - s->clken[5] = 0; - s->clken[6] = 0; - s->clken[7] = 0xc; - s->clken[8] = 0x3e; - s->clken[9] = 0x0d; - s->clken[10] = 0; - s->clken[11] = 0; - s->clkidle[0] = 0; - s->clkidle[2] = 7; - s->clkidle[3] = 0; - s->clkidle[4] = 0; - s->clkidle[5] = 0x0c; - s->clkidle[6] = 0; - s->clksel[0] = 0x01; - s->clksel[1] = 0x02100121; - s->clksel[2] = 0x00000000; - s->clksel[3] = 0x01; - s->clksel[4] = 0; - s->clksel[7] = 0x0121; - s->wkup[0] = 0x15; - s->wkup[1] = 0x13; - s->wkup[2] = 0x13; - s->wken[0] = 0x04667ff8; - s->wken[1] = 0x00000005; - s->wken[2] = 5; - s->wkst[0] = 0; - s->wkst[1] = 0; - s->wkst[2] = 0; - s->power[0] = 0x00c; - s->power[1] = 4; - s->power[2] = 0x0000c; - s->power[3] = 0x14; - s->rstctrl[0] = 1; - s->rst[3] = 1; - omap_prcm_apll_update(s); - omap_prcm_dpll_update(s); -} - -static void omap_prcm_coldreset(struct omap_prcm_s *s) -{ - s->setuptime[0] = 0; - s->setuptime[1] = 0; - memset(&s->scratch, 0, sizeof(s->scratch)); - s->rst[0] = 0x01; - s->rst[1] = 0x00; - s->rst[2] = 0x01; - s->clken[0] = 0; - s->clken[2] = 0; - s->clkidle[1] = 0; - s->clksel[5] = 0; - s->clksel[6] = 2; - s->clksrc[0] = 0x43; - s->clkout[0] = 0x0303; - s->clkemul[0] = 0; - s->clkpol[0] = 0x100; - s->rsttime_wkup = 0x1002; - - omap_prcm_reset(s); -} - -static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, - qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, - struct omap_mpu_state_s *mpu) -{ - struct omap_prcm_s *s = (struct omap_prcm_s *) - g_malloc0(sizeof(struct omap_prcm_s)); - - s->irq[0] = mpu_int; - s->irq[1] = dsp_int; - s->irq[2] = iva_int; - s->mpu = mpu; - omap_prcm_coldreset(s); - - memory_region_init_io(&s->iomem0, &omap_prcm_ops, s, "omap.pcrm0", - omap_l4_region_size(ta, 0)); - memory_region_init_io(&s->iomem1, &omap_prcm_ops, s, "omap.pcrm1", - omap_l4_region_size(ta, 1)); - omap_l4_attach(ta, 0, &s->iomem0); - omap_l4_attach(ta, 1, &s->iomem1); - - return s; -} - -/* System and Pinout control */ -struct omap_sysctl_s { - struct omap_mpu_state_s *mpu; - MemoryRegion iomem; - - uint32_t sysconfig; - uint32_t devconfig; - uint32_t psaconfig; - uint32_t padconf[0x45]; - uint8_t obs; - uint32_t msuspendmux[5]; -}; - -static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr) -{ - - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - int pad_offset, byte_offset; - int value; - - switch (addr) { - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - pad_offset = (addr - 0x30) >> 2; - byte_offset = (addr - 0x30) & (4 - 1); - - value = s->padconf[pad_offset]; - value = (value >> (byte_offset * 8)) & 0xff; - - return value; - - default: - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static uint32_t omap_sysctl_read(void *opaque, hwaddr addr) -{ - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - - switch (addr) { - case 0x000: /* CONTROL_REVISION */ - return 0x20; - - case 0x010: /* CONTROL_SYSCONFIG */ - return s->sysconfig; - - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - return s->padconf[(addr - 0x30) >> 2]; - - case 0x270: /* CONTROL_DEBOBS */ - return s->obs; - - case 0x274: /* CONTROL_DEVCONF */ - return s->devconfig; - - case 0x28c: /* CONTROL_EMU_SUPPORT */ - return 0; - - case 0x290: /* CONTROL_MSUSPENDMUX_0 */ - return s->msuspendmux[0]; - case 0x294: /* CONTROL_MSUSPENDMUX_1 */ - return s->msuspendmux[1]; - case 0x298: /* CONTROL_MSUSPENDMUX_2 */ - return s->msuspendmux[2]; - case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ - return s->msuspendmux[3]; - case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ - return s->msuspendmux[4]; - case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ - return 0; - - case 0x2b8: /* CONTROL_PSA_CTRL */ - return s->psaconfig; - case 0x2bc: /* CONTROL_PSA_CMD */ - case 0x2c0: /* CONTROL_PSA_VALUE */ - return 0; - - case 0x2b0: /* CONTROL_SEC_CTRL */ - return 0x800000f1; - case 0x2d0: /* CONTROL_SEC_EMU */ - return 0x80000015; - case 0x2d4: /* CONTROL_SEC_TAP */ - return 0x8000007f; - case 0x2b4: /* CONTROL_SEC_TEST */ - case 0x2f0: /* CONTROL_SEC_STATUS */ - case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ - /* Secure mode is not present on general-pusrpose device. Outside - * secure mode these values cannot be read or written. */ - return 0; - - case 0x2d8: /* CONTROL_OCM_RAM_PERM */ - return 0xff; - case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ - case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ - case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ - /* No secure mode so no Extended Secure RAM present. */ - return 0; - - case 0x2f8: /* CONTROL_STATUS */ - /* Device Type => General-purpose */ - return 0x0300; - case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ - - case 0x300: /* CONTROL_RPUB_KEY_H_0 */ - case 0x304: /* CONTROL_RPUB_KEY_H_1 */ - case 0x308: /* CONTROL_RPUB_KEY_H_2 */ - case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ - return 0xdecafbad; - - case 0x310: /* CONTROL_RAND_KEY_0 */ - case 0x314: /* CONTROL_RAND_KEY_1 */ - case 0x318: /* CONTROL_RAND_KEY_2 */ - case 0x31c: /* CONTROL_RAND_KEY_3 */ - case 0x320: /* CONTROL_CUST_KEY_0 */ - case 0x324: /* CONTROL_CUST_KEY_1 */ - case 0x330: /* CONTROL_TEST_KEY_0 */ - case 0x334: /* CONTROL_TEST_KEY_1 */ - case 0x338: /* CONTROL_TEST_KEY_2 */ - case 0x33c: /* CONTROL_TEST_KEY_3 */ - case 0x340: /* CONTROL_TEST_KEY_4 */ - case 0x344: /* CONTROL_TEST_KEY_5 */ - case 0x348: /* CONTROL_TEST_KEY_6 */ - case 0x34c: /* CONTROL_TEST_KEY_7 */ - case 0x350: /* CONTROL_TEST_KEY_8 */ - case 0x354: /* CONTROL_TEST_KEY_9 */ - /* Can only be accessed in secure mode and when C_FieldAccEnable - * bit is set in CONTROL_SEC_CTRL. - * TODO: otherwise an interconnect access error is generated. */ - return 0; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_sysctl_write8(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - int pad_offset, byte_offset; - int prev_value; - - switch (addr) { - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - pad_offset = (addr - 0x30) >> 2; - byte_offset = (addr - 0x30) & (4 - 1); - - prev_value = s->padconf[pad_offset]; - prev_value &= ~(0xff << (byte_offset * 8)); - prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f; - s->padconf[pad_offset] = prev_value; - break; - - default: - OMAP_BAD_REG(addr); - break; - } -} - -static void omap_sysctl_write(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - - switch (addr) { - case 0x000: /* CONTROL_REVISION */ - case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ - case 0x2c0: /* CONTROL_PSA_VALUE */ - case 0x2f8: /* CONTROL_STATUS */ - case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ - case 0x300: /* CONTROL_RPUB_KEY_H_0 */ - case 0x304: /* CONTROL_RPUB_KEY_H_1 */ - case 0x308: /* CONTROL_RPUB_KEY_H_2 */ - case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ - case 0x310: /* CONTROL_RAND_KEY_0 */ - case 0x314: /* CONTROL_RAND_KEY_1 */ - case 0x318: /* CONTROL_RAND_KEY_2 */ - case 0x31c: /* CONTROL_RAND_KEY_3 */ - case 0x320: /* CONTROL_CUST_KEY_0 */ - case 0x324: /* CONTROL_CUST_KEY_1 */ - case 0x330: /* CONTROL_TEST_KEY_0 */ - case 0x334: /* CONTROL_TEST_KEY_1 */ - case 0x338: /* CONTROL_TEST_KEY_2 */ - case 0x33c: /* CONTROL_TEST_KEY_3 */ - case 0x340: /* CONTROL_TEST_KEY_4 */ - case 0x344: /* CONTROL_TEST_KEY_5 */ - case 0x348: /* CONTROL_TEST_KEY_6 */ - case 0x34c: /* CONTROL_TEST_KEY_7 */ - case 0x350: /* CONTROL_TEST_KEY_8 */ - case 0x354: /* CONTROL_TEST_KEY_9 */ - OMAP_RO_REG(addr); - return; - - case 0x010: /* CONTROL_SYSCONFIG */ - s->sysconfig = value & 0x1e; - break; - - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - /* XXX: should check constant bits */ - s->padconf[(addr - 0x30) >> 2] = value & 0x1f1f1f1f; - break; - - case 0x270: /* CONTROL_DEBOBS */ - s->obs = value & 0xff; - break; - - case 0x274: /* CONTROL_DEVCONF */ - s->devconfig = value & 0xffffc7ff; - break; - - case 0x28c: /* CONTROL_EMU_SUPPORT */ - break; - - case 0x290: /* CONTROL_MSUSPENDMUX_0 */ - s->msuspendmux[0] = value & 0x3fffffff; - break; - case 0x294: /* CONTROL_MSUSPENDMUX_1 */ - s->msuspendmux[1] = value & 0x3fffffff; - break; - case 0x298: /* CONTROL_MSUSPENDMUX_2 */ - s->msuspendmux[2] = value & 0x3fffffff; - break; - case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ - s->msuspendmux[3] = value & 0x3fffffff; - break; - case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ - s->msuspendmux[4] = value & 0x3fffffff; - break; - - case 0x2b8: /* CONTROL_PSA_CTRL */ - s->psaconfig = value & 0x1c; - s->psaconfig |= (value & 0x20) ? 2 : 1; - break; - case 0x2bc: /* CONTROL_PSA_CMD */ - break; - - case 0x2b0: /* CONTROL_SEC_CTRL */ - case 0x2b4: /* CONTROL_SEC_TEST */ - case 0x2d0: /* CONTROL_SEC_EMU */ - case 0x2d4: /* CONTROL_SEC_TAP */ - case 0x2d8: /* CONTROL_OCM_RAM_PERM */ - case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ - case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ - case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ - case 0x2f0: /* CONTROL_SEC_STATUS */ - case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_sysctl_ops = { - .old_mmio = { - .read = { - omap_sysctl_read8, - omap_badwidth_read32, /* TODO */ - omap_sysctl_read, - }, - .write = { - omap_sysctl_write8, - omap_badwidth_write32, /* TODO */ - omap_sysctl_write, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_sysctl_reset(struct omap_sysctl_s *s) -{ - /* (power-on reset) */ - s->sysconfig = 0; - s->obs = 0; - s->devconfig = 0x0c000000; - s->msuspendmux[0] = 0x00000000; - s->msuspendmux[1] = 0x00000000; - s->msuspendmux[2] = 0x00000000; - s->msuspendmux[3] = 0x00000000; - s->msuspendmux[4] = 0x00000000; - s->psaconfig = 1; - - s->padconf[0x00] = 0x000f0f0f; - s->padconf[0x01] = 0x00000000; - s->padconf[0x02] = 0x00000000; - s->padconf[0x03] = 0x00000000; - s->padconf[0x04] = 0x00000000; - s->padconf[0x05] = 0x00000000; - s->padconf[0x06] = 0x00000000; - s->padconf[0x07] = 0x00000000; - s->padconf[0x08] = 0x08080800; - s->padconf[0x09] = 0x08080808; - s->padconf[0x0a] = 0x08080808; - s->padconf[0x0b] = 0x08080808; - s->padconf[0x0c] = 0x08080808; - s->padconf[0x0d] = 0x08080800; - s->padconf[0x0e] = 0x08080808; - s->padconf[0x0f] = 0x08080808; - s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */ - s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */ - s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */ - s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */ - s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */ - s->padconf[0x15] = 0x18181818; - s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */ - s->padconf[0x17] = 0x1f001f00; - s->padconf[0x18] = 0x1f1f1f1f; - s->padconf[0x19] = 0x00000000; - s->padconf[0x1a] = 0x1f180000; - s->padconf[0x1b] = 0x00001f1f; - s->padconf[0x1c] = 0x1f001f00; - s->padconf[0x1d] = 0x00000000; - s->padconf[0x1e] = 0x00000000; - s->padconf[0x1f] = 0x08000000; - s->padconf[0x20] = 0x08080808; - s->padconf[0x21] = 0x08080808; - s->padconf[0x22] = 0x0f080808; - s->padconf[0x23] = 0x0f0f0f0f; - s->padconf[0x24] = 0x000f0f0f; - s->padconf[0x25] = 0x1f1f1f0f; - s->padconf[0x26] = 0x080f0f1f; - s->padconf[0x27] = 0x070f1808; - s->padconf[0x28] = 0x0f070707; - s->padconf[0x29] = 0x000f0f1f; - s->padconf[0x2a] = 0x0f0f0f1f; - s->padconf[0x2b] = 0x08000000; - s->padconf[0x2c] = 0x0000001f; - s->padconf[0x2d] = 0x0f0f1f00; - s->padconf[0x2e] = 0x1f1f0f0f; - s->padconf[0x2f] = 0x0f1f1f1f; - s->padconf[0x30] = 0x0f0f0f0f; - s->padconf[0x31] = 0x0f1f0f1f; - s->padconf[0x32] = 0x0f0f0f0f; - s->padconf[0x33] = 0x0f1f0f1f; - s->padconf[0x34] = 0x1f1f0f0f; - s->padconf[0x35] = 0x0f0f1f1f; - s->padconf[0x36] = 0x0f0f1f0f; - s->padconf[0x37] = 0x0f0f0f0f; - s->padconf[0x38] = 0x1f18180f; - s->padconf[0x39] = 0x1f1f1f1f; - s->padconf[0x3a] = 0x00001f1f; - s->padconf[0x3b] = 0x00000000; - s->padconf[0x3c] = 0x00000000; - s->padconf[0x3d] = 0x0f0f0f0f; - s->padconf[0x3e] = 0x18000f0f; - s->padconf[0x3f] = 0x00070000; - s->padconf[0x40] = 0x00000707; - s->padconf[0x41] = 0x0f1f0700; - s->padconf[0x42] = 0x1f1f070f; - s->padconf[0x43] = 0x0008081f; - s->padconf[0x44] = 0x00000800; -} - -static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, - omap_clk iclk, struct omap_mpu_state_s *mpu) -{ - struct omap_sysctl_s *s = (struct omap_sysctl_s *) - g_malloc0(sizeof(struct omap_sysctl_s)); - - s->mpu = mpu; - omap_sysctl_reset(s); - - memory_region_init_io(&s->iomem, &omap_sysctl_ops, s, "omap.sysctl", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - return s; -} - -/* General chip reset */ -static void omap2_mpu_reset(void *opaque) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - - omap_dma_reset(mpu->dma); - omap_prcm_reset(mpu->prcm); - omap_sysctl_reset(mpu->sysc); - omap_gp_timer_reset(mpu->gptimer[0]); - omap_gp_timer_reset(mpu->gptimer[1]); - omap_gp_timer_reset(mpu->gptimer[2]); - omap_gp_timer_reset(mpu->gptimer[3]); - omap_gp_timer_reset(mpu->gptimer[4]); - omap_gp_timer_reset(mpu->gptimer[5]); - omap_gp_timer_reset(mpu->gptimer[6]); - omap_gp_timer_reset(mpu->gptimer[7]); - omap_gp_timer_reset(mpu->gptimer[8]); - omap_gp_timer_reset(mpu->gptimer[9]); - omap_gp_timer_reset(mpu->gptimer[10]); - omap_gp_timer_reset(mpu->gptimer[11]); - omap_synctimer_reset(mpu->synctimer); - omap_sdrc_reset(mpu->sdrc); - omap_gpmc_reset(mpu->gpmc); - omap_dss_reset(mpu->dss); - omap_uart_reset(mpu->uart[0]); - omap_uart_reset(mpu->uart[1]); - omap_uart_reset(mpu->uart[2]); - omap_mmc_reset(mpu->mmc); - omap_mcspi_reset(mpu->mcspi[0]); - omap_mcspi_reset(mpu->mcspi[1]); - cpu_reset(CPU(mpu->cpu)); -} - -static int omap2_validate_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return 1; -} - -static const struct dma_irq_map omap2_dma_irq_map[] = { - { 0, OMAP_INT_24XX_SDMA_IRQ0 }, - { 0, OMAP_INT_24XX_SDMA_IRQ1 }, - { 0, OMAP_INT_24XX_SDMA_IRQ2 }, - { 0, OMAP_INT_24XX_SDMA_IRQ3 }, -}; - -struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, - unsigned long sdram_size, - const char *core) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) - g_malloc0(sizeof(struct omap_mpu_state_s)); - qemu_irq *cpu_irq; - qemu_irq dma_irqs[4]; - DriveInfo *dinfo; - int i; - SysBusDevice *busdev; - struct omap_target_agent_s *ta; - - /* Core */ - s->mpu_model = omap2420; - s->cpu = cpu_arm_init(core ?: "arm1136-r2"); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->sdram_size = sdram_size; - s->sram_size = OMAP242X_SRAM_SIZE; - - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; - - /* Clocks */ - omap_clk_init(s); - - /* Memory-mapped stuff */ - memory_region_init_ram(&s->sdram, "omap2.dram", s->sdram_size); - vmstate_register_ram_global(&s->sdram); - memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram); - memory_region_init_ram(&s->sram, "omap2.sram", s->sram_size); - vmstate_register_ram_global(&s->sram); - memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram); - - s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54); - - /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ - cpu_irq = arm_pic_init_cpu(s->cpu); - s->ih[0] = qdev_create(NULL, "omap2-intc"); - qdev_prop_set_uint8(s->ih[0], "revision", 0x21); - qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk")); - qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk")); - qdev_init_nofail(s->ih[0]); - busdev = SYS_BUS_DEVICE(s->ih[0]); - sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); - sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); - sysbus_mmio_map(busdev, 0, 0x480fe000); - s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_PRCM_MPU_IRQ), - NULL, NULL, s); - - s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1), - omap_findclk(s, "omapctrl_iclk"), s); - - for (i = 0; i < 4; i++) { - dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih], - omap2_dma_irq_map[i].intr); - } - s->dma = omap_dma4_init(0x48056000, dma_irqs, sysmem, s, 256, 32, - omap_findclk(s, "sdma_iclk"), - omap_findclk(s, "sdma_fclk")); - s->port->addr_valid = omap2_validate_addr; - - /* Register SDRAM and SRAM ports for fast DMA transfers. */ - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sdram), - OMAP2_Q2_BASE, s->sdram_size); - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram), - OMAP2_SRAM_BASE, s->sram_size); - - s->uart[0] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 19), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_UART1_IRQ), - omap_findclk(s, "uart1_fclk"), - omap_findclk(s, "uart1_iclk"), - s->drq[OMAP24XX_DMA_UART1_TX], - s->drq[OMAP24XX_DMA_UART1_RX], - "uart1", - serial_hds[0]); - s->uart[1] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 20), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_UART2_IRQ), - omap_findclk(s, "uart2_fclk"), - omap_findclk(s, "uart2_iclk"), - s->drq[OMAP24XX_DMA_UART2_TX], - s->drq[OMAP24XX_DMA_UART2_RX], - "uart2", - serial_hds[0] ? serial_hds[1] : NULL); - s->uart[2] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 21), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_UART3_IRQ), - omap_findclk(s, "uart3_fclk"), - omap_findclk(s, "uart3_iclk"), - s->drq[OMAP24XX_DMA_UART3_TX], - s->drq[OMAP24XX_DMA_UART3_RX], - "uart3", - serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL); - - s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1), - omap_findclk(s, "wu_gpt1_clk"), - omap_findclk(s, "wu_l4_iclk")); - s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2), - omap_findclk(s, "core_gpt2_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3), - omap_findclk(s, "core_gpt3_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4), - omap_findclk(s, "core_gpt4_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5), - omap_findclk(s, "core_gpt5_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6), - omap_findclk(s, "core_gpt6_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7), - omap_findclk(s, "core_gpt7_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8), - omap_findclk(s, "core_gpt8_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9), - omap_findclk(s, "core_gpt9_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10), - omap_findclk(s, "core_gpt10_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11), - omap_findclk(s, "core_gpt11_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12), - omap_findclk(s, "core_gpt12_clk"), - omap_findclk(s, "core_l4_iclk")); - - omap_tap_init(omap_l4ta(s->l4, 2), s); - - s->synctimer = omap_synctimer_init(omap_l4tao(s->l4, 2), s, - omap_findclk(s, "clk32-kHz"), - omap_findclk(s, "core_l4_iclk")); - - s->i2c[0] = qdev_create(NULL, "omap_i2c"); - qdev_prop_set_uint8(s->i2c[0], "revision", 0x34); - qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk")); - qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk")); - qdev_init_nofail(s->i2c[0]); - busdev = SYS_BUS_DEVICE(s->i2c[0]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ)); - sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]); - sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]); - sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0)); - - s->i2c[1] = qdev_create(NULL, "omap_i2c"); - qdev_prop_set_uint8(s->i2c[1], "revision", 0x34); - qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk")); - qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk")); - qdev_init_nofail(s->i2c[1]); - busdev = SYS_BUS_DEVICE(s->i2c[1]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ)); - sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]); - sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]); - sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0)); - - s->gpio = qdev_create(NULL, "omap2-gpio"); - qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); - qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk")); - qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk")); - qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk")); - qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk")); - qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk")); - if (s->mpu_model == omap2430) { - qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk")); - } - qdev_init_nofail(s->gpio); - busdev = SYS_BUS_DEVICE(s->gpio); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1)); - sysbus_connect_irq(busdev, 3, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2)); - sysbus_connect_irq(busdev, 6, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3)); - sysbus_connect_irq(busdev, 9, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4)); - if (s->mpu_model == omap2430) { - sysbus_connect_irq(busdev, 12, - qdev_get_gpio_in(s->ih[0], - OMAP_INT_243X_GPIO_BANK5)); - } - ta = omap_l4ta(s->l4, 3); - sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1)); - sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0)); - sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2)); - sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4)); - sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5)); - - s->sdrc = omap_sdrc_init(sysmem, 0x68009000); - s->gpmc = omap_gpmc_init(s, 0x6800a000, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ), - s->drq[OMAP24XX_DMA_GPMC]); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ), - &s->drq[OMAP24XX_DMA_MMC1_TX], - omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); - - s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ), - &s->drq[OMAP24XX_DMA_SPI1_TX0], - omap_findclk(s, "spi1_fclk"), - omap_findclk(s, "spi1_iclk")); - s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ), - &s->drq[OMAP24XX_DMA_SPI2_TX0], - omap_findclk(s, "spi2_fclk"), - omap_findclk(s, "spi2_iclk")); - - s->dss = omap_dss_init(omap_l4ta(s->l4, 10), sysmem, 0x68000800, - /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */ - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ), - s->drq[OMAP24XX_DMA_DSS], - omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"), - omap_findclk(s, "dss_54m_clk"), - omap_findclk(s, "dss_l3_iclk"), - omap_findclk(s, "dss_l4_iclk")); - - omap_sti_init(omap_l4ta(s->l4, 18), sysmem, 0x54000000, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI), - omap_findclk(s, "emul_ck"), - serial_hds[0] && serial_hds[1] && serial_hds[2] ? - serial_hds[3] : NULL); - - s->eac = omap_eac_init(omap_l4ta(s->l4, 32), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ), - /* Ten consecutive lines */ - &s->drq[OMAP24XX_DMA_EAC_AC_RD], - omap_findclk(s, "func_96m_clk"), - omap_findclk(s, "core_l4_iclk")); - - /* All register mappings (includin those not currenlty implemented): - * SystemControlMod 48000000 - 48000fff - * SystemControlL4 48001000 - 48001fff - * 32kHz Timer Mod 48004000 - 48004fff - * 32kHz Timer L4 48005000 - 48005fff - * PRCM ModA 48008000 - 480087ff - * PRCM ModB 48008800 - 48008fff - * PRCM L4 48009000 - 48009fff - * TEST-BCM Mod 48012000 - 48012fff - * TEST-BCM L4 48013000 - 48013fff - * TEST-TAP Mod 48014000 - 48014fff - * TEST-TAP L4 48015000 - 48015fff - * GPIO1 Mod 48018000 - 48018fff - * GPIO Top 48019000 - 48019fff - * GPIO2 Mod 4801a000 - 4801afff - * GPIO L4 4801b000 - 4801bfff - * GPIO3 Mod 4801c000 - 4801cfff - * GPIO4 Mod 4801e000 - 4801efff - * WDTIMER1 Mod 48020000 - 48010fff - * WDTIMER Top 48021000 - 48011fff - * WDTIMER2 Mod 48022000 - 48012fff - * WDTIMER L4 48023000 - 48013fff - * WDTIMER3 Mod 48024000 - 48014fff - * WDTIMER3 L4 48025000 - 48015fff - * WDTIMER4 Mod 48026000 - 48016fff - * WDTIMER4 L4 48027000 - 48017fff - * GPTIMER1 Mod 48028000 - 48018fff - * GPTIMER1 L4 48029000 - 48019fff - * GPTIMER2 Mod 4802a000 - 4801afff - * GPTIMER2 L4 4802b000 - 4801bfff - * L4-Config AP 48040000 - 480407ff - * L4-Config IP 48040800 - 48040fff - * L4-Config LA 48041000 - 48041fff - * ARM11ETB Mod 48048000 - 48049fff - * ARM11ETB L4 4804a000 - 4804afff - * DISPLAY Top 48050000 - 480503ff - * DISPLAY DISPC 48050400 - 480507ff - * DISPLAY RFBI 48050800 - 48050bff - * DISPLAY VENC 48050c00 - 48050fff - * DISPLAY L4 48051000 - 48051fff - * CAMERA Top 48052000 - 480523ff - * CAMERA core 48052400 - 480527ff - * CAMERA DMA 48052800 - 48052bff - * CAMERA MMU 48052c00 - 48052fff - * CAMERA L4 48053000 - 48053fff - * SDMA Mod 48056000 - 48056fff - * SDMA L4 48057000 - 48057fff - * SSI Top 48058000 - 48058fff - * SSI GDD 48059000 - 48059fff - * SSI Port1 4805a000 - 4805afff - * SSI Port2 4805b000 - 4805bfff - * SSI L4 4805c000 - 4805cfff - * USB Mod 4805e000 - 480fefff - * USB L4 4805f000 - 480fffff - * WIN_TRACER1 Mod 48060000 - 48060fff - * WIN_TRACER1 L4 48061000 - 48061fff - * WIN_TRACER2 Mod 48062000 - 48062fff - * WIN_TRACER2 L4 48063000 - 48063fff - * WIN_TRACER3 Mod 48064000 - 48064fff - * WIN_TRACER3 L4 48065000 - 48065fff - * WIN_TRACER4 Top 48066000 - 480660ff - * WIN_TRACER4 ETT 48066100 - 480661ff - * WIN_TRACER4 WT 48066200 - 480662ff - * WIN_TRACER4 L4 48067000 - 48067fff - * XTI Mod 48068000 - 48068fff - * XTI L4 48069000 - 48069fff - * UART1 Mod 4806a000 - 4806afff - * UART1 L4 4806b000 - 4806bfff - * UART2 Mod 4806c000 - 4806cfff - * UART2 L4 4806d000 - 4806dfff - * UART3 Mod 4806e000 - 4806efff - * UART3 L4 4806f000 - 4806ffff - * I2C1 Mod 48070000 - 48070fff - * I2C1 L4 48071000 - 48071fff - * I2C2 Mod 48072000 - 48072fff - * I2C2 L4 48073000 - 48073fff - * McBSP1 Mod 48074000 - 48074fff - * McBSP1 L4 48075000 - 48075fff - * McBSP2 Mod 48076000 - 48076fff - * McBSP2 L4 48077000 - 48077fff - * GPTIMER3 Mod 48078000 - 48078fff - * GPTIMER3 L4 48079000 - 48079fff - * GPTIMER4 Mod 4807a000 - 4807afff - * GPTIMER4 L4 4807b000 - 4807bfff - * GPTIMER5 Mod 4807c000 - 4807cfff - * GPTIMER5 L4 4807d000 - 4807dfff - * GPTIMER6 Mod 4807e000 - 4807efff - * GPTIMER6 L4 4807f000 - 4807ffff - * GPTIMER7 Mod 48080000 - 48080fff - * GPTIMER7 L4 48081000 - 48081fff - * GPTIMER8 Mod 48082000 - 48082fff - * GPTIMER8 L4 48083000 - 48083fff - * GPTIMER9 Mod 48084000 - 48084fff - * GPTIMER9 L4 48085000 - 48085fff - * GPTIMER10 Mod 48086000 - 48086fff - * GPTIMER10 L4 48087000 - 48087fff - * GPTIMER11 Mod 48088000 - 48088fff - * GPTIMER11 L4 48089000 - 48089fff - * GPTIMER12 Mod 4808a000 - 4808afff - * GPTIMER12 L4 4808b000 - 4808bfff - * EAC Mod 48090000 - 48090fff - * EAC L4 48091000 - 48091fff - * FAC Mod 48092000 - 48092fff - * FAC L4 48093000 - 48093fff - * MAILBOX Mod 48094000 - 48094fff - * MAILBOX L4 48095000 - 48095fff - * SPI1 Mod 48098000 - 48098fff - * SPI1 L4 48099000 - 48099fff - * SPI2 Mod 4809a000 - 4809afff - * SPI2 L4 4809b000 - 4809bfff - * MMC/SDIO Mod 4809c000 - 4809cfff - * MMC/SDIO L4 4809d000 - 4809dfff - * MS_PRO Mod 4809e000 - 4809efff - * MS_PRO L4 4809f000 - 4809ffff - * RNG Mod 480a0000 - 480a0fff - * RNG L4 480a1000 - 480a1fff - * DES3DES Mod 480a2000 - 480a2fff - * DES3DES L4 480a3000 - 480a3fff - * SHA1MD5 Mod 480a4000 - 480a4fff - * SHA1MD5 L4 480a5000 - 480a5fff - * AES Mod 480a6000 - 480a6fff - * AES L4 480a7000 - 480a7fff - * PKA Mod 480a8000 - 480a9fff - * PKA L4 480aa000 - 480aafff - * MG Mod 480b0000 - 480b0fff - * MG L4 480b1000 - 480b1fff - * HDQ/1-wire Mod 480b2000 - 480b2fff - * HDQ/1-wire L4 480b3000 - 480b3fff - * MPU interrupt 480fe000 - 480fefff - * STI channel base 54000000 - 5400ffff - * IVA RAM 5c000000 - 5c01ffff - * IVA ROM 5c020000 - 5c027fff - * IMG_BUF_A 5c040000 - 5c040fff - * IMG_BUF_B 5c042000 - 5c042fff - * VLCDS 5c048000 - 5c0487ff - * IMX_COEF 5c049000 - 5c04afff - * IMX_CMD 5c051000 - 5c051fff - * VLCDQ 5c053000 - 5c0533ff - * VLCDH 5c054000 - 5c054fff - * SEQ_CMD 5c055000 - 5c055fff - * IMX_REG 5c056000 - 5c0560ff - * VLCD_REG 5c056100 - 5c0561ff - * SEQ_REG 5c056200 - 5c0562ff - * IMG_BUF_REG 5c056300 - 5c0563ff - * SEQIRQ_REG 5c056400 - 5c0564ff - * OCP_REG 5c060000 - 5c060fff - * SYSC_REG 5c070000 - 5c070fff - * MMU_REG 5d000000 - 5d000fff - * sDMA R 68000400 - 680005ff - * sDMA W 68000600 - 680007ff - * Display Control 68000800 - 680009ff - * DSP subsystem 68000a00 - 68000bff - * MPU subsystem 68000c00 - 68000dff - * IVA subsystem 68001000 - 680011ff - * USB 68001200 - 680013ff - * Camera 68001400 - 680015ff - * VLYNQ (firewall) 68001800 - 68001bff - * VLYNQ 68001e00 - 68001fff - * SSI 68002000 - 680021ff - * L4 68002400 - 680025ff - * DSP (firewall) 68002800 - 68002bff - * DSP subsystem 68002e00 - 68002fff - * IVA (firewall) 68003000 - 680033ff - * IVA 68003600 - 680037ff - * GFX 68003a00 - 68003bff - * CMDWR emulation 68003c00 - 68003dff - * SMS 68004000 - 680041ff - * OCM 68004200 - 680043ff - * GPMC 68004400 - 680045ff - * RAM (firewall) 68005000 - 680053ff - * RAM (err login) 68005400 - 680057ff - * ROM (firewall) 68005800 - 68005bff - * ROM (err login) 68005c00 - 68005fff - * GPMC (firewall) 68006000 - 680063ff - * GPMC (err login) 68006400 - 680067ff - * SMS (err login) 68006c00 - 68006fff - * SMS registers 68008000 - 68008fff - * SDRC registers 68009000 - 68009fff - * GPMC registers 6800a000 6800afff - */ - - qemu_register_reset(omap2_mpu_reset, s); - - return s; -} diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c deleted file mode 100644 index c0f50c90fe..0000000000 --- a/hw/pxa2xx.c +++ /dev/null @@ -1,2291 +0,0 @@ -/* - * Intel XScale PXA255/270 processor support. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski - * - * This code is licensed under the GPL. - */ - -#include "hw/sysbus.h" -#include "hw/pxa.h" -#include "sysemu/sysemu.h" -#include "hw/serial.h" -#include "hw/i2c.h" -#include "hw/ssi.h" -#include "char/char.h" -#include "sysemu/blockdev.h" - -static struct { - hwaddr io_base; - int irqn; -} pxa255_serial[] = { - { 0x40100000, PXA2XX_PIC_FFUART }, - { 0x40200000, PXA2XX_PIC_BTUART }, - { 0x40700000, PXA2XX_PIC_STUART }, - { 0x41600000, PXA25X_PIC_HWUART }, - { 0, 0 } -}, pxa270_serial[] = { - { 0x40100000, PXA2XX_PIC_FFUART }, - { 0x40200000, PXA2XX_PIC_BTUART }, - { 0x40700000, PXA2XX_PIC_STUART }, - { 0, 0 } -}; - -typedef struct PXASSPDef { - hwaddr io_base; - int irqn; -} PXASSPDef; - -#if 0 -static PXASSPDef pxa250_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0, 0 } -}; -#endif - -static PXASSPDef pxa255_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0x41400000, PXA25X_PIC_NSSP }, - { 0, 0 } -}; - -#if 0 -static PXASSPDef pxa26x_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0x41400000, PXA25X_PIC_NSSP }, - { 0x41500000, PXA26X_PIC_ASSP }, - { 0, 0 } -}; -#endif - -static PXASSPDef pxa27x_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0x41700000, PXA27X_PIC_SSP2 }, - { 0x41900000, PXA2XX_PIC_SSP3 }, - { 0, 0 } -}; - -#define PMCR 0x00 /* Power Manager Control register */ -#define PSSR 0x04 /* Power Manager Sleep Status register */ -#define PSPR 0x08 /* Power Manager Scratch-Pad register */ -#define PWER 0x0c /* Power Manager Wake-Up Enable register */ -#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */ -#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */ -#define PEDR 0x18 /* Power Manager Edge-Detect Status register */ -#define PCFR 0x1c /* Power Manager General Configuration register */ -#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */ -#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */ -#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */ -#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */ -#define RCSR 0x30 /* Reset Controller Status register */ -#define PSLR 0x34 /* Power Manager Sleep Configuration register */ -#define PTSR 0x38 /* Power Manager Standby Configuration register */ -#define PVCR 0x40 /* Power Manager Voltage Change Control register */ -#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */ -#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */ -#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */ -#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ -#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ - -static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case PMCR ... PCMD31: - if (addr & 3) - goto fail; - - return s->pm_regs[addr >> 2]; - default: - fail: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_pm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case PMCR: - /* Clear the write-one-to-clear bits... */ - s->pm_regs[addr >> 2] &= ~(value & 0x2a); - /* ...and set the plain r/w bits */ - s->pm_regs[addr >> 2] &= ~0x15; - s->pm_regs[addr >> 2] |= value & 0x15; - break; - - case PSSR: /* Read-clean registers */ - case RCSR: - case PKSR: - s->pm_regs[addr >> 2] &= ~value; - break; - - default: /* Read-write registers */ - if (!(addr & 3)) { - s->pm_regs[addr >> 2] = value; - break; - } - - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_pm_ops = { - .read = pxa2xx_pm_read, - .write = pxa2xx_pm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_pm = { - .name = "pxa2xx_pm", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40), - VMSTATE_END_OF_LIST() - } -}; - -#define CCCR 0x00 /* Core Clock Configuration register */ -#define CKEN 0x04 /* Clock Enable register */ -#define OSCC 0x08 /* Oscillator Configuration register */ -#define CCSR 0x0c /* Core Clock Status register */ - -static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case CCCR: - case CKEN: - case OSCC: - return s->cm_regs[addr >> 2]; - - case CCSR: - return s->cm_regs[CCCR >> 2] | (3 << 28); - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_cm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case CCCR: - case CKEN: - s->cm_regs[addr >> 2] = value; - break; - - case OSCC: - s->cm_regs[addr >> 2] &= ~0x6c; - s->cm_regs[addr >> 2] |= value & 0x6e; - if ((value >> 1) & 1) /* OON */ - s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */ - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_cm_ops = { - .read = pxa2xx_cm_read, - .write = pxa2xx_cm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_cm = { - .name = "pxa2xx_cm", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4), - VMSTATE_UINT32(clkcfg, PXA2xxState), - VMSTATE_UINT32(pmnc, PXA2xxState), - VMSTATE_END_OF_LIST() - } -}; - -static int pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t *value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - *value = s->clkcfg; - return 0; -} - -static int pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - s->clkcfg = value & 0xf; - if (value & 2) { - printf("%s: CPU frequency change attempt\n", __func__); - } - return 0; -} - -static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - static const char *pwrmode[8] = { - "Normal", "Idle", "Deep-idle", "Standby", - "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep", - }; - - if (value & 8) { - printf("%s: CPU voltage change attempt\n", __func__); - } - switch (value & 7) { - case 0: - /* Do nothing */ - break; - - case 1: - /* Idle */ - if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); - break; - } - /* Fall through. */ - - case 2: - /* Deep-Idle */ - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); - s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ - goto message; - - case 3: - s->cpu->env.uncached_cpsr = - ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; - s->cpu->env.cp15.c1_sys = 0; - s->cpu->env.cp15.c1_coproc = 0; - s->cpu->env.cp15.c2_base0 = 0; - s->cpu->env.cp15.c3 = 0; - s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ - s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ - - /* - * The scratch-pad register is almost universally used - * for storing the return address on suspend. For the - * lack of a resuming bootloader, perform a jump - * directly to that address. - */ - memset(s->cpu->env.regs, 0, 4 * 15); - s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; - -#if 0 - buffer = 0xe59ff000; /* ldr pc, [pc, #0] */ - cpu_physical_memory_write(0, &buffer, 4); - buffer = s->pm_regs[PSPR >> 2]; - cpu_physical_memory_write(8, &buffer, 4); -#endif - - /* Suspend */ - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); - - goto message; - - default: - message: - printf("%s: machine entered %s mode\n", __func__, - pwrmode[value & 7]); - } - - return 0; -} - -static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t *value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - *value = s->pmnc; - return 0; -} - -static int pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - s->pmnc = value; - return 0; -} - -static int pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t *value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - if (s->pmnc & 1) { - *value = qemu_get_clock_ns(vm_clock); - } else { - *value = 0; - } - return 0; -} - -static const ARMCPRegInfo pxa_cp_reginfo[] = { - /* cp14 crm==1: perf registers */ - { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, - .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write }, - { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, - .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore }, - { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* cp14 crm==2: performance count registers */ - { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* cp14 crn==6: CLKCFG */ - { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, - .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write }, - /* cp14 crn==7: PWRMODE */ - { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, - .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, - REGINFO_SENTINEL -}; - -static void pxa2xx_setup_cp14(PXA2xxState *s) -{ - define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s); -} - -#define MDCNFG 0x00 /* SDRAM Configuration register */ -#define MDREFR 0x04 /* SDRAM Refresh Control register */ -#define MSC0 0x08 /* Static Memory Control register 0 */ -#define MSC1 0x0c /* Static Memory Control register 1 */ -#define MSC2 0x10 /* Static Memory Control register 2 */ -#define MECR 0x14 /* Expansion Memory Bus Config register */ -#define SXCNFG 0x1c /* Synchronous Static Memory Config register */ -#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */ -#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */ -#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */ -#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */ -#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */ -#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */ -#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */ -#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */ -#define ARB_CNTL 0x48 /* Arbiter Control register */ -#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */ -#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */ -#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */ -#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */ -#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */ -#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */ -#define SA1110 0x64 /* SA-1110 Memory Compatibility register */ - -static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case MDCNFG ... SA1110: - if ((addr & 3) == 0) - return s->mm_regs[addr >> 2]; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_mm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case MDCNFG ... SA1110: - if ((addr & 3) == 0) { - s->mm_regs[addr >> 2] = value; - break; - } - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_mm_ops = { - .read = pxa2xx_mm_read, - .write = pxa2xx_mm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_mm = { - .name = "pxa2xx_mm", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a), - VMSTATE_END_OF_LIST() - } -}; - -/* Synchronous Serial Ports */ -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - qemu_irq irq; - int enable; - SSIBus *bus; - - uint32_t sscr[2]; - uint32_t sspsp; - uint32_t ssto; - uint32_t ssitr; - uint32_t sssr; - uint8_t sstsa; - uint8_t ssrsa; - uint8_t ssacd; - - uint32_t rx_fifo[16]; - int rx_level; - int rx_start; -} PXA2xxSSPState; - -#define SSCR0 0x00 /* SSP Control register 0 */ -#define SSCR1 0x04 /* SSP Control register 1 */ -#define SSSR 0x08 /* SSP Status register */ -#define SSITR 0x0c /* SSP Interrupt Test register */ -#define SSDR 0x10 /* SSP Data register */ -#define SSTO 0x28 /* SSP Time-Out register */ -#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */ -#define SSTSA 0x30 /* SSP TX Time Slot Active register */ -#define SSRSA 0x34 /* SSP RX Time Slot Active register */ -#define SSTSS 0x38 /* SSP Time Slot Status register */ -#define SSACD 0x3c /* SSP Audio Clock Divider register */ - -/* Bitfields for above registers */ -#define SSCR0_SPI(x) (((x) & 0x30) == 0x00) -#define SSCR0_SSP(x) (((x) & 0x30) == 0x10) -#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20) -#define SSCR0_PSP(x) (((x) & 0x30) == 0x30) -#define SSCR0_SSE (1 << 7) -#define SSCR0_RIM (1 << 22) -#define SSCR0_TIM (1 << 23) -#define SSCR0_MOD (1 << 31) -#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1) -#define SSCR1_RIE (1 << 0) -#define SSCR1_TIE (1 << 1) -#define SSCR1_LBM (1 << 2) -#define SSCR1_MWDS (1 << 5) -#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1) -#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1) -#define SSCR1_EFWR (1 << 14) -#define SSCR1_PINTE (1 << 18) -#define SSCR1_TINTE (1 << 19) -#define SSCR1_RSRE (1 << 20) -#define SSCR1_TSRE (1 << 21) -#define SSCR1_EBCEI (1 << 29) -#define SSITR_INT (7 << 5) -#define SSSR_TNF (1 << 2) -#define SSSR_RNE (1 << 3) -#define SSSR_TFS (1 << 5) -#define SSSR_RFS (1 << 6) -#define SSSR_ROR (1 << 7) -#define SSSR_PINT (1 << 18) -#define SSSR_TINT (1 << 19) -#define SSSR_EOC (1 << 20) -#define SSSR_TUR (1 << 21) -#define SSSR_BCE (1 << 23) -#define SSSR_RW 0x00bc0080 - -static void pxa2xx_ssp_int_update(PXA2xxSSPState *s) -{ - int level = 0; - - level |= s->ssitr & SSITR_INT; - level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI); - level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM); - level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT)); - level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE); - level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE); - level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM); - level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE); - level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE); - qemu_set_irq(s->irq, !!level); -} - -static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s) -{ - s->sssr &= ~(0xf << 12); /* Clear RFL */ - s->sssr &= ~(0xf << 8); /* Clear TFL */ - s->sssr &= ~SSSR_TFS; - s->sssr &= ~SSSR_TNF; - if (s->enable) { - s->sssr |= ((s->rx_level - 1) & 0xf) << 12; - if (s->rx_level >= SSCR1_RFT(s->sscr[1])) - s->sssr |= SSSR_RFS; - else - s->sssr &= ~SSSR_RFS; - if (s->rx_level) - s->sssr |= SSSR_RNE; - else - s->sssr &= ~SSSR_RNE; - /* TX FIFO is never filled, so it is always in underrun - condition if SSP is enabled */ - s->sssr |= SSSR_TFS; - s->sssr |= SSSR_TNF; - } - - pxa2xx_ssp_int_update(s); -} - -static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - uint32_t retval; - - switch (addr) { - case SSCR0: - return s->sscr[0]; - case SSCR1: - return s->sscr[1]; - case SSPSP: - return s->sspsp; - case SSTO: - return s->ssto; - case SSITR: - return s->ssitr; - case SSSR: - return s->sssr | s->ssitr; - case SSDR: - if (!s->enable) - return 0xffffffff; - if (s->rx_level < 1) { - printf("%s: SSP Rx Underrun\n", __FUNCTION__); - return 0xffffffff; - } - s->rx_level --; - retval = s->rx_fifo[s->rx_start ++]; - s->rx_start &= 0xf; - pxa2xx_ssp_fifo_update(s); - return retval; - case SSTSA: - return s->sstsa; - case SSRSA: - return s->ssrsa; - case SSTSS: - return 0; - case SSACD: - return s->ssacd; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_ssp_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - uint32_t value = value64; - - switch (addr) { - case SSCR0: - s->sscr[0] = value & 0xc7ffffff; - s->enable = value & SSCR0_SSE; - if (value & SSCR0_MOD) - printf("%s: Attempt to use network mode\n", __FUNCTION__); - if (s->enable && SSCR0_DSS(value) < 4) - printf("%s: Wrong data size: %i bits\n", __FUNCTION__, - SSCR0_DSS(value)); - if (!(value & SSCR0_SSE)) { - s->sssr = 0; - s->ssitr = 0; - s->rx_level = 0; - } - pxa2xx_ssp_fifo_update(s); - break; - - case SSCR1: - s->sscr[1] = value; - if (value & (SSCR1_LBM | SSCR1_EFWR)) - printf("%s: Attempt to use SSP test mode\n", __FUNCTION__); - pxa2xx_ssp_fifo_update(s); - break; - - case SSPSP: - s->sspsp = value; - break; - - case SSTO: - s->ssto = value; - break; - - case SSITR: - s->ssitr = value & SSITR_INT; - pxa2xx_ssp_int_update(s); - break; - - case SSSR: - s->sssr &= ~(value & SSSR_RW); - pxa2xx_ssp_int_update(s); - break; - - case SSDR: - if (SSCR0_UWIRE(s->sscr[0])) { - if (s->sscr[1] & SSCR1_MWDS) - value &= 0xffff; - else - value &= 0xff; - } else - /* Note how 32bits overflow does no harm here */ - value &= (1 << SSCR0_DSS(s->sscr[0])) - 1; - - /* Data goes from here to the Tx FIFO and is shifted out from - * there directly to the slave, no need to buffer it. - */ - if (s->enable) { - uint32_t readval; - readval = ssi_transfer(s->bus, value); - if (s->rx_level < 0x10) { - s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval; - } else { - s->sssr |= SSSR_ROR; - } - } - pxa2xx_ssp_fifo_update(s); - break; - - case SSTSA: - s->sstsa = value; - break; - - case SSRSA: - s->ssrsa = value; - break; - - case SSACD: - s->ssacd = value; - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_ssp_ops = { - .read = pxa2xx_ssp_read, - .write = pxa2xx_ssp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i; - - qemu_put_be32(f, s->enable); - - qemu_put_be32s(f, &s->sscr[0]); - qemu_put_be32s(f, &s->sscr[1]); - qemu_put_be32s(f, &s->sspsp); - qemu_put_be32s(f, &s->ssto); - qemu_put_be32s(f, &s->ssitr); - qemu_put_be32s(f, &s->sssr); - qemu_put_8s(f, &s->sstsa); - qemu_put_8s(f, &s->ssrsa); - qemu_put_8s(f, &s->ssacd); - - qemu_put_byte(f, s->rx_level); - for (i = 0; i < s->rx_level; i ++) - qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]); -} - -static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i; - - s->enable = qemu_get_be32(f); - - qemu_get_be32s(f, &s->sscr[0]); - qemu_get_be32s(f, &s->sscr[1]); - qemu_get_be32s(f, &s->sspsp); - qemu_get_be32s(f, &s->ssto); - qemu_get_be32s(f, &s->ssitr); - qemu_get_be32s(f, &s->sssr); - qemu_get_8s(f, &s->sstsa); - qemu_get_8s(f, &s->ssrsa); - qemu_get_8s(f, &s->ssacd); - - s->rx_level = qemu_get_byte(f); - s->rx_start = 0; - for (i = 0; i < s->rx_level; i ++) - s->rx_fifo[i] = qemu_get_byte(f); - - return 0; -} - -static int pxa2xx_ssp_init(SysBusDevice *dev) -{ - PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->iomem, &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0, - pxa2xx_ssp_save, pxa2xx_ssp_load, s); - - s->bus = ssi_create_bus(&dev->qdev, "ssi"); - return 0; -} - -/* Real-Time Clock */ -#define RCNR 0x00 /* RTC Counter register */ -#define RTAR 0x04 /* RTC Alarm register */ -#define RTSR 0x08 /* RTC Status register */ -#define RTTR 0x0c /* RTC Timer Trim register */ -#define RDCR 0x10 /* RTC Day Counter register */ -#define RYCR 0x14 /* RTC Year Counter register */ -#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */ -#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */ -#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */ -#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */ -#define SWCR 0x28 /* RTC Stopwatch Counter register */ -#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */ -#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */ -#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */ -#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */ - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t rttr; - uint32_t rtsr; - uint32_t rtar; - uint32_t rdar1; - uint32_t rdar2; - uint32_t ryar1; - uint32_t ryar2; - uint32_t swar1; - uint32_t swar2; - uint32_t piar; - uint32_t last_rcnr; - uint32_t last_rdcr; - uint32_t last_rycr; - uint32_t last_swcr; - uint32_t last_rtcpicr; - int64_t last_hz; - int64_t last_sw; - int64_t last_pi; - QEMUTimer *rtc_hz; - QEMUTimer *rtc_rdal1; - QEMUTimer *rtc_rdal2; - QEMUTimer *rtc_swal1; - QEMUTimer *rtc_swal2; - QEMUTimer *rtc_pi; - qemu_irq rtc_irq; -} PXA2xxRTCState; - -static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s) -{ - qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553)); -} - -static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s) -{ - int64_t rt = qemu_get_clock_ms(rtc_clock); - s->last_rcnr += ((rt - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - s->last_rdcr += ((rt - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - s->last_hz = rt; -} - -static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s) -{ - int64_t rt = qemu_get_clock_ms(rtc_clock); - if (s->rtsr & (1 << 12)) - s->last_swcr += (rt - s->last_sw) / 10; - s->last_sw = rt; -} - -static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s) -{ - int64_t rt = qemu_get_clock_ms(rtc_clock); - if (s->rtsr & (1 << 15)) - s->last_swcr += rt - s->last_pi; - s->last_pi = rt; -} - -static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s, - uint32_t rtsr) -{ - if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0))) - qemu_mod_timer(s->rtc_hz, s->last_hz + - (((s->rtar - s->last_rcnr) * 1000 * - ((s->rttr & 0xffff) + 1)) >> 15)); - else - qemu_del_timer(s->rtc_hz); - - if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4))) - qemu_mod_timer(s->rtc_rdal1, s->last_hz + - (((s->rdar1 - s->last_rdcr) * 1000 * - ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ - else - qemu_del_timer(s->rtc_rdal1); - - if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6))) - qemu_mod_timer(s->rtc_rdal2, s->last_hz + - (((s->rdar2 - s->last_rdcr) * 1000 * - ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ - else - qemu_del_timer(s->rtc_rdal2); - - if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8))) - qemu_mod_timer(s->rtc_swal1, s->last_sw + - (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */ - else - qemu_del_timer(s->rtc_swal1); - - if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10))) - qemu_mod_timer(s->rtc_swal2, s->last_sw + - (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */ - else - qemu_del_timer(s->rtc_swal2); - - if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13))) - qemu_mod_timer(s->rtc_pi, s->last_pi + - (s->piar & 0xffff) - s->last_rtcpicr); - else - qemu_del_timer(s->rtc_pi); -} - -static inline void pxa2xx_rtc_hz_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 0); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_rdal1_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 4); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_rdal2_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 6); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_swal1_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 8); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_swal2_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 10); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_pi_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 13); - pxa2xx_rtc_piupdate(s); - s->last_rtcpicr = 0; - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - - switch (addr) { - case RTTR: - return s->rttr; - case RTSR: - return s->rtsr; - case RTAR: - return s->rtar; - case RDAR1: - return s->rdar1; - case RDAR2: - return s->rdar2; - case RYAR1: - return s->ryar1; - case RYAR2: - return s->ryar2; - case SWAR1: - return s->swar1; - case SWAR2: - return s->swar2; - case PIAR: - return s->piar; - case RCNR: - return s->last_rcnr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - case RDCR: - return s->last_rdcr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - case RYCR: - return s->last_rycr; - case SWCR: - if (s->rtsr & (1 << 12)) - return s->last_swcr + (qemu_get_clock_ms(rtc_clock) - s->last_sw) / 10; - else - return s->last_swcr; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_rtc_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - uint32_t value = value64; - - switch (addr) { - case RTTR: - if (!(s->rttr & (1 << 31))) { - pxa2xx_rtc_hzupdate(s); - s->rttr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - } - break; - - case RTSR: - if ((s->rtsr ^ value) & (1 << 15)) - pxa2xx_rtc_piupdate(s); - - if ((s->rtsr ^ value) & (1 << 12)) - pxa2xx_rtc_swupdate(s); - - if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac)) - pxa2xx_rtc_alarm_update(s, value); - - s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac)); - pxa2xx_rtc_int_update(s); - break; - - case RTAR: - s->rtar = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RDAR1: - s->rdar1 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RDAR2: - s->rdar2 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RYAR1: - s->ryar1 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RYAR2: - s->ryar2 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case SWAR1: - pxa2xx_rtc_swupdate(s); - s->swar1 = value; - s->last_swcr = 0; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case SWAR2: - s->swar2 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case PIAR: - s->piar = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RCNR: - pxa2xx_rtc_hzupdate(s); - s->last_rcnr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RDCR: - pxa2xx_rtc_hzupdate(s); - s->last_rdcr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RYCR: - s->last_rycr = value; - break; - - case SWCR: - pxa2xx_rtc_swupdate(s); - s->last_swcr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RTCPICR: - pxa2xx_rtc_piupdate(s); - s->last_rtcpicr = value & 0xffff; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_rtc_ops = { - .read = pxa2xx_rtc_read, - .write = pxa2xx_rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pxa2xx_rtc_init(SysBusDevice *dev) -{ - PXA2xxRTCState *s = FROM_SYSBUS(PXA2xxRTCState, dev); - struct tm tm; - int wom; - - s->rttr = 0x7fff; - s->rtsr = 0; - - qemu_get_timedate(&tm, 0); - wom = ((tm.tm_mday - 1) / 7) + 1; - - s->last_rcnr = (uint32_t) mktimegm(&tm); - s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) | - (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec; - s->last_rycr = ((tm.tm_year + 1900) << 9) | - ((tm.tm_mon + 1) << 5) | tm.tm_mday; - s->last_swcr = (tm.tm_hour << 19) | - (tm.tm_min << 13) | (tm.tm_sec << 7); - s->last_rtcpicr = 0; - s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rtc_clock); - - s->rtc_hz = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_hz_tick, s); - s->rtc_rdal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s); - s->rtc_rdal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s); - s->rtc_swal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s); - s->rtc_swal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s); - s->rtc_pi = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_pi_tick, s); - - sysbus_init_irq(dev, &s->rtc_irq); - - memory_region_init_io(&s->iomem, &pxa2xx_rtc_ops, s, "pxa2xx-rtc", 0x10000); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void pxa2xx_rtc_pre_save(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - - pxa2xx_rtc_hzupdate(s); - pxa2xx_rtc_piupdate(s); - pxa2xx_rtc_swupdate(s); -} - -static int pxa2xx_rtc_post_load(void *opaque, int version_id) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - - pxa2xx_rtc_alarm_update(s, s->rtsr); - - return 0; -} - -static const VMStateDescription vmstate_pxa2xx_rtc_regs = { - .name = "pxa2xx_rtc", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .pre_save = pxa2xx_rtc_pre_save, - .post_load = pxa2xx_rtc_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(rttr, PXA2xxRTCState), - VMSTATE_UINT32(rtsr, PXA2xxRTCState), - VMSTATE_UINT32(rtar, PXA2xxRTCState), - VMSTATE_UINT32(rdar1, PXA2xxRTCState), - VMSTATE_UINT32(rdar2, PXA2xxRTCState), - VMSTATE_UINT32(ryar1, PXA2xxRTCState), - VMSTATE_UINT32(ryar2, PXA2xxRTCState), - VMSTATE_UINT32(swar1, PXA2xxRTCState), - VMSTATE_UINT32(swar2, PXA2xxRTCState), - VMSTATE_UINT32(piar, PXA2xxRTCState), - VMSTATE_UINT32(last_rcnr, PXA2xxRTCState), - VMSTATE_UINT32(last_rdcr, PXA2xxRTCState), - VMSTATE_UINT32(last_rycr, PXA2xxRTCState), - VMSTATE_UINT32(last_swcr, PXA2xxRTCState), - VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState), - VMSTATE_INT64(last_hz, PXA2xxRTCState), - VMSTATE_INT64(last_sw, PXA2xxRTCState), - VMSTATE_INT64(last_pi, PXA2xxRTCState), - VMSTATE_END_OF_LIST(), - }, -}; - -static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_rtc_init; - dc->desc = "PXA2xx RTC Controller"; - dc->vmsd = &vmstate_pxa2xx_rtc_regs; -} - -static const TypeInfo pxa2xx_rtc_sysbus_info = { - .name = "pxa2xx_rtc", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxRTCState), - .class_init = pxa2xx_rtc_sysbus_class_init, -}; - -/* I2C Interface */ -typedef struct { - I2CSlave i2c; - PXA2xxI2CState *host; -} PXA2xxI2CSlaveState; - -struct PXA2xxI2CState { - SysBusDevice busdev; - MemoryRegion iomem; - PXA2xxI2CSlaveState *slave; - i2c_bus *bus; - qemu_irq irq; - uint32_t offset; - uint32_t region_size; - - uint16_t control; - uint16_t status; - uint8_t ibmr; - uint8_t data; -}; - -#define IBMR 0x80 /* I2C Bus Monitor register */ -#define IDBR 0x88 /* I2C Data Buffer register */ -#define ICR 0x90 /* I2C Control register */ -#define ISR 0x98 /* I2C Status register */ -#define ISAR 0xa0 /* I2C Slave Address register */ - -static void pxa2xx_i2c_update(PXA2xxI2CState *s) -{ - uint16_t level = 0; - level |= s->status & s->control & (1 << 10); /* BED */ - level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */ - level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */ - level |= s->status & (1 << 9); /* SAD */ - qemu_set_irq(s->irq, !!level); -} - -/* These are only stubs now. */ -static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) -{ - PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); - PXA2xxI2CState *s = slave->host; - - switch (event) { - case I2C_START_SEND: - s->status |= (1 << 9); /* set SAD */ - s->status &= ~(1 << 0); /* clear RWM */ - break; - case I2C_START_RECV: - s->status |= (1 << 9); /* set SAD */ - s->status |= 1 << 0; /* set RWM */ - break; - case I2C_FINISH: - s->status |= (1 << 4); /* set SSD */ - break; - case I2C_NACK: - s->status |= 1 << 1; /* set ACKNAK */ - break; - } - pxa2xx_i2c_update(s); -} - -static int pxa2xx_i2c_rx(I2CSlave *i2c) -{ - PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); - PXA2xxI2CState *s = slave->host; - if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) - return 0; - - if (s->status & (1 << 0)) { /* RWM */ - s->status |= 1 << 6; /* set ITE */ - } - pxa2xx_i2c_update(s); - - return s->data; -} - -static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data) -{ - PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); - PXA2xxI2CState *s = slave->host; - if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) - return 1; - - if (!(s->status & (1 << 0))) { /* RWM */ - s->status |= 1 << 7; /* set IRF */ - s->data = data; - } - pxa2xx_i2c_update(s); - - return 1; -} - -static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; - - addr -= s->offset; - switch (addr) { - case ICR: - return s->control; - case ISR: - return s->status | (i2c_bus_busy(s->bus) << 2); - case ISAR: - return s->slave->i2c.address; - case IDBR: - return s->data; - case IBMR: - if (s->status & (1 << 2)) - s->ibmr ^= 3; /* Fake SCL and SDA pin changes */ - else - s->ibmr = 0; - return s->ibmr; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_i2c_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; - uint32_t value = value64; - int ack; - - addr -= s->offset; - switch (addr) { - case ICR: - s->control = value & 0xfff7; - if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */ - /* TODO: slave mode */ - if (value & (1 << 0)) { /* START condition */ - if (s->data & 1) - s->status |= 1 << 0; /* set RWM */ - else - s->status &= ~(1 << 0); /* clear RWM */ - ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1); - } else { - if (s->status & (1 << 0)) { /* RWM */ - s->data = i2c_recv(s->bus); - if (value & (1 << 2)) /* ACKNAK */ - i2c_nack(s->bus); - ack = 1; - } else - ack = !i2c_send(s->bus, s->data); - } - - if (value & (1 << 1)) /* STOP condition */ - i2c_end_transfer(s->bus); - - if (ack) { - if (value & (1 << 0)) /* START condition */ - s->status |= 1 << 6; /* set ITE */ - else - if (s->status & (1 << 0)) /* RWM */ - s->status |= 1 << 7; /* set IRF */ - else - s->status |= 1 << 6; /* set ITE */ - s->status &= ~(1 << 1); /* clear ACKNAK */ - } else { - s->status |= 1 << 6; /* set ITE */ - s->status |= 1 << 10; /* set BED */ - s->status |= 1 << 1; /* set ACKNAK */ - } - } - if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */ - if (value & (1 << 4)) /* MA */ - i2c_end_transfer(s->bus); - pxa2xx_i2c_update(s); - break; - - case ISR: - s->status &= ~(value & 0x07f0); - pxa2xx_i2c_update(s); - break; - - case ISAR: - i2c_set_slave_address(&s->slave->i2c, value & 0x7f); - break; - - case IDBR: - s->data = value & 0xff; - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_i2c_ops = { - .read = pxa2xx_i2c_read, - .write = pxa2xx_i2c_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_i2c_slave = { - .name = "pxa2xx_i2c_slave", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_I2C_SLAVE(i2c, PXA2xxI2CSlaveState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_pxa2xx_i2c = { - .name = "pxa2xx_i2c", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_UINT16(control, PXA2xxI2CState), - VMSTATE_UINT16(status, PXA2xxI2CState), - VMSTATE_UINT8(ibmr, PXA2xxI2CState), - VMSTATE_UINT8(data, PXA2xxI2CState), - VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState, - vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState *), - VMSTATE_END_OF_LIST() - } -}; - -static int pxa2xx_i2c_slave_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - -static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) -{ - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = pxa2xx_i2c_slave_init; - k->event = pxa2xx_i2c_event; - k->recv = pxa2xx_i2c_rx; - k->send = pxa2xx_i2c_tx; -} - -static const TypeInfo pxa2xx_i2c_slave_info = { - .name = "pxa2xx-i2c-slave", - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(PXA2xxI2CSlaveState), - .class_init = pxa2xx_i2c_slave_class_init, -}; - -PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, - qemu_irq irq, uint32_t region_size) -{ - DeviceState *dev; - SysBusDevice *i2c_dev; - PXA2xxI2CState *s; - - i2c_dev = SYS_BUS_DEVICE(qdev_create(NULL, "pxa2xx_i2c")); - qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1); - qdev_prop_set_uint32(&i2c_dev->qdev, "offset", base & region_size); - - qdev_init_nofail(&i2c_dev->qdev); - - sysbus_mmio_map(i2c_dev, 0, base & ~region_size); - sysbus_connect_irq(i2c_dev, 0, irq); - - s = FROM_SYSBUS(PXA2xxI2CState, i2c_dev); - /* FIXME: Should the slave device really be on a separate bus? */ - dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0); - s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE(dev)); - s->slave->host = s; - - return s; -} - -static int pxa2xx_i2c_initfn(SysBusDevice *dev) -{ - PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev); - - s->bus = i2c_init_bus(&dev->qdev, "i2c"); - - memory_region_init_io(&s->iomem, &pxa2xx_i2c_ops, s, - "pxa2xx-i2x", s->region_size); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - - return 0; -} - -i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s) -{ - return s->bus; -} - -static Property pxa2xx_i2c_properties[] = { - DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000), - DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_i2c_initfn; - dc->desc = "PXA2xx I2C Bus Controller"; - dc->vmsd = &vmstate_pxa2xx_i2c; - dc->props = pxa2xx_i2c_properties; -} - -static const TypeInfo pxa2xx_i2c_info = { - .name = "pxa2xx_i2c", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxI2CState), - .class_init = pxa2xx_i2c_class_init, -}; - -/* PXA Inter-IC Sound Controller */ -static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s) -{ - i2s->rx_len = 0; - i2s->tx_len = 0; - i2s->fifo_len = 0; - i2s->clk = 0x1a; - i2s->control[0] = 0x00; - i2s->control[1] = 0x00; - i2s->status = 0x00; - i2s->mask = 0x00; -} - -#define SACR_TFTH(val) ((val >> 8) & 0xf) -#define SACR_RFTH(val) ((val >> 12) & 0xf) -#define SACR_DREC(val) (val & (1 << 3)) -#define SACR_DPRL(val) (val & (1 << 4)) - -static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s) -{ - int rfs, tfs; - rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len && - !SACR_DREC(i2s->control[1]); - tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) && - i2s->enable && !SACR_DPRL(i2s->control[1]); - - qemu_set_irq(i2s->rx_dma, rfs); - qemu_set_irq(i2s->tx_dma, tfs); - - i2s->status &= 0xe0; - if (i2s->fifo_len < 16 || !i2s->enable) - i2s->status |= 1 << 0; /* TNF */ - if (i2s->rx_len) - i2s->status |= 1 << 1; /* RNE */ - if (i2s->enable) - i2s->status |= 1 << 2; /* BSY */ - if (tfs) - i2s->status |= 1 << 3; /* TFS */ - if (rfs) - i2s->status |= 1 << 4; /* RFS */ - if (!(i2s->tx_len && i2s->enable)) - i2s->status |= i2s->fifo_len << 8; /* TFL */ - i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */ - - qemu_set_irq(i2s->irq, i2s->status & i2s->mask); -} - -#define SACR0 0x00 /* Serial Audio Global Control register */ -#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */ -#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */ -#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */ -#define SAICR 0x18 /* Serial Audio Interrupt Clear register */ -#define SADIV 0x60 /* Serial Audio Clock Divider register */ -#define SADR 0x80 /* Serial Audio Data register */ - -static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - - switch (addr) { - case SACR0: - return s->control[0]; - case SACR1: - return s->control[1]; - case SASR0: - return s->status; - case SAIMR: - return s->mask; - case SAICR: - return 0; - case SADIV: - return s->clk; - case SADR: - if (s->rx_len > 0) { - s->rx_len --; - pxa2xx_i2s_update(s); - return s->codec_in(s->opaque); - } - return 0; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_i2s_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - uint32_t *sample; - - switch (addr) { - case SACR0: - if (value & (1 << 3)) /* RST */ - pxa2xx_i2s_reset(s); - s->control[0] = value & 0xff3d; - if (!s->enable && (value & 1) && s->tx_len) { /* ENB */ - for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++) - s->codec_out(s->opaque, *sample); - s->status &= ~(1 << 7); /* I2SOFF */ - } - if (value & (1 << 4)) /* EFWR */ - printf("%s: Attempt to use special function\n", __FUNCTION__); - s->enable = (value & 9) == 1; /* ENB && !RST*/ - pxa2xx_i2s_update(s); - break; - case SACR1: - s->control[1] = value & 0x0039; - if (value & (1 << 5)) /* ENLBF */ - printf("%s: Attempt to use loopback function\n", __FUNCTION__); - if (value & (1 << 4)) /* DPRL */ - s->fifo_len = 0; - pxa2xx_i2s_update(s); - break; - case SAIMR: - s->mask = value & 0x0078; - pxa2xx_i2s_update(s); - break; - case SAICR: - s->status &= ~(value & (3 << 5)); - pxa2xx_i2s_update(s); - break; - case SADIV: - s->clk = value & 0x007f; - break; - case SADR: - if (s->tx_len && s->enable) { - s->tx_len --; - pxa2xx_i2s_update(s); - s->codec_out(s->opaque, value); - } else if (s->fifo_len < 16) { - s->fifo[s->fifo_len ++] = value; - pxa2xx_i2s_update(s); - } - break; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_i2s_ops = { - .read = pxa2xx_i2s_read, - .write = pxa2xx_i2s_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_i2s = { - .name = "pxa2xx_i2s", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2), - VMSTATE_UINT32(status, PXA2xxI2SState), - VMSTATE_UINT32(mask, PXA2xxI2SState), - VMSTATE_UINT32(clk, PXA2xxI2SState), - VMSTATE_INT32(enable, PXA2xxI2SState), - VMSTATE_INT32(rx_len, PXA2xxI2SState), - VMSTATE_INT32(tx_len, PXA2xxI2SState), - VMSTATE_INT32(fifo_len, PXA2xxI2SState), - VMSTATE_END_OF_LIST() - } -}; - -static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - uint32_t *sample; - - /* Signal FIFO errors */ - if (s->enable && s->tx_len) - s->status |= 1 << 5; /* TUR */ - if (s->enable && s->rx_len) - s->status |= 1 << 6; /* ROR */ - - /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to - * handle the cases where it makes a difference. */ - s->tx_len = tx - s->fifo_len; - s->rx_len = rx; - /* Note that is s->codec_out wasn't set, we wouldn't get called. */ - if (s->enable) - for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++) - s->codec_out(s->opaque, *sample); - pxa2xx_i2s_update(s); -} - -static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) - g_malloc0(sizeof(PXA2xxI2SState)); - - s->irq = irq; - s->rx_dma = rx_dma; - s->tx_dma = tx_dma; - s->data_req = pxa2xx_i2s_data_req; - - pxa2xx_i2s_reset(s); - - memory_region_init_io(&s->iomem, &pxa2xx_i2s_ops, s, - "pxa2xx-i2s", 0x100000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s); - - return s; -} - -/* PXA Fast Infra-red Communications Port */ -struct PXA2xxFIrState { - MemoryRegion iomem; - qemu_irq irq; - qemu_irq rx_dma; - qemu_irq tx_dma; - int enable; - CharDriverState *chr; - - uint8_t control[3]; - uint8_t status[2]; - - int rx_len; - int rx_start; - uint8_t rx_fifo[64]; -}; - -static void pxa2xx_fir_reset(PXA2xxFIrState *s) -{ - s->control[0] = 0x00; - s->control[1] = 0x00; - s->control[2] = 0x00; - s->status[0] = 0x00; - s->status[1] = 0x00; - s->enable = 0; -} - -static inline void pxa2xx_fir_update(PXA2xxFIrState *s) -{ - static const int tresh[4] = { 8, 16, 32, 0 }; - int intr = 0; - if ((s->control[0] & (1 << 4)) && /* RXE */ - s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */ - s->status[0] |= 1 << 4; /* RFS */ - else - s->status[0] &= ~(1 << 4); /* RFS */ - if (s->control[0] & (1 << 3)) /* TXE */ - s->status[0] |= 1 << 3; /* TFS */ - else - s->status[0] &= ~(1 << 3); /* TFS */ - if (s->rx_len) - s->status[1] |= 1 << 2; /* RNE */ - else - s->status[1] &= ~(1 << 2); /* RNE */ - if (s->control[0] & (1 << 4)) /* RXE */ - s->status[1] |= 1 << 0; /* RSY */ - else - s->status[1] &= ~(1 << 0); /* RSY */ - - intr |= (s->control[0] & (1 << 5)) && /* RIE */ - (s->status[0] & (1 << 4)); /* RFS */ - intr |= (s->control[0] & (1 << 6)) && /* TIE */ - (s->status[0] & (1 << 3)); /* TFS */ - intr |= (s->control[2] & (1 << 4)) && /* TRAIL */ - (s->status[0] & (1 << 6)); /* EOC */ - intr |= (s->control[0] & (1 << 2)) && /* TUS */ - (s->status[0] & (1 << 1)); /* TUR */ - intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */ - - qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1); - qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1); - - qemu_set_irq(s->irq, intr && s->enable); -} - -#define ICCR0 0x00 /* FICP Control register 0 */ -#define ICCR1 0x04 /* FICP Control register 1 */ -#define ICCR2 0x08 /* FICP Control register 2 */ -#define ICDR 0x0c /* FICP Data register */ -#define ICSR0 0x14 /* FICP Status register 0 */ -#define ICSR1 0x18 /* FICP Status register 1 */ -#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */ - -static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - uint8_t ret; - - switch (addr) { - case ICCR0: - return s->control[0]; - case ICCR1: - return s->control[1]; - case ICCR2: - return s->control[2]; - case ICDR: - s->status[0] &= ~0x01; - s->status[1] &= ~0x72; - if (s->rx_len) { - s->rx_len --; - ret = s->rx_fifo[s->rx_start ++]; - s->rx_start &= 63; - pxa2xx_fir_update(s); - return ret; - } - printf("%s: Rx FIFO underrun.\n", __FUNCTION__); - break; - case ICSR0: - return s->status[0]; - case ICSR1: - return s->status[1] | (1 << 3); /* TNF */ - case ICFOR: - return s->rx_len; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_fir_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - uint32_t value = value64; - uint8_t ch; - - switch (addr) { - case ICCR0: - s->control[0] = value; - if (!(value & (1 << 4))) /* RXE */ - s->rx_len = s->rx_start = 0; - if (!(value & (1 << 3))) { /* TXE */ - /* Nop */ - } - s->enable = value & 1; /* ITR */ - if (!s->enable) - s->status[0] = 0; - pxa2xx_fir_update(s); - break; - case ICCR1: - s->control[1] = value; - break; - case ICCR2: - s->control[2] = value & 0x3f; - pxa2xx_fir_update(s); - break; - case ICDR: - if (s->control[2] & (1 << 2)) /* TXP */ - ch = value; - else - ch = ~value; - if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */ - qemu_chr_fe_write(s->chr, &ch, 1); - break; - case ICSR0: - s->status[0] &= ~(value & 0x66); - pxa2xx_fir_update(s); - break; - case ICFOR: - break; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_fir_ops = { - .read = pxa2xx_fir_read, - .write = pxa2xx_fir_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pxa2xx_fir_is_empty(void *opaque) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - return (s->rx_len < 64); -} - -static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - if (!(s->control[0] & (1 << 4))) /* RXE */ - return; - - while (size --) { - s->status[1] |= 1 << 4; /* EOF */ - if (s->rx_len >= 64) { - s->status[1] |= 1 << 6; /* ROR */ - break; - } - - if (s->control[2] & (1 << 3)) /* RXP */ - s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++); - else - s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++); - } - - pxa2xx_fir_update(s); -} - -static void pxa2xx_fir_event(void *opaque, int event) -{ -} - -static void pxa2xx_fir_save(QEMUFile *f, void *opaque) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - int i; - - qemu_put_be32(f, s->enable); - - qemu_put_8s(f, &s->control[0]); - qemu_put_8s(f, &s->control[1]); - qemu_put_8s(f, &s->control[2]); - qemu_put_8s(f, &s->status[0]); - qemu_put_8s(f, &s->status[1]); - - qemu_put_byte(f, s->rx_len); - for (i = 0; i < s->rx_len; i ++) - qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]); -} - -static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - int i; - - s->enable = qemu_get_be32(f); - - qemu_get_8s(f, &s->control[0]); - qemu_get_8s(f, &s->control[1]); - qemu_get_8s(f, &s->control[2]); - qemu_get_8s(f, &s->status[0]); - qemu_get_8s(f, &s->status[1]); - - s->rx_len = qemu_get_byte(f); - s->rx_start = 0; - for (i = 0; i < s->rx_len; i ++) - s->rx_fifo[i] = qemu_get_byte(f); - - return 0; -} - -static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, - CharDriverState *chr) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) - g_malloc0(sizeof(PXA2xxFIrState)); - - s->irq = irq; - s->rx_dma = rx_dma; - s->tx_dma = tx_dma; - s->chr = chr; - - pxa2xx_fir_reset(s); - - memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - if (chr) - qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, - pxa2xx_fir_rx, pxa2xx_fir_event, s); - - register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, - pxa2xx_fir_load, s); - - return s; -} - -static void pxa2xx_reset(void *opaque, int line, int level) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */ - cpu_reset(CPU(s->cpu)); - /* TODO: reset peripherals */ - } -} - -/* Initialise a PXA270 integrated chip (ARM based core). */ -PXA2xxState *pxa270_init(MemoryRegion *address_space, - unsigned int sdram_size, const char *revision) -{ - PXA2xxState *s; - int i; - DriveInfo *dinfo; - s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); - - if (revision && strncmp(revision, "pxa27", 5)) { - fprintf(stderr, "Machine requires a PXA27x processor.\n"); - exit(1); - } - if (!revision) - revision = "pxa270"; - - s->cpu = cpu_arm_init(revision); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; - - /* SDRAM & Internal Memory Storage */ - memory_region_init_ram(&s->sdram, "pxa270.sdram", sdram_size); - vmstate_register_ram_global(&s->sdram); - memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); - memory_region_init_ram(&s->internal, "pxa270.internal", 0x40000); - vmstate_register_ram_global(&s->internal); - memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, - &s->internal); - - s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); - - s->dma = pxa27x_dma_init(0x40000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); - - sysbus_create_varargs("pxa27x-timer", 0x40a00000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), - qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11), - NULL); - - s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI)); - - for (i = 0; pxa270_serial[i].io_base; i++) { - if (serial_hds[i]) { - serial_mm_init(address_space, pxa270_serial[i].io_base, 2, - qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn), - 14857000 / 16, serial_hds[i], - DEVICE_NATIVE_ENDIAN); - } else { - break; - } - } - if (serial_hds[i]) - s->fir = pxa2xx_fir_init(address_space, 0x40800000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), - serial_hds[i]); - - s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD)); - - s->cm_base = 0x41300000; - s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ - s->clkcfg = 0x00000009; /* Turbo mode active */ - memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); - memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); - - pxa2xx_setup_cp14(s); - - s->mm_base = 0x48000000; - s->mm_regs[MDMRS >> 2] = 0x00020002; - s->mm_regs[MDREFR >> 2] = 0x03ca4000; - s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); - memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); - - s->pm_base = 0x40f00000; - memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); - memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); - - for (i = 0; pxa27x_ssp[i].io_base; i ++); - s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); - for (i = 0; pxa27x_ssp[i].io_base; i ++) { - DeviceState *dev; - dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base, - qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn)); - s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); - } - - if (usb_enabled(false)) { - sysbus_create_simple("sysbus-ohci", 0x4c000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); - } - - s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); - s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); - - sysbus_create_simple("pxa2xx_rtc", 0x40900000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); - - s->i2c[0] = pxa2xx_i2c_init(0x40301600, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff); - s->i2c[1] = pxa2xx_i2c_init(0x40f00100, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); - - s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); - - s->kp = pxa27x_keypad_init(address_space, 0x41500000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD)); - - /* GPIO1 resets the processor */ - /* The handler can be overridden by board-specific code */ - qdev_connect_gpio_out(s->gpio, 1, s->reset); - return s; -} - -/* Initialise a PXA255 integrated chip (ARM based core). */ -PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) -{ - PXA2xxState *s; - int i; - DriveInfo *dinfo; - - s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); - - s->cpu = cpu_arm_init("pxa255"); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; - - /* SDRAM & Internal Memory Storage */ - memory_region_init_ram(&s->sdram, "pxa255.sdram", sdram_size); - vmstate_register_ram_global(&s->sdram); - memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); - memory_region_init_ram(&s->internal, "pxa255.internal", - PXA2XX_INTERNAL_SIZE); - vmstate_register_ram_global(&s->internal); - memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, - &s->internal); - - s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); - - s->dma = pxa255_dma_init(0x40000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); - - sysbus_create_varargs("pxa25x-timer", 0x40a00000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), - NULL); - - s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI)); - - for (i = 0; pxa255_serial[i].io_base; i++) { - if (serial_hds[i]) { - serial_mm_init(address_space, pxa255_serial[i].io_base, 2, - qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn), - 14745600 / 16, serial_hds[i], - DEVICE_NATIVE_ENDIAN); - } else { - break; - } - } - if (serial_hds[i]) - s->fir = pxa2xx_fir_init(address_space, 0x40800000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), - serial_hds[i]); - - s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD)); - - s->cm_base = 0x41300000; - s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ - s->clkcfg = 0x00000009; /* Turbo mode active */ - memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); - memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); - - pxa2xx_setup_cp14(s); - - s->mm_base = 0x48000000; - s->mm_regs[MDMRS >> 2] = 0x00020002; - s->mm_regs[MDREFR >> 2] = 0x03ca4000; - s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); - memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); - - s->pm_base = 0x40f00000; - memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); - memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); - - for (i = 0; pxa255_ssp[i].io_base; i ++); - s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); - for (i = 0; pxa255_ssp[i].io_base; i ++) { - DeviceState *dev; - dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base, - qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn)); - s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); - } - - if (usb_enabled(false)) { - sysbus_create_simple("sysbus-ohci", 0x4c000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); - } - - s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); - s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); - - sysbus_create_simple("pxa2xx_rtc", 0x40900000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); - - s->i2c[0] = pxa2xx_i2c_init(0x40301600, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff); - s->i2c[1] = pxa2xx_i2c_init(0x40f00100, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); - - s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); - - /* GPIO1 resets the processor */ - /* The handler can be overridden by board-specific code */ - qdev_connect_gpio_out(s->gpio, 1, s->reset); - return s; -} - -static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = pxa2xx_ssp_init; -} - -static const TypeInfo pxa2xx_ssp_info = { - .name = "pxa2xx-ssp", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxSSPState), - .class_init = pxa2xx_ssp_class_init, -}; - -static void pxa2xx_register_types(void) -{ - type_register_static(&pxa2xx_i2c_slave_info); - type_register_static(&pxa2xx_ssp_info); - type_register_static(&pxa2xx_i2c_info); - type_register_static(&pxa2xx_rtc_sysbus_info); -} - -type_init(pxa2xx_register_types) diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c deleted file mode 100644 index eef8411e86..0000000000 --- a/hw/pxa2xx_gpio.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Intel XScale PXA255/270 GPIO controller emulation. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski - * - * This code is licensed under the GPL. - */ - -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "hw/pxa.h" - -#define PXA2XX_GPIO_BANKS 4 - -typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo; -struct PXA2xxGPIOInfo { - SysBusDevice busdev; - MemoryRegion iomem; - qemu_irq irq0, irq1, irqX; - int lines; - int ncpu; - ARMCPU *cpu; - - /* XXX: GNU C vectors are more suitable */ - uint32_t ilevel[PXA2XX_GPIO_BANKS]; - uint32_t olevel[PXA2XX_GPIO_BANKS]; - uint32_t dir[PXA2XX_GPIO_BANKS]; - uint32_t rising[PXA2XX_GPIO_BANKS]; - uint32_t falling[PXA2XX_GPIO_BANKS]; - uint32_t status[PXA2XX_GPIO_BANKS]; - uint32_t gpsr[PXA2XX_GPIO_BANKS]; - uint32_t gafr[PXA2XX_GPIO_BANKS * 2]; - - uint32_t prev_level[PXA2XX_GPIO_BANKS]; - qemu_irq handler[PXA2XX_GPIO_BANKS * 32]; - qemu_irq read_notify; -}; - -static struct { - enum { - GPIO_NONE, - GPLR, - GPSR, - GPCR, - GPDR, - GRER, - GFER, - GEDR, - GAFR_L, - GAFR_U, - } reg; - int bank; -} pxa2xx_gpio_regs[0x200] = { - [0 ... 0x1ff] = { GPIO_NONE, 0 }, -#define PXA2XX_REG(reg, a0, a1, a2, a3) \ - [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, - - PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100) - PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118) - PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124) - PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c) - PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130) - PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c) - PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148) - PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c) - PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070) -}; - -static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s) -{ - if (s->status[0] & (1 << 0)) - qemu_irq_raise(s->irq0); - else - qemu_irq_lower(s->irq0); - - if (s->status[0] & (1 << 1)) - qemu_irq_raise(s->irq1); - else - qemu_irq_lower(s->irq1); - - if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3]) - qemu_irq_raise(s->irqX); - else - qemu_irq_lower(s->irqX); -} - -/* Bitmap of pins used as standby and sleep wake-up sources. */ -static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { - 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f, -}; - -static void pxa2xx_gpio_set(void *opaque, int line, int level) -{ - PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; - int bank; - uint32_t mask; - - if (line >= s->lines) { - printf("%s: No GPIO pin %i\n", __FUNCTION__, line); - return; - } - - bank = line >> 5; - mask = 1 << (line & 31); - - if (level) { - s->status[bank] |= s->rising[bank] & mask & - ~s->ilevel[bank] & ~s->dir[bank]; - s->ilevel[bank] |= mask; - } else { - s->status[bank] |= s->falling[bank] & mask & - s->ilevel[bank] & ~s->dir[bank]; - s->ilevel[bank] &= ~mask; - } - - if (s->status[bank] & mask) - pxa2xx_gpio_irq_update(s); - - /* Wake-up GPIOs */ - if (s->cpu->env.halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); - } -} - -static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) { - uint32_t level, diff; - int i, bit, line; - for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) { - level = s->olevel[i] & s->dir[i]; - - for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) { - bit = ffs(diff) - 1; - line = bit + 32 * i; - qemu_set_irq(s->handler[line], (level >> bit) & 1); - } - - s->prev_level[i] = level; - } -} - -static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset, - unsigned size) -{ - PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; - uint32_t ret; - int bank; - if (offset >= 0x200) - return 0; - - bank = pxa2xx_gpio_regs[offset].bank; - switch (pxa2xx_gpio_regs[offset].reg) { - case GPDR: /* GPIO Pin-Direction registers */ - return s->dir[bank]; - - case GPSR: /* GPIO Pin-Output Set registers */ - printf("%s: Read from a write-only register " REG_FMT "\n", - __FUNCTION__, offset); - return s->gpsr[bank]; /* Return last written value. */ - - case GPCR: /* GPIO Pin-Output Clear registers */ - printf("%s: Read from a write-only register " REG_FMT "\n", - __FUNCTION__, offset); - return 31337; /* Specified as unpredictable in the docs. */ - - case GRER: /* GPIO Rising-Edge Detect Enable registers */ - return s->rising[bank]; - - case GFER: /* GPIO Falling-Edge Detect Enable registers */ - return s->falling[bank]; - - case GAFR_L: /* GPIO Alternate Function registers */ - return s->gafr[bank * 2]; - - case GAFR_U: /* GPIO Alternate Function registers */ - return s->gafr[bank * 2 + 1]; - - case GPLR: /* GPIO Pin-Level registers */ - ret = (s->olevel[bank] & s->dir[bank]) | - (s->ilevel[bank] & ~s->dir[bank]); - qemu_irq_raise(s->read_notify); - return ret; - - case GEDR: /* GPIO Edge Detect Status registers */ - return s->status[bank]; - - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } - - return 0; -} - -static void pxa2xx_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; - int bank; - if (offset >= 0x200) - return; - - bank = pxa2xx_gpio_regs[offset].bank; - switch (pxa2xx_gpio_regs[offset].reg) { - case GPDR: /* GPIO Pin-Direction registers */ - s->dir[bank] = value; - pxa2xx_gpio_handler_update(s); - break; - - case GPSR: /* GPIO Pin-Output Set registers */ - s->olevel[bank] |= value; - pxa2xx_gpio_handler_update(s); - s->gpsr[bank] = value; - break; - - case GPCR: /* GPIO Pin-Output Clear registers */ - s->olevel[bank] &= ~value; - pxa2xx_gpio_handler_update(s); - break; - - case GRER: /* GPIO Rising-Edge Detect Enable registers */ - s->rising[bank] = value; - break; - - case GFER: /* GPIO Falling-Edge Detect Enable registers */ - s->falling[bank] = value; - break; - - case GAFR_L: /* GPIO Alternate Function registers */ - s->gafr[bank * 2] = value; - break; - - case GAFR_U: /* GPIO Alternate Function registers */ - s->gafr[bank * 2 + 1] = value; - break; - - case GEDR: /* GPIO Edge Detect Status registers */ - s->status[bank] &= ~value; - pxa2xx_gpio_irq_update(s); - break; - - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } -} - -static const MemoryRegionOps pxa_gpio_ops = { - .read = pxa2xx_gpio_read, - .write = pxa2xx_gpio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -DeviceState *pxa2xx_gpio_init(hwaddr base, - ARMCPU *cpu, DeviceState *pic, int lines) -{ - CPUState *cs = CPU(cpu); - DeviceState *dev; - - dev = qdev_create(NULL, "pxa2xx-gpio"); - qdev_prop_set_int32(dev, "lines", lines); - qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); - qdev_init_nofail(dev); - - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, - qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0)); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, - qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1)); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, - qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X)); - - return dev; -} - -static int pxa2xx_gpio_initfn(SysBusDevice *dev) -{ - PXA2xxGPIOInfo *s; - - s = FROM_SYSBUS(PXA2xxGPIOInfo, dev); - - s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu)); - - qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines); - qdev_init_gpio_out(&dev->qdev, s->handler, s->lines); - - memory_region_init_io(&s->iomem, &pxa_gpio_ops, s, "pxa2xx-gpio", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq0); - sysbus_init_irq(dev, &s->irq1); - sysbus_init_irq(dev, &s->irqX); - - return 0; -} - -/* - * Registers a callback to notify on GPLR reads. This normally - * shouldn't be needed but it is used for the hack on Spitz machines. - */ -void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler) -{ - PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, SYS_BUS_DEVICE(dev)); - s->read_notify = handler; -} - -static const VMStateDescription vmstate_pxa2xx_gpio_regs = { - .name = "pxa2xx-gpio", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT32(lines, PXA2xxGPIOInfo), - VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2), - VMSTATE_END_OF_LIST(), - }, -}; - -static Property pxa2xx_gpio_properties[] = { - DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0), - DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_gpio_initfn; - dc->desc = "PXA2xx GPIO controller"; - dc->props = pxa2xx_gpio_properties; -} - -static const TypeInfo pxa2xx_gpio_info = { - .name = "pxa2xx-gpio", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxGPIOInfo), - .class_init = pxa2xx_gpio_class_init, -}; - -static void pxa2xx_gpio_register_types(void) -{ - type_register_static(&pxa2xx_gpio_info); -} - -type_init(pxa2xx_gpio_register_types) diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c deleted file mode 100644 index 145fc78c2f..0000000000 --- a/hw/pxa2xx_pic.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Intel XScale PXA Programmable Interrupt Controller. - * - * Copyright (c) 2006 Openedhand Ltd. - * Copyright (c) 2006 Thorsten Zitterell - * Written by Andrzej Zaborowski - * - * This code is licensed under the GPL. - */ - -#include "hw/hw.h" -#include "hw/pxa.h" -#include "hw/sysbus.h" - -#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ -#define ICMR 0x04 /* Interrupt Controller Mask register */ -#define ICLR 0x08 /* Interrupt Controller Level register */ -#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */ -#define ICPR 0x10 /* Interrupt Controller Pending register */ -#define ICCR 0x14 /* Interrupt Controller Control register */ -#define ICHP 0x18 /* Interrupt Controller Highest Priority register */ -#define IPR0 0x1c /* Interrupt Controller Priority register 0 */ -#define IPR31 0x98 /* Interrupt Controller Priority register 31 */ -#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */ -#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */ -#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */ -#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */ -#define ICPR2 0xac /* Interrupt Controller Pending register 2 */ -#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */ -#define IPR39 0xcc /* Interrupt Controller Priority register 39 */ - -#define PXA2XX_PIC_SRCS 40 - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - ARMCPU *cpu; - uint32_t int_enabled[2]; - uint32_t int_pending[2]; - uint32_t is_fiq[2]; - uint32_t int_idle; - uint32_t priority[PXA2XX_PIC_SRCS]; -} PXA2xxPICState; - -static void pxa2xx_pic_update(void *opaque) -{ - uint32_t mask[2]; - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - - if (s->cpu->env.halted) { - mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); - mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); - if (mask[0] || mask[1]) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); - } - } - - mask[0] = s->int_pending[0] & s->int_enabled[0]; - mask[1] = s->int_pending[1] & s->int_enabled[1]; - - if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); - } else { - cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); - } - - if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); - } -} - -/* Note: Here level means state of the signal on a pin, not - * IRQ/FIQ distinction as in PXA Developer Manual. */ -static void pxa2xx_pic_set_irq(void *opaque, int irq, int level) -{ - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - int int_set = (irq >= 32); - irq &= 31; - - if (level) - s->int_pending[int_set] |= 1 << irq; - else - s->int_pending[int_set] &= ~(1 << irq); - - pxa2xx_pic_update(opaque); -} - -static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) { - int i, int_set, irq; - uint32_t bit, mask[2]; - uint32_t ichp = 0x003f003f; /* Both IDs invalid */ - - mask[0] = s->int_pending[0] & s->int_enabled[0]; - mask[1] = s->int_pending[1] & s->int_enabled[1]; - - for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) { - irq = s->priority[i] & 0x3f; - if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) { - /* Source peripheral ID is valid. */ - bit = 1 << (irq & 31); - int_set = (irq >= 32); - - if (mask[int_set] & bit & s->is_fiq[int_set]) { - /* FIQ asserted */ - ichp &= 0xffff0000; - ichp |= (1 << 15) | irq; - } - - if (mask[int_set] & bit & ~s->is_fiq[int_set]) { - /* IRQ asserted */ - ichp &= 0x0000ffff; - ichp |= (1 << 31) | (irq << 16); - } - } - } - - return ichp; -} - -static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset, - unsigned size) -{ - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - - switch (offset) { - case ICIP: /* IRQ Pending register */ - return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0]; - case ICIP2: /* IRQ Pending register 2 */ - return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1]; - case ICMR: /* Mask register */ - return s->int_enabled[0]; - case ICMR2: /* Mask register 2 */ - return s->int_enabled[1]; - case ICLR: /* Level register */ - return s->is_fiq[0]; - case ICLR2: /* Level register 2 */ - return s->is_fiq[1]; - case ICCR: /* Idle mask */ - return (s->int_idle == 0); - case ICFP: /* FIQ Pending register */ - return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0]; - case ICFP2: /* FIQ Pending register 2 */ - return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1]; - case ICPR: /* Pending register */ - return s->int_pending[0]; - case ICPR2: /* Pending register 2 */ - return s->int_pending[1]; - case IPR0 ... IPR31: - return s->priority[0 + ((offset - IPR0 ) >> 2)]; - case IPR32 ... IPR39: - return s->priority[32 + ((offset - IPR32) >> 2)]; - case ICHP: /* Highest Priority register */ - return pxa2xx_pic_highest(s); - default: - printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); - return 0; - } -} - -static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - - switch (offset) { - case ICMR: /* Mask register */ - s->int_enabled[0] = value; - break; - case ICMR2: /* Mask register 2 */ - s->int_enabled[1] = value; - break; - case ICLR: /* Level register */ - s->is_fiq[0] = value; - break; - case ICLR2: /* Level register 2 */ - s->is_fiq[1] = value; - break; - case ICCR: /* Idle mask */ - s->int_idle = (value & 1) ? 0 : ~0; - break; - case IPR0 ... IPR31: - s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f; - break; - case IPR32 ... IPR39: - s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f; - break; - default: - printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); - return; - } - pxa2xx_pic_update(opaque); -} - -/* Interrupt Controller Coprocessor Space Register Mapping */ -static const int pxa2xx_cp_reg_map[0x10] = { - [0x0 ... 0xf] = -1, - [0x0] = ICIP, - [0x1] = ICMR, - [0x2] = ICLR, - [0x3] = ICFP, - [0x4] = ICPR, - [0x5] = ICHP, - [0x6] = ICIP2, - [0x7] = ICMR2, - [0x8] = ICLR2, - [0x9] = ICFP2, - [0xa] = ICPR2, -}; - -static int pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t *value) -{ - int offset = pxa2xx_cp_reg_map[ri->crn]; - *value = pxa2xx_pic_mem_read(ri->opaque, offset, 4); - return 0; -} - -static int pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - int offset = pxa2xx_cp_reg_map[ri->crn]; - pxa2xx_pic_mem_write(ri->opaque, offset, value, 4); - return 0; -} - -#define REGINFO_FOR_PIC_CP(NAME, CRN) \ - { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \ - .access = PL1_RW, \ - .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write } - -static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { - REGINFO_FOR_PIC_CP("ICIP", 0), - REGINFO_FOR_PIC_CP("ICMR", 1), - REGINFO_FOR_PIC_CP("ICLR", 2), - REGINFO_FOR_PIC_CP("ICFP", 3), - REGINFO_FOR_PIC_CP("ICPR", 4), - REGINFO_FOR_PIC_CP("ICHP", 5), - REGINFO_FOR_PIC_CP("ICIP2", 6), - REGINFO_FOR_PIC_CP("ICMR2", 7), - REGINFO_FOR_PIC_CP("ICLR2", 8), - REGINFO_FOR_PIC_CP("ICFP2", 9), - REGINFO_FOR_PIC_CP("ICPR2", 0xa), - REGINFO_SENTINEL -}; - -static const MemoryRegionOps pxa2xx_pic_ops = { - .read = pxa2xx_pic_mem_read, - .write = pxa2xx_pic_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pxa2xx_pic_post_load(void *opaque, int version_id) -{ - pxa2xx_pic_update(opaque); - return 0; -} - -DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) -{ - CPUARMState *env = &cpu->env; - DeviceState *dev = qdev_create(NULL, "pxa2xx_pic"); - PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, SYS_BUS_DEVICE(dev)); - - s->cpu = cpu; - - s->int_pending[0] = 0; - s->int_pending[1] = 0; - s->int_enabled[0] = 0; - s->int_enabled[1] = 0; - s->is_fiq[0] = 0; - s->is_fiq[1] = 0; - - qdev_init_nofail(dev); - - qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS); - - /* Enable IC memory-mapped registers access. */ - memory_region_init_io(&s->iomem, &pxa2xx_pic_ops, s, - "pxa2xx-pic", 0x00100000); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - /* Enable IC coprocessor access. */ - define_arm_cp_regs_with_opaque(arm_env_get_cpu(env), pxa_pic_cp_reginfo, s); - - return dev; -} - -static VMStateDescription vmstate_pxa2xx_pic_regs = { - .name = "pxa2xx_pic", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .post_load = pxa2xx_pic_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2), - VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2), - VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2), - VMSTATE_UINT32(int_idle, PXA2xxPICState), - VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS), - VMSTATE_END_OF_LIST(), - }, -}; - -static int pxa2xx_pic_initfn(SysBusDevice *dev) -{ - return 0; -} - -static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_pic_initfn; - dc->desc = "PXA2xx PIC"; - dc->vmsd = &vmstate_pxa2xx_pic_regs; -} - -static const TypeInfo pxa2xx_pic_info = { - .name = "pxa2xx_pic", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxPICState), - .class_init = pxa2xx_pic_class_init, -}; - -static void pxa2xx_pic_register_types(void) -{ - type_register_static(&pxa2xx_pic_info); -} - -type_init(pxa2xx_pic_register_types) -- cgit v1.2.3 From 8786b05e7bf3c4fc7a25fa14f1736a716cd8a8c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: i386: move files referencing CPU to hw/i386/ Signed-off-by: Paolo Bonzini --- hw/i386/Makefile.objs | 4 +- hw/i386/kvmvapic.c | 822 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/kvmvapic.c | 822 -------------------------------------------------- 3 files changed, 825 insertions(+), 823 deletions(-) create mode 100644 hw/i386/kvmvapic.c delete mode 100644 hw/kvmvapic.c diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 5d071f418e..a78c0b2921 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,5 +1,5 @@ obj-y += mc146818rtc.o -obj-y += apic_common.o apic.o kvmvapic.o +obj-y += apic_common.o apic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o obj-y += pci/pci-hotplug.o wdt_ib700.o @@ -18,3 +18,5 @@ obj-y := $(addprefix ../,$(obj-y)) obj-y += multiboot.o smbios.o obj-y += pc.o pc_piix.o pc_q35.o obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o + +obj-y += kvmvapic.o diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c new file mode 100644 index 0000000000..c151c95c3e --- /dev/null +++ b/hw/i386/kvmvapic.c @@ -0,0 +1,822 @@ +/* + * TPR optimization for 32-bit Windows guests (XP and Server 2003) + * + * Copyright (C) 2007-2008 Qumranet Technologies + * Copyright (C) 2012 Jan Kiszka, Siemens AG + * + * This work is licensed under the terms of the GNU GPL version 2, or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "sysemu/kvm.h" +#include "hw/apic_internal.h" + +#define APIC_DEFAULT_ADDRESS 0xfee00000 + +#define VAPIC_IO_PORT 0x7e + +#define VAPIC_CPU_SHIFT 7 + +#define ROM_BLOCK_SIZE 512 +#define ROM_BLOCK_MASK (~(ROM_BLOCK_SIZE - 1)) + +typedef enum VAPICMode { + VAPIC_INACTIVE = 0, + VAPIC_ACTIVE = 1, + VAPIC_STANDBY = 2, +} VAPICMode; + +typedef struct VAPICHandlers { + uint32_t set_tpr; + uint32_t set_tpr_eax; + uint32_t get_tpr[8]; + uint32_t get_tpr_stack; +} QEMU_PACKED VAPICHandlers; + +typedef struct GuestROMState { + char signature[8]; + uint32_t vaddr; + uint32_t fixup_start; + uint32_t fixup_end; + uint32_t vapic_vaddr; + uint32_t vapic_size; + uint32_t vcpu_shift; + uint32_t real_tpr_addr; + VAPICHandlers up; + VAPICHandlers mp; +} QEMU_PACKED GuestROMState; + +typedef struct VAPICROMState { + SysBusDevice busdev; + MemoryRegion io; + MemoryRegion rom; + uint32_t state; + uint32_t rom_state_paddr; + uint32_t rom_state_vaddr; + uint32_t vapic_paddr; + uint32_t real_tpr_addr; + GuestROMState rom_state; + size_t rom_size; + bool rom_mapped_writable; +} VAPICROMState; + +#define TPR_INSTR_ABS_MODRM 0x1 +#define TPR_INSTR_MATCH_MODRM_REG 0x2 + +typedef struct TPRInstruction { + uint8_t opcode; + uint8_t modrm_reg; + unsigned int flags; + TPRAccess access; + size_t length; + off_t addr_offset; +} TPRInstruction; + +/* must be sorted by length, shortest first */ +static const TPRInstruction tpr_instr[] = { + { /* mov abs to eax */ + .opcode = 0xa1, + .access = TPR_ACCESS_READ, + .length = 5, + .addr_offset = 1, + }, + { /* mov eax to abs */ + .opcode = 0xa3, + .access = TPR_ACCESS_WRITE, + .length = 5, + .addr_offset = 1, + }, + { /* mov r32 to r/m32 */ + .opcode = 0x89, + .flags = TPR_INSTR_ABS_MODRM, + .access = TPR_ACCESS_WRITE, + .length = 6, + .addr_offset = 2, + }, + { /* mov r/m32 to r32 */ + .opcode = 0x8b, + .flags = TPR_INSTR_ABS_MODRM, + .access = TPR_ACCESS_READ, + .length = 6, + .addr_offset = 2, + }, + { /* push r/m32 */ + .opcode = 0xff, + .modrm_reg = 6, + .flags = TPR_INSTR_ABS_MODRM | TPR_INSTR_MATCH_MODRM_REG, + .access = TPR_ACCESS_READ, + .length = 6, + .addr_offset = 2, + }, + { /* mov imm32, r/m32 (c7/0) */ + .opcode = 0xc7, + .modrm_reg = 0, + .flags = TPR_INSTR_ABS_MODRM | TPR_INSTR_MATCH_MODRM_REG, + .access = TPR_ACCESS_WRITE, + .length = 10, + .addr_offset = 2, + }, +}; + +static void read_guest_rom_state(VAPICROMState *s) +{ + cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state, + sizeof(GuestROMState), 0); +} + +static void write_guest_rom_state(VAPICROMState *s) +{ + cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state, + sizeof(GuestROMState), 1); +} + +static void update_guest_rom_state(VAPICROMState *s) +{ + read_guest_rom_state(s); + + s->rom_state.real_tpr_addr = cpu_to_le32(s->real_tpr_addr); + s->rom_state.vcpu_shift = cpu_to_le32(VAPIC_CPU_SHIFT); + + write_guest_rom_state(s); +} + +static int find_real_tpr_addr(VAPICROMState *s, CPUX86State *env) +{ + hwaddr paddr; + target_ulong addr; + + if (s->state == VAPIC_ACTIVE) { + return 0; + } + /* + * If there is no prior TPR access instruction we could analyze (which is + * the case after resume from hibernation), we need to scan the possible + * virtual address space for the APIC mapping. + */ + for (addr = 0xfffff000; addr >= 0x80000000; addr -= TARGET_PAGE_SIZE) { + paddr = cpu_get_phys_page_debug(env, addr); + if (paddr != APIC_DEFAULT_ADDRESS) { + continue; + } + s->real_tpr_addr = addr + 0x80; + update_guest_rom_state(s); + return 0; + } + return -1; +} + +static uint8_t modrm_reg(uint8_t modrm) +{ + return (modrm >> 3) & 7; +} + +static bool is_abs_modrm(uint8_t modrm) +{ + return (modrm & 0xc7) == 0x05; +} + +static bool opcode_matches(uint8_t *opcode, const TPRInstruction *instr) +{ + return opcode[0] == instr->opcode && + (!(instr->flags & TPR_INSTR_ABS_MODRM) || is_abs_modrm(opcode[1])) && + (!(instr->flags & TPR_INSTR_MATCH_MODRM_REG) || + modrm_reg(opcode[1]) == instr->modrm_reg); +} + +static int evaluate_tpr_instruction(VAPICROMState *s, CPUX86State *env, + target_ulong *pip, TPRAccess access) +{ + const TPRInstruction *instr; + target_ulong ip = *pip; + uint8_t opcode[2]; + uint32_t real_tpr_addr; + int i; + + if ((ip & 0xf0000000ULL) != 0x80000000ULL && + (ip & 0xf0000000ULL) != 0xe0000000ULL) { + return -1; + } + + /* + * Early Windows 2003 SMP initialization contains a + * + * mov imm32, r/m32 + * + * instruction that is patched by TPR optimization. The problem is that + * RSP, used by the patched instruction, is zero, so the guest gets a + * double fault and dies. + */ + if (env->regs[R_ESP] == 0) { + return -1; + } + + if (kvm_enabled() && !kvm_irqchip_in_kernel()) { + /* + * KVM without kernel-based TPR access reporting will pass an IP that + * points after the accessing instruction. So we need to look backward + * to find the reason. + */ + for (i = 0; i < ARRAY_SIZE(tpr_instr); i++) { + instr = &tpr_instr[i]; + if (instr->access != access) { + continue; + } + if (cpu_memory_rw_debug(env, ip - instr->length, opcode, + sizeof(opcode), 0) < 0) { + return -1; + } + if (opcode_matches(opcode, instr)) { + ip -= instr->length; + goto instruction_ok; + } + } + return -1; + } else { + if (cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0) < 0) { + return -1; + } + for (i = 0; i < ARRAY_SIZE(tpr_instr); i++) { + instr = &tpr_instr[i]; + if (opcode_matches(opcode, instr)) { + goto instruction_ok; + } + } + return -1; + } + +instruction_ok: + /* + * Grab the virtual TPR address from the instruction + * and update the cached values. + */ + if (cpu_memory_rw_debug(env, ip + instr->addr_offset, + (void *)&real_tpr_addr, + sizeof(real_tpr_addr), 0) < 0) { + return -1; + } + real_tpr_addr = le32_to_cpu(real_tpr_addr); + if ((real_tpr_addr & 0xfff) != 0x80) { + return -1; + } + s->real_tpr_addr = real_tpr_addr; + update_guest_rom_state(s); + + *pip = ip; + return 0; +} + +static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong ip) +{ + hwaddr paddr; + uint32_t rom_state_vaddr; + uint32_t pos, patch, offset; + + /* nothing to do if already activated */ + if (s->state == VAPIC_ACTIVE) { + return 0; + } + + /* bail out if ROM init code was not executed (missing ROM?) */ + if (s->state == VAPIC_INACTIVE) { + return -1; + } + + /* find out virtual address of the ROM */ + rom_state_vaddr = s->rom_state_paddr + (ip & 0xf0000000); + paddr = cpu_get_phys_page_debug(env, rom_state_vaddr); + if (paddr == -1) { + return -1; + } + paddr += rom_state_vaddr & ~TARGET_PAGE_MASK; + if (paddr != s->rom_state_paddr) { + return -1; + } + read_guest_rom_state(s); + if (memcmp(s->rom_state.signature, "kvm aPiC", 8) != 0) { + return -1; + } + s->rom_state_vaddr = rom_state_vaddr; + + /* fixup addresses in ROM if needed */ + if (rom_state_vaddr == le32_to_cpu(s->rom_state.vaddr)) { + return 0; + } + for (pos = le32_to_cpu(s->rom_state.fixup_start); + pos < le32_to_cpu(s->rom_state.fixup_end); + pos += 4) { + cpu_physical_memory_rw(paddr + pos - s->rom_state.vaddr, + (void *)&offset, sizeof(offset), 0); + offset = le32_to_cpu(offset); + cpu_physical_memory_rw(paddr + offset, (void *)&patch, + sizeof(patch), 0); + patch = le32_to_cpu(patch); + patch += rom_state_vaddr - le32_to_cpu(s->rom_state.vaddr); + patch = cpu_to_le32(patch); + cpu_physical_memory_rw(paddr + offset, (void *)&patch, + sizeof(patch), 1); + } + read_guest_rom_state(s); + s->vapic_paddr = paddr + le32_to_cpu(s->rom_state.vapic_vaddr) - + le32_to_cpu(s->rom_state.vaddr); + + return 0; +} + +/* + * Tries to read the unique processor number from the Kernel Processor Control + * Region (KPCR) of 32-bit Windows XP and Server 2003. Returns -1 if the KPCR + * cannot be accessed or is considered invalid. This also ensures that we are + * not patching the wrong guest. + */ +static int get_kpcr_number(CPUX86State *env) +{ + struct kpcr { + uint8_t fill1[0x1c]; + uint32_t self; + uint8_t fill2[0x31]; + uint8_t number; + } QEMU_PACKED kpcr; + + if (cpu_memory_rw_debug(env, env->segs[R_FS].base, + (void *)&kpcr, sizeof(kpcr), 0) < 0 || + kpcr.self != env->segs[R_FS].base) { + return -1; + } + return kpcr.number; +} + +static int vapic_enable(VAPICROMState *s, CPUX86State *env) +{ + int cpu_number = get_kpcr_number(env); + hwaddr vapic_paddr; + static const uint8_t enabled = 1; + + if (cpu_number < 0) { + return -1; + } + vapic_paddr = s->vapic_paddr + + (((hwaddr)cpu_number) << VAPIC_CPU_SHIFT); + cpu_physical_memory_rw(vapic_paddr + offsetof(VAPICState, enabled), + (void *)&enabled, sizeof(enabled), 1); + apic_enable_vapic(env->apic_state, vapic_paddr); + + s->state = VAPIC_ACTIVE; + + return 0; +} + +static void patch_byte(CPUX86State *env, target_ulong addr, uint8_t byte) +{ + cpu_memory_rw_debug(env, addr, &byte, 1, 1); +} + +static void patch_call(VAPICROMState *s, CPUX86State *env, target_ulong ip, + uint32_t target) +{ + uint32_t offset; + + offset = cpu_to_le32(target - ip - 5); + patch_byte(env, ip, 0xe8); /* call near */ + cpu_memory_rw_debug(env, ip + 1, (void *)&offset, sizeof(offset), 1); +} + +static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) +{ + CPUState *cs = CPU(cpu); + CPUX86State *env = &cpu->env; + VAPICHandlers *handlers; + uint8_t opcode[2]; + uint32_t imm32; + target_ulong current_pc = 0; + target_ulong current_cs_base = 0; + int current_flags = 0; + + if (smp_cpus == 1) { + handlers = &s->rom_state.up; + } else { + handlers = &s->rom_state.mp; + } + + if (!kvm_enabled()) { + cpu_restore_state(env, env->mem_io_pc); + cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, + ¤t_flags); + } + + pause_all_vcpus(); + + cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0); + + switch (opcode[0]) { + case 0x89: /* mov r32 to r/m32 */ + patch_byte(env, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */ + patch_call(s, env, ip + 1, handlers->set_tpr); + break; + case 0x8b: /* mov r/m32 to r32 */ + patch_byte(env, ip, 0x90); + patch_call(s, env, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]); + break; + case 0xa1: /* mov abs to eax */ + patch_call(s, env, ip, handlers->get_tpr[0]); + break; + case 0xa3: /* mov eax to abs */ + patch_call(s, env, ip, handlers->set_tpr_eax); + break; + case 0xc7: /* mov imm32, r/m32 (c7/0) */ + patch_byte(env, ip, 0x68); /* push imm32 */ + cpu_memory_rw_debug(env, ip + 6, (void *)&imm32, sizeof(imm32), 0); + cpu_memory_rw_debug(env, ip + 1, (void *)&imm32, sizeof(imm32), 1); + patch_call(s, env, ip + 5, handlers->set_tpr); + break; + case 0xff: /* push r/m32 */ + patch_byte(env, ip, 0x50); /* push eax */ + patch_call(s, env, ip + 1, handlers->get_tpr_stack); + break; + default: + abort(); + } + + resume_all_vcpus(); + + if (!kvm_enabled()) { + cs->current_tb = NULL; + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + cpu_resume_from_signal(env, NULL); + } +} + +void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip, + TPRAccess access) +{ + VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + cpu_synchronize_state(env); + + if (evaluate_tpr_instruction(s, env, &ip, access) < 0) { + if (s->state == VAPIC_ACTIVE) { + vapic_enable(s, env); + } + return; + } + if (update_rom_mapping(s, env, ip) < 0) { + return; + } + if (vapic_enable(s, env) < 0) { + return; + } + patch_instruction(s, cpu, ip); +} + +typedef struct VAPICEnableTPRReporting { + DeviceState *apic; + bool enable; +} VAPICEnableTPRReporting; + +static void vapic_do_enable_tpr_reporting(void *data) +{ + VAPICEnableTPRReporting *info = data; + + apic_enable_tpr_access_reporting(info->apic, info->enable); +} + +static void vapic_enable_tpr_reporting(bool enable) +{ + VAPICEnableTPRReporting info = { + .enable = enable, + }; + X86CPU *cpu; + CPUX86State *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = x86_env_get_cpu(env); + info.apic = env->apic_state; + run_on_cpu(CPU(cpu), vapic_do_enable_tpr_reporting, &info); + } +} + +static void vapic_reset(DeviceState *dev) +{ + VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev); + + if (s->state == VAPIC_ACTIVE) { + s->state = VAPIC_STANDBY; + } + vapic_enable_tpr_reporting(false); +} + +/* + * Set the IRQ polling hypercalls to the supported variant: + * - vmcall if using KVM in-kernel irqchip + * - 32-bit VAPIC port write otherwise + */ +static int patch_hypercalls(VAPICROMState *s) +{ + hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; + static const uint8_t vmcall_pattern[] = { /* vmcall */ + 0xb8, 0x1, 0, 0, 0, 0xf, 0x1, 0xc1 + }; + static const uint8_t outl_pattern[] = { /* nop; outl %eax,0x7e */ + 0xb8, 0x1, 0, 0, 0, 0x90, 0xe7, 0x7e + }; + uint8_t alternates[2]; + const uint8_t *pattern; + const uint8_t *patch; + int patches = 0; + off_t pos; + uint8_t *rom; + + rom = g_malloc(s->rom_size); + cpu_physical_memory_rw(rom_paddr, rom, s->rom_size, 0); + + for (pos = 0; pos < s->rom_size - sizeof(vmcall_pattern); pos++) { + if (kvm_irqchip_in_kernel()) { + pattern = outl_pattern; + alternates[0] = outl_pattern[7]; + alternates[1] = outl_pattern[7]; + patch = &vmcall_pattern[5]; + } else { + pattern = vmcall_pattern; + alternates[0] = vmcall_pattern[7]; + alternates[1] = 0xd9; /* AMD's VMMCALL */ + patch = &outl_pattern[5]; + } + if (memcmp(rom + pos, pattern, 7) == 0 && + (rom[pos + 7] == alternates[0] || rom[pos + 7] == alternates[1])) { + cpu_physical_memory_rw(rom_paddr + pos + 5, (uint8_t *)patch, + 3, 1); + /* + * Don't flush the tb here. Under ordinary conditions, the patched + * calls are miles away from the current IP. Under malicious + * conditions, the guest could trick us to crash. + */ + } + } + + g_free(rom); + + if (patches != 0 && patches != 2) { + return -1; + } + + return 0; +} + +/* + * For TCG mode or the time KVM honors read-only memory regions, we need to + * enable write access to the option ROM so that variables can be updated by + * the guest. + */ +static void vapic_map_rom_writable(VAPICROMState *s) +{ + hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; + MemoryRegionSection section; + MemoryRegion *as; + size_t rom_size; + uint8_t *ram; + + as = sysbus_address_space(&s->busdev); + + if (s->rom_mapped_writable) { + memory_region_del_subregion(as, &s->rom); + memory_region_destroy(&s->rom); + } + + /* grab RAM memory region (region @rom_paddr may still be pc.rom) */ + section = memory_region_find(as, 0, 1); + + /* read ROM size from RAM region */ + ram = memory_region_get_ram_ptr(section.mr); + rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE; + s->rom_size = rom_size; + + /* We need to round to avoid creating subpages + * from which we cannot run code. */ + rom_size += rom_paddr & ~TARGET_PAGE_MASK; + rom_paddr &= TARGET_PAGE_MASK; + rom_size = TARGET_PAGE_ALIGN(rom_size); + + memory_region_init_alias(&s->rom, "kvmvapic-rom", section.mr, rom_paddr, + rom_size); + memory_region_add_subregion_overlap(as, rom_paddr, &s->rom, 1000); + s->rom_mapped_writable = true; +} + +static int vapic_prepare(VAPICROMState *s) +{ + vapic_map_rom_writable(s); + + if (patch_hypercalls(s) < 0) { + return -1; + } + + vapic_enable_tpr_reporting(true); + + return 0; +} + +static void vapic_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) +{ + CPUX86State *env = cpu_single_env; + hwaddr rom_paddr; + VAPICROMState *s = opaque; + + cpu_synchronize_state(env); + + /* + * The VAPIC supports two PIO-based hypercalls, both via port 0x7E. + * o 16-bit write access: + * Reports the option ROM initialization to the hypervisor. Written + * value is the offset of the state structure in the ROM. + * o 8-bit write access: + * Reactivates the VAPIC after a guest hibernation, i.e. after the + * option ROM content has been re-initialized by a guest power cycle. + * o 32-bit write access: + * Poll for pending IRQs, considering the current VAPIC state. + */ + switch (size) { + case 2: + if (s->state == VAPIC_INACTIVE) { + rom_paddr = (env->segs[R_CS].base + env->eip) & ROM_BLOCK_MASK; + s->rom_state_paddr = rom_paddr + data; + + s->state = VAPIC_STANDBY; + } + if (vapic_prepare(s) < 0) { + s->state = VAPIC_INACTIVE; + break; + } + break; + case 1: + if (kvm_enabled()) { + /* + * Disable triggering instruction in ROM by writing a NOP. + * + * We cannot do this in TCG mode as the reported IP is not + * accurate. + */ + pause_all_vcpus(); + patch_byte(env, env->eip - 2, 0x66); + patch_byte(env, env->eip - 1, 0x90); + resume_all_vcpus(); + } + + if (s->state == VAPIC_ACTIVE) { + break; + } + if (update_rom_mapping(s, env, env->eip) < 0) { + break; + } + if (find_real_tpr_addr(s, env) < 0) { + break; + } + vapic_enable(s, env); + break; + default: + case 4: + if (!kvm_irqchip_in_kernel()) { + apic_poll_irq(env->apic_state); + } + break; + } +} + +static const MemoryRegionOps vapic_ops = { + .write = vapic_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int vapic_init(SysBusDevice *dev) +{ + VAPICROMState *s = FROM_SYSBUS(VAPICROMState, dev); + + memory_region_init_io(&s->io, &vapic_ops, s, "kvmvapic", 2); + sysbus_add_io(dev, VAPIC_IO_PORT, &s->io); + sysbus_init_ioports(dev, VAPIC_IO_PORT, 2); + + option_rom[nb_option_roms].name = "kvmvapic.bin"; + option_rom[nb_option_roms].bootindex = -1; + nb_option_roms++; + + return 0; +} + +static void do_vapic_enable(void *data) +{ + VAPICROMState *s = data; + + vapic_enable(s, first_cpu); +} + +static int vapic_post_load(void *opaque, int version_id) +{ + VAPICROMState *s = opaque; + uint8_t *zero; + + /* + * The old implementation of qemu-kvm did not provide the state + * VAPIC_STANDBY. Reconstruct it. + */ + if (s->state == VAPIC_INACTIVE && s->rom_state_paddr != 0) { + s->state = VAPIC_STANDBY; + } + + if (s->state != VAPIC_INACTIVE) { + if (vapic_prepare(s) < 0) { + return -1; + } + } + if (s->state == VAPIC_ACTIVE) { + if (smp_cpus == 1) { + run_on_cpu(ENV_GET_CPU(first_cpu), do_vapic_enable, s); + } else { + zero = g_malloc0(s->rom_state.vapic_size); + cpu_physical_memory_rw(s->vapic_paddr, zero, + s->rom_state.vapic_size, 1); + g_free(zero); + } + } + + return 0; +} + +static const VMStateDescription vmstate_handlers = { + .name = "kvmvapic-handlers", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(set_tpr, VAPICHandlers), + VMSTATE_UINT32(set_tpr_eax, VAPICHandlers), + VMSTATE_UINT32_ARRAY(get_tpr, VAPICHandlers, 8), + VMSTATE_UINT32(get_tpr_stack, VAPICHandlers), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_guest_rom = { + .name = "kvmvapic-guest-rom", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UNUSED(8), /* signature */ + VMSTATE_UINT32(vaddr, GuestROMState), + VMSTATE_UINT32(fixup_start, GuestROMState), + VMSTATE_UINT32(fixup_end, GuestROMState), + VMSTATE_UINT32(vapic_vaddr, GuestROMState), + VMSTATE_UINT32(vapic_size, GuestROMState), + VMSTATE_UINT32(vcpu_shift, GuestROMState), + VMSTATE_UINT32(real_tpr_addr, GuestROMState), + VMSTATE_STRUCT(up, GuestROMState, 0, vmstate_handlers, VAPICHandlers), + VMSTATE_STRUCT(mp, GuestROMState, 0, vmstate_handlers, VAPICHandlers), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_vapic = { + .name = "kvm-tpr-opt", /* compatible with qemu-kvm VAPIC */ + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = vapic_post_load, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(rom_state, VAPICROMState, 0, vmstate_guest_rom, + GuestROMState), + VMSTATE_UINT32(state, VAPICROMState), + VMSTATE_UINT32(real_tpr_addr, VAPICROMState), + VMSTATE_UINT32(rom_state_vaddr, VAPICROMState), + VMSTATE_UINT32(vapic_paddr, VAPICROMState), + VMSTATE_UINT32(rom_state_paddr, VAPICROMState), + VMSTATE_END_OF_LIST() + } +}; + +static void vapic_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->no_user = 1; + dc->reset = vapic_reset; + dc->vmsd = &vmstate_vapic; + sc->init = vapic_init; +} + +static const TypeInfo vapic_type = { + .name = "kvmvapic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VAPICROMState), + .class_init = vapic_class_init, +}; + +static void vapic_register(void) +{ + type_register_static(&vapic_type); +} + +type_init(vapic_register); diff --git a/hw/kvmvapic.c b/hw/kvmvapic.c deleted file mode 100644 index c151c95c3e..0000000000 --- a/hw/kvmvapic.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * TPR optimization for 32-bit Windows guests (XP and Server 2003) - * - * Copyright (C) 2007-2008 Qumranet Technologies - * Copyright (C) 2012 Jan Kiszka, Siemens AG - * - * This work is licensed under the terms of the GNU GPL version 2, or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ -#include "sysemu/sysemu.h" -#include "sysemu/cpus.h" -#include "sysemu/kvm.h" -#include "hw/apic_internal.h" - -#define APIC_DEFAULT_ADDRESS 0xfee00000 - -#define VAPIC_IO_PORT 0x7e - -#define VAPIC_CPU_SHIFT 7 - -#define ROM_BLOCK_SIZE 512 -#define ROM_BLOCK_MASK (~(ROM_BLOCK_SIZE - 1)) - -typedef enum VAPICMode { - VAPIC_INACTIVE = 0, - VAPIC_ACTIVE = 1, - VAPIC_STANDBY = 2, -} VAPICMode; - -typedef struct VAPICHandlers { - uint32_t set_tpr; - uint32_t set_tpr_eax; - uint32_t get_tpr[8]; - uint32_t get_tpr_stack; -} QEMU_PACKED VAPICHandlers; - -typedef struct GuestROMState { - char signature[8]; - uint32_t vaddr; - uint32_t fixup_start; - uint32_t fixup_end; - uint32_t vapic_vaddr; - uint32_t vapic_size; - uint32_t vcpu_shift; - uint32_t real_tpr_addr; - VAPICHandlers up; - VAPICHandlers mp; -} QEMU_PACKED GuestROMState; - -typedef struct VAPICROMState { - SysBusDevice busdev; - MemoryRegion io; - MemoryRegion rom; - uint32_t state; - uint32_t rom_state_paddr; - uint32_t rom_state_vaddr; - uint32_t vapic_paddr; - uint32_t real_tpr_addr; - GuestROMState rom_state; - size_t rom_size; - bool rom_mapped_writable; -} VAPICROMState; - -#define TPR_INSTR_ABS_MODRM 0x1 -#define TPR_INSTR_MATCH_MODRM_REG 0x2 - -typedef struct TPRInstruction { - uint8_t opcode; - uint8_t modrm_reg; - unsigned int flags; - TPRAccess access; - size_t length; - off_t addr_offset; -} TPRInstruction; - -/* must be sorted by length, shortest first */ -static const TPRInstruction tpr_instr[] = { - { /* mov abs to eax */ - .opcode = 0xa1, - .access = TPR_ACCESS_READ, - .length = 5, - .addr_offset = 1, - }, - { /* mov eax to abs */ - .opcode = 0xa3, - .access = TPR_ACCESS_WRITE, - .length = 5, - .addr_offset = 1, - }, - { /* mov r32 to r/m32 */ - .opcode = 0x89, - .flags = TPR_INSTR_ABS_MODRM, - .access = TPR_ACCESS_WRITE, - .length = 6, - .addr_offset = 2, - }, - { /* mov r/m32 to r32 */ - .opcode = 0x8b, - .flags = TPR_INSTR_ABS_MODRM, - .access = TPR_ACCESS_READ, - .length = 6, - .addr_offset = 2, - }, - { /* push r/m32 */ - .opcode = 0xff, - .modrm_reg = 6, - .flags = TPR_INSTR_ABS_MODRM | TPR_INSTR_MATCH_MODRM_REG, - .access = TPR_ACCESS_READ, - .length = 6, - .addr_offset = 2, - }, - { /* mov imm32, r/m32 (c7/0) */ - .opcode = 0xc7, - .modrm_reg = 0, - .flags = TPR_INSTR_ABS_MODRM | TPR_INSTR_MATCH_MODRM_REG, - .access = TPR_ACCESS_WRITE, - .length = 10, - .addr_offset = 2, - }, -}; - -static void read_guest_rom_state(VAPICROMState *s) -{ - cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state, - sizeof(GuestROMState), 0); -} - -static void write_guest_rom_state(VAPICROMState *s) -{ - cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state, - sizeof(GuestROMState), 1); -} - -static void update_guest_rom_state(VAPICROMState *s) -{ - read_guest_rom_state(s); - - s->rom_state.real_tpr_addr = cpu_to_le32(s->real_tpr_addr); - s->rom_state.vcpu_shift = cpu_to_le32(VAPIC_CPU_SHIFT); - - write_guest_rom_state(s); -} - -static int find_real_tpr_addr(VAPICROMState *s, CPUX86State *env) -{ - hwaddr paddr; - target_ulong addr; - - if (s->state == VAPIC_ACTIVE) { - return 0; - } - /* - * If there is no prior TPR access instruction we could analyze (which is - * the case after resume from hibernation), we need to scan the possible - * virtual address space for the APIC mapping. - */ - for (addr = 0xfffff000; addr >= 0x80000000; addr -= TARGET_PAGE_SIZE) { - paddr = cpu_get_phys_page_debug(env, addr); - if (paddr != APIC_DEFAULT_ADDRESS) { - continue; - } - s->real_tpr_addr = addr + 0x80; - update_guest_rom_state(s); - return 0; - } - return -1; -} - -static uint8_t modrm_reg(uint8_t modrm) -{ - return (modrm >> 3) & 7; -} - -static bool is_abs_modrm(uint8_t modrm) -{ - return (modrm & 0xc7) == 0x05; -} - -static bool opcode_matches(uint8_t *opcode, const TPRInstruction *instr) -{ - return opcode[0] == instr->opcode && - (!(instr->flags & TPR_INSTR_ABS_MODRM) || is_abs_modrm(opcode[1])) && - (!(instr->flags & TPR_INSTR_MATCH_MODRM_REG) || - modrm_reg(opcode[1]) == instr->modrm_reg); -} - -static int evaluate_tpr_instruction(VAPICROMState *s, CPUX86State *env, - target_ulong *pip, TPRAccess access) -{ - const TPRInstruction *instr; - target_ulong ip = *pip; - uint8_t opcode[2]; - uint32_t real_tpr_addr; - int i; - - if ((ip & 0xf0000000ULL) != 0x80000000ULL && - (ip & 0xf0000000ULL) != 0xe0000000ULL) { - return -1; - } - - /* - * Early Windows 2003 SMP initialization contains a - * - * mov imm32, r/m32 - * - * instruction that is patched by TPR optimization. The problem is that - * RSP, used by the patched instruction, is zero, so the guest gets a - * double fault and dies. - */ - if (env->regs[R_ESP] == 0) { - return -1; - } - - if (kvm_enabled() && !kvm_irqchip_in_kernel()) { - /* - * KVM without kernel-based TPR access reporting will pass an IP that - * points after the accessing instruction. So we need to look backward - * to find the reason. - */ - for (i = 0; i < ARRAY_SIZE(tpr_instr); i++) { - instr = &tpr_instr[i]; - if (instr->access != access) { - continue; - } - if (cpu_memory_rw_debug(env, ip - instr->length, opcode, - sizeof(opcode), 0) < 0) { - return -1; - } - if (opcode_matches(opcode, instr)) { - ip -= instr->length; - goto instruction_ok; - } - } - return -1; - } else { - if (cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0) < 0) { - return -1; - } - for (i = 0; i < ARRAY_SIZE(tpr_instr); i++) { - instr = &tpr_instr[i]; - if (opcode_matches(opcode, instr)) { - goto instruction_ok; - } - } - return -1; - } - -instruction_ok: - /* - * Grab the virtual TPR address from the instruction - * and update the cached values. - */ - if (cpu_memory_rw_debug(env, ip + instr->addr_offset, - (void *)&real_tpr_addr, - sizeof(real_tpr_addr), 0) < 0) { - return -1; - } - real_tpr_addr = le32_to_cpu(real_tpr_addr); - if ((real_tpr_addr & 0xfff) != 0x80) { - return -1; - } - s->real_tpr_addr = real_tpr_addr; - update_guest_rom_state(s); - - *pip = ip; - return 0; -} - -static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong ip) -{ - hwaddr paddr; - uint32_t rom_state_vaddr; - uint32_t pos, patch, offset; - - /* nothing to do if already activated */ - if (s->state == VAPIC_ACTIVE) { - return 0; - } - - /* bail out if ROM init code was not executed (missing ROM?) */ - if (s->state == VAPIC_INACTIVE) { - return -1; - } - - /* find out virtual address of the ROM */ - rom_state_vaddr = s->rom_state_paddr + (ip & 0xf0000000); - paddr = cpu_get_phys_page_debug(env, rom_state_vaddr); - if (paddr == -1) { - return -1; - } - paddr += rom_state_vaddr & ~TARGET_PAGE_MASK; - if (paddr != s->rom_state_paddr) { - return -1; - } - read_guest_rom_state(s); - if (memcmp(s->rom_state.signature, "kvm aPiC", 8) != 0) { - return -1; - } - s->rom_state_vaddr = rom_state_vaddr; - - /* fixup addresses in ROM if needed */ - if (rom_state_vaddr == le32_to_cpu(s->rom_state.vaddr)) { - return 0; - } - for (pos = le32_to_cpu(s->rom_state.fixup_start); - pos < le32_to_cpu(s->rom_state.fixup_end); - pos += 4) { - cpu_physical_memory_rw(paddr + pos - s->rom_state.vaddr, - (void *)&offset, sizeof(offset), 0); - offset = le32_to_cpu(offset); - cpu_physical_memory_rw(paddr + offset, (void *)&patch, - sizeof(patch), 0); - patch = le32_to_cpu(patch); - patch += rom_state_vaddr - le32_to_cpu(s->rom_state.vaddr); - patch = cpu_to_le32(patch); - cpu_physical_memory_rw(paddr + offset, (void *)&patch, - sizeof(patch), 1); - } - read_guest_rom_state(s); - s->vapic_paddr = paddr + le32_to_cpu(s->rom_state.vapic_vaddr) - - le32_to_cpu(s->rom_state.vaddr); - - return 0; -} - -/* - * Tries to read the unique processor number from the Kernel Processor Control - * Region (KPCR) of 32-bit Windows XP and Server 2003. Returns -1 if the KPCR - * cannot be accessed or is considered invalid. This also ensures that we are - * not patching the wrong guest. - */ -static int get_kpcr_number(CPUX86State *env) -{ - struct kpcr { - uint8_t fill1[0x1c]; - uint32_t self; - uint8_t fill2[0x31]; - uint8_t number; - } QEMU_PACKED kpcr; - - if (cpu_memory_rw_debug(env, env->segs[R_FS].base, - (void *)&kpcr, sizeof(kpcr), 0) < 0 || - kpcr.self != env->segs[R_FS].base) { - return -1; - } - return kpcr.number; -} - -static int vapic_enable(VAPICROMState *s, CPUX86State *env) -{ - int cpu_number = get_kpcr_number(env); - hwaddr vapic_paddr; - static const uint8_t enabled = 1; - - if (cpu_number < 0) { - return -1; - } - vapic_paddr = s->vapic_paddr + - (((hwaddr)cpu_number) << VAPIC_CPU_SHIFT); - cpu_physical_memory_rw(vapic_paddr + offsetof(VAPICState, enabled), - (void *)&enabled, sizeof(enabled), 1); - apic_enable_vapic(env->apic_state, vapic_paddr); - - s->state = VAPIC_ACTIVE; - - return 0; -} - -static void patch_byte(CPUX86State *env, target_ulong addr, uint8_t byte) -{ - cpu_memory_rw_debug(env, addr, &byte, 1, 1); -} - -static void patch_call(VAPICROMState *s, CPUX86State *env, target_ulong ip, - uint32_t target) -{ - uint32_t offset; - - offset = cpu_to_le32(target - ip - 5); - patch_byte(env, ip, 0xe8); /* call near */ - cpu_memory_rw_debug(env, ip + 1, (void *)&offset, sizeof(offset), 1); -} - -static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) -{ - CPUState *cs = CPU(cpu); - CPUX86State *env = &cpu->env; - VAPICHandlers *handlers; - uint8_t opcode[2]; - uint32_t imm32; - target_ulong current_pc = 0; - target_ulong current_cs_base = 0; - int current_flags = 0; - - if (smp_cpus == 1) { - handlers = &s->rom_state.up; - } else { - handlers = &s->rom_state.mp; - } - - if (!kvm_enabled()) { - cpu_restore_state(env, env->mem_io_pc); - cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, - ¤t_flags); - } - - pause_all_vcpus(); - - cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0); - - switch (opcode[0]) { - case 0x89: /* mov r32 to r/m32 */ - patch_byte(env, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */ - patch_call(s, env, ip + 1, handlers->set_tpr); - break; - case 0x8b: /* mov r/m32 to r32 */ - patch_byte(env, ip, 0x90); - patch_call(s, env, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]); - break; - case 0xa1: /* mov abs to eax */ - patch_call(s, env, ip, handlers->get_tpr[0]); - break; - case 0xa3: /* mov eax to abs */ - patch_call(s, env, ip, handlers->set_tpr_eax); - break; - case 0xc7: /* mov imm32, r/m32 (c7/0) */ - patch_byte(env, ip, 0x68); /* push imm32 */ - cpu_memory_rw_debug(env, ip + 6, (void *)&imm32, sizeof(imm32), 0); - cpu_memory_rw_debug(env, ip + 1, (void *)&imm32, sizeof(imm32), 1); - patch_call(s, env, ip + 5, handlers->set_tpr); - break; - case 0xff: /* push r/m32 */ - patch_byte(env, ip, 0x50); /* push eax */ - patch_call(s, env, ip + 1, handlers->get_tpr_stack); - break; - default: - abort(); - } - - resume_all_vcpus(); - - if (!kvm_enabled()) { - cs->current_tb = NULL; - tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); - cpu_resume_from_signal(env, NULL); - } -} - -void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip, - TPRAccess access) -{ - VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev); - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - - cpu_synchronize_state(env); - - if (evaluate_tpr_instruction(s, env, &ip, access) < 0) { - if (s->state == VAPIC_ACTIVE) { - vapic_enable(s, env); - } - return; - } - if (update_rom_mapping(s, env, ip) < 0) { - return; - } - if (vapic_enable(s, env) < 0) { - return; - } - patch_instruction(s, cpu, ip); -} - -typedef struct VAPICEnableTPRReporting { - DeviceState *apic; - bool enable; -} VAPICEnableTPRReporting; - -static void vapic_do_enable_tpr_reporting(void *data) -{ - VAPICEnableTPRReporting *info = data; - - apic_enable_tpr_access_reporting(info->apic, info->enable); -} - -static void vapic_enable_tpr_reporting(bool enable) -{ - VAPICEnableTPRReporting info = { - .enable = enable, - }; - X86CPU *cpu; - CPUX86State *env; - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = x86_env_get_cpu(env); - info.apic = env->apic_state; - run_on_cpu(CPU(cpu), vapic_do_enable_tpr_reporting, &info); - } -} - -static void vapic_reset(DeviceState *dev) -{ - VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev); - - if (s->state == VAPIC_ACTIVE) { - s->state = VAPIC_STANDBY; - } - vapic_enable_tpr_reporting(false); -} - -/* - * Set the IRQ polling hypercalls to the supported variant: - * - vmcall if using KVM in-kernel irqchip - * - 32-bit VAPIC port write otherwise - */ -static int patch_hypercalls(VAPICROMState *s) -{ - hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; - static const uint8_t vmcall_pattern[] = { /* vmcall */ - 0xb8, 0x1, 0, 0, 0, 0xf, 0x1, 0xc1 - }; - static const uint8_t outl_pattern[] = { /* nop; outl %eax,0x7e */ - 0xb8, 0x1, 0, 0, 0, 0x90, 0xe7, 0x7e - }; - uint8_t alternates[2]; - const uint8_t *pattern; - const uint8_t *patch; - int patches = 0; - off_t pos; - uint8_t *rom; - - rom = g_malloc(s->rom_size); - cpu_physical_memory_rw(rom_paddr, rom, s->rom_size, 0); - - for (pos = 0; pos < s->rom_size - sizeof(vmcall_pattern); pos++) { - if (kvm_irqchip_in_kernel()) { - pattern = outl_pattern; - alternates[0] = outl_pattern[7]; - alternates[1] = outl_pattern[7]; - patch = &vmcall_pattern[5]; - } else { - pattern = vmcall_pattern; - alternates[0] = vmcall_pattern[7]; - alternates[1] = 0xd9; /* AMD's VMMCALL */ - patch = &outl_pattern[5]; - } - if (memcmp(rom + pos, pattern, 7) == 0 && - (rom[pos + 7] == alternates[0] || rom[pos + 7] == alternates[1])) { - cpu_physical_memory_rw(rom_paddr + pos + 5, (uint8_t *)patch, - 3, 1); - /* - * Don't flush the tb here. Under ordinary conditions, the patched - * calls are miles away from the current IP. Under malicious - * conditions, the guest could trick us to crash. - */ - } - } - - g_free(rom); - - if (patches != 0 && patches != 2) { - return -1; - } - - return 0; -} - -/* - * For TCG mode or the time KVM honors read-only memory regions, we need to - * enable write access to the option ROM so that variables can be updated by - * the guest. - */ -static void vapic_map_rom_writable(VAPICROMState *s) -{ - hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; - MemoryRegionSection section; - MemoryRegion *as; - size_t rom_size; - uint8_t *ram; - - as = sysbus_address_space(&s->busdev); - - if (s->rom_mapped_writable) { - memory_region_del_subregion(as, &s->rom); - memory_region_destroy(&s->rom); - } - - /* grab RAM memory region (region @rom_paddr may still be pc.rom) */ - section = memory_region_find(as, 0, 1); - - /* read ROM size from RAM region */ - ram = memory_region_get_ram_ptr(section.mr); - rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE; - s->rom_size = rom_size; - - /* We need to round to avoid creating subpages - * from which we cannot run code. */ - rom_size += rom_paddr & ~TARGET_PAGE_MASK; - rom_paddr &= TARGET_PAGE_MASK; - rom_size = TARGET_PAGE_ALIGN(rom_size); - - memory_region_init_alias(&s->rom, "kvmvapic-rom", section.mr, rom_paddr, - rom_size); - memory_region_add_subregion_overlap(as, rom_paddr, &s->rom, 1000); - s->rom_mapped_writable = true; -} - -static int vapic_prepare(VAPICROMState *s) -{ - vapic_map_rom_writable(s); - - if (patch_hypercalls(s) < 0) { - return -1; - } - - vapic_enable_tpr_reporting(true); - - return 0; -} - -static void vapic_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - CPUX86State *env = cpu_single_env; - hwaddr rom_paddr; - VAPICROMState *s = opaque; - - cpu_synchronize_state(env); - - /* - * The VAPIC supports two PIO-based hypercalls, both via port 0x7E. - * o 16-bit write access: - * Reports the option ROM initialization to the hypervisor. Written - * value is the offset of the state structure in the ROM. - * o 8-bit write access: - * Reactivates the VAPIC after a guest hibernation, i.e. after the - * option ROM content has been re-initialized by a guest power cycle. - * o 32-bit write access: - * Poll for pending IRQs, considering the current VAPIC state. - */ - switch (size) { - case 2: - if (s->state == VAPIC_INACTIVE) { - rom_paddr = (env->segs[R_CS].base + env->eip) & ROM_BLOCK_MASK; - s->rom_state_paddr = rom_paddr + data; - - s->state = VAPIC_STANDBY; - } - if (vapic_prepare(s) < 0) { - s->state = VAPIC_INACTIVE; - break; - } - break; - case 1: - if (kvm_enabled()) { - /* - * Disable triggering instruction in ROM by writing a NOP. - * - * We cannot do this in TCG mode as the reported IP is not - * accurate. - */ - pause_all_vcpus(); - patch_byte(env, env->eip - 2, 0x66); - patch_byte(env, env->eip - 1, 0x90); - resume_all_vcpus(); - } - - if (s->state == VAPIC_ACTIVE) { - break; - } - if (update_rom_mapping(s, env, env->eip) < 0) { - break; - } - if (find_real_tpr_addr(s, env) < 0) { - break; - } - vapic_enable(s, env); - break; - default: - case 4: - if (!kvm_irqchip_in_kernel()) { - apic_poll_irq(env->apic_state); - } - break; - } -} - -static const MemoryRegionOps vapic_ops = { - .write = vapic_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int vapic_init(SysBusDevice *dev) -{ - VAPICROMState *s = FROM_SYSBUS(VAPICROMState, dev); - - memory_region_init_io(&s->io, &vapic_ops, s, "kvmvapic", 2); - sysbus_add_io(dev, VAPIC_IO_PORT, &s->io); - sysbus_init_ioports(dev, VAPIC_IO_PORT, 2); - - option_rom[nb_option_roms].name = "kvmvapic.bin"; - option_rom[nb_option_roms].bootindex = -1; - nb_option_roms++; - - return 0; -} - -static void do_vapic_enable(void *data) -{ - VAPICROMState *s = data; - - vapic_enable(s, first_cpu); -} - -static int vapic_post_load(void *opaque, int version_id) -{ - VAPICROMState *s = opaque; - uint8_t *zero; - - /* - * The old implementation of qemu-kvm did not provide the state - * VAPIC_STANDBY. Reconstruct it. - */ - if (s->state == VAPIC_INACTIVE && s->rom_state_paddr != 0) { - s->state = VAPIC_STANDBY; - } - - if (s->state != VAPIC_INACTIVE) { - if (vapic_prepare(s) < 0) { - return -1; - } - } - if (s->state == VAPIC_ACTIVE) { - if (smp_cpus == 1) { - run_on_cpu(ENV_GET_CPU(first_cpu), do_vapic_enable, s); - } else { - zero = g_malloc0(s->rom_state.vapic_size); - cpu_physical_memory_rw(s->vapic_paddr, zero, - s->rom_state.vapic_size, 1); - g_free(zero); - } - } - - return 0; -} - -static const VMStateDescription vmstate_handlers = { - .name = "kvmvapic-handlers", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(set_tpr, VAPICHandlers), - VMSTATE_UINT32(set_tpr_eax, VAPICHandlers), - VMSTATE_UINT32_ARRAY(get_tpr, VAPICHandlers, 8), - VMSTATE_UINT32(get_tpr_stack, VAPICHandlers), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_guest_rom = { - .name = "kvmvapic-guest-rom", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UNUSED(8), /* signature */ - VMSTATE_UINT32(vaddr, GuestROMState), - VMSTATE_UINT32(fixup_start, GuestROMState), - VMSTATE_UINT32(fixup_end, GuestROMState), - VMSTATE_UINT32(vapic_vaddr, GuestROMState), - VMSTATE_UINT32(vapic_size, GuestROMState), - VMSTATE_UINT32(vcpu_shift, GuestROMState), - VMSTATE_UINT32(real_tpr_addr, GuestROMState), - VMSTATE_STRUCT(up, GuestROMState, 0, vmstate_handlers, VAPICHandlers), - VMSTATE_STRUCT(mp, GuestROMState, 0, vmstate_handlers, VAPICHandlers), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_vapic = { - .name = "kvm-tpr-opt", /* compatible with qemu-kvm VAPIC */ - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .post_load = vapic_post_load, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(rom_state, VAPICROMState, 0, vmstate_guest_rom, - GuestROMState), - VMSTATE_UINT32(state, VAPICROMState), - VMSTATE_UINT32(real_tpr_addr, VAPICROMState), - VMSTATE_UINT32(rom_state_vaddr, VAPICROMState), - VMSTATE_UINT32(vapic_paddr, VAPICROMState), - VMSTATE_UINT32(rom_state_paddr, VAPICROMState), - VMSTATE_END_OF_LIST() - } -}; - -static void vapic_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->no_user = 1; - dc->reset = vapic_reset; - dc->vmsd = &vmstate_vapic; - sc->init = vapic_init; -} - -static const TypeInfo vapic_type = { - .name = "kvmvapic", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(VAPICROMState), - .class_init = vapic_class_init, -}; - -static void vapic_register(void) -{ - type_register_static(&vapic_type); -} - -type_init(vapic_register); -- cgit v1.2.3 From 9743b581a819a05668e6a1f60e3ee6486d25f141 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: m68k: move files referencing CPU to hw/m68k/ Signed-off-by: Paolo Bonzini --- hw/m68k/Makefile.objs | 3 +- hw/m68k/mcf5206.c | 548 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/m68k/mcf_intc.c | 154 ++++++++++++++ hw/mcf5206.c | 548 -------------------------------------------------- hw/mcf_intc.c | 154 -------------- 5 files changed, 704 insertions(+), 703 deletions(-) create mode 100644 hw/m68k/mcf5206.c create mode 100644 hw/m68k/mcf_intc.c delete mode 100644 hw/mcf5206.c delete mode 100644 hw/mcf_intc.c diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs index 7c033a886c..ede32a7c4e 100644 --- a/hw/m68k/Makefile.objs +++ b/hw/m68k/Makefile.objs @@ -1,7 +1,8 @@ -obj-y = mcf5206.o mcf_uart.o mcf_intc.o mcf_fec.o +obj-y = mcf_uart.o mcf_fec.o obj-y := $(addprefix ../,$(obj-y)) obj-y += an5206.o mcf5208.o obj-y += dummy_m68k.o +obj-y += mcf5206.o mcf_intc.o diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c new file mode 100644 index 0000000000..58cd8d46c9 --- /dev/null +++ b/hw/m68k/mcf5206.c @@ -0,0 +1,548 @@ +/* + * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ +#include "hw/hw.h" +#include "hw/mcf.h" +#include "qemu/timer.h" +#include "hw/ptimer.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" + +/* General purpose timer module. */ +typedef struct { + uint16_t tmr; + uint16_t trr; + uint16_t tcr; + uint16_t ter; + ptimer_state *timer; + qemu_irq irq; + int irq_state; +} m5206_timer_state; + +#define TMR_RST 0x01 +#define TMR_CLK 0x06 +#define TMR_FRR 0x08 +#define TMR_ORI 0x10 +#define TMR_OM 0x20 +#define TMR_CE 0xc0 + +#define TER_CAP 0x01 +#define TER_REF 0x02 + +static void m5206_timer_update(m5206_timer_state *s) +{ + if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF)) + qemu_irq_raise(s->irq); + else + qemu_irq_lower(s->irq); +} + +static void m5206_timer_reset(m5206_timer_state *s) +{ + s->tmr = 0; + s->trr = 0; +} + +static void m5206_timer_recalibrate(m5206_timer_state *s) +{ + int prescale; + int mode; + + ptimer_stop(s->timer); + + if ((s->tmr & TMR_RST) == 0) + return; + + prescale = (s->tmr >> 8) + 1; + mode = (s->tmr >> 1) & 3; + if (mode == 2) + prescale *= 16; + + if (mode == 3 || mode == 0) + hw_error("m5206_timer: mode %d not implemented\n", mode); + if ((s->tmr & TMR_FRR) == 0) + hw_error("m5206_timer: free running mode not implemented\n"); + + /* Assume 66MHz system clock. */ + ptimer_set_freq(s->timer, 66000000 / prescale); + + ptimer_set_limit(s->timer, s->trr, 0); + + ptimer_run(s->timer, 0); +} + +static void m5206_timer_trigger(void *opaque) +{ + m5206_timer_state *s = (m5206_timer_state *)opaque; + s->ter |= TER_REF; + m5206_timer_update(s); +} + +static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr) +{ + switch (addr) { + case 0: + return s->tmr; + case 4: + return s->trr; + case 8: + return s->tcr; + case 0xc: + return s->trr - ptimer_get_count(s->timer); + case 0x11: + return s->ter; + default: + return 0; + } +} + +static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) +{ + switch (addr) { + case 0: + if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) { + m5206_timer_reset(s); + } + s->tmr = val; + m5206_timer_recalibrate(s); + break; + case 4: + s->trr = val; + m5206_timer_recalibrate(s); + break; + case 8: + s->tcr = val; + break; + case 0xc: + ptimer_set_count(s->timer, val); + break; + case 0x11: + s->ter &= ~val; + break; + default: + break; + } + m5206_timer_update(s); +} + +static m5206_timer_state *m5206_timer_init(qemu_irq irq) +{ + m5206_timer_state *s; + QEMUBH *bh; + + s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state)); + bh = qemu_bh_new(m5206_timer_trigger, s); + s->timer = ptimer_init(bh); + s->irq = irq; + m5206_timer_reset(s); + return s; +} + +/* System Integration Module. */ + +typedef struct { + M68kCPU *cpu; + MemoryRegion iomem; + m5206_timer_state *timer[2]; + void *uart[2]; + uint8_t scr; + uint8_t icr[14]; + uint16_t imr; /* 1 == interrupt is masked. */ + uint16_t ipr; + uint8_t rsr; + uint8_t swivr; + uint8_t par; + /* Include the UART vector registers here. */ + uint8_t uivr[2]; +} m5206_mbar_state; + +/* Interrupt controller. */ + +static int m5206_find_pending_irq(m5206_mbar_state *s) +{ + int level; + int vector; + uint16_t active; + int i; + + level = 0; + vector = 0; + active = s->ipr & ~s->imr; + if (!active) + return 0; + + for (i = 1; i < 14; i++) { + if (active & (1 << i)) { + if ((s->icr[i] & 0x1f) > level) { + level = s->icr[i] & 0x1f; + vector = i; + } + } + } + + if (level < 4) + vector = 0; + + return vector; +} + +static void m5206_mbar_update(m5206_mbar_state *s) +{ + int irq; + int vector; + int level; + + irq = m5206_find_pending_irq(s); + if (irq) { + int tmp; + tmp = s->icr[irq]; + level = (tmp >> 2) & 7; + if (tmp & 0x80) { + /* Autovector. */ + vector = 24 + level; + } else { + switch (irq) { + case 8: /* SWT */ + vector = s->swivr; + break; + case 12: /* UART1 */ + vector = s->uivr[0]; + break; + case 13: /* UART2 */ + vector = s->uivr[1]; + break; + default: + /* Unknown vector. */ + fprintf(stderr, "Unhandled vector for IRQ %d\n", irq); + vector = 0xf; + break; + } + } + } else { + level = 0; + vector = 0; + } + m68k_set_irq_level(s->cpu, level, vector); +} + +static void m5206_mbar_set_irq(void *opaque, int irq, int level) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + if (level) { + s->ipr |= 1 << irq; + } else { + s->ipr &= ~(1 << irq); + } + m5206_mbar_update(s); +} + +/* System Integration Module. */ + +static void m5206_mbar_reset(m5206_mbar_state *s) +{ + s->scr = 0xc0; + s->icr[1] = 0x04; + s->icr[2] = 0x08; + s->icr[3] = 0x0c; + s->icr[4] = 0x10; + s->icr[5] = 0x14; + s->icr[6] = 0x18; + s->icr[7] = 0x1c; + s->icr[8] = 0x1c; + s->icr[9] = 0x80; + s->icr[10] = 0x80; + s->icr[11] = 0x80; + s->icr[12] = 0x00; + s->icr[13] = 0x00; + s->imr = 0x3ffe; + s->rsr = 0x80; + s->swivr = 0x0f; + s->par = 0; +} + +static uint64_t m5206_mbar_read(m5206_mbar_state *s, + uint64_t offset, unsigned size) +{ + if (offset >= 0x100 && offset < 0x120) { + return m5206_timer_read(s->timer[0], offset - 0x100); + } else if (offset >= 0x120 && offset < 0x140) { + return m5206_timer_read(s->timer[1], offset - 0x120); + } else if (offset >= 0x140 && offset < 0x160) { + return mcf_uart_read(s->uart[0], offset - 0x140, size); + } else if (offset >= 0x180 && offset < 0x1a0) { + return mcf_uart_read(s->uart[1], offset - 0x180, size); + } + switch (offset) { + case 0x03: return s->scr; + case 0x14 ... 0x20: return s->icr[offset - 0x13]; + case 0x36: return s->imr; + case 0x3a: return s->ipr; + case 0x40: return s->rsr; + case 0x41: return 0; + case 0x42: return s->swivr; + case 0x50: + /* DRAM mask register. */ + /* FIXME: currently hardcoded to 128Mb. */ + { + uint32_t mask = ~0; + while (mask > ram_size) + mask >>= 1; + return mask & 0x0ffe0000; + } + case 0x5c: return 1; /* DRAM bank 1 empty. */ + case 0xcb: return s->par; + case 0x170: return s->uivr[0]; + case 0x1b0: return s->uivr[1]; + } + hw_error("Bad MBAR read offset 0x%x", (int)offset); + return 0; +} + +static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, + uint64_t value, unsigned size) +{ + if (offset >= 0x100 && offset < 0x120) { + m5206_timer_write(s->timer[0], offset - 0x100, value); + return; + } else if (offset >= 0x120 && offset < 0x140) { + m5206_timer_write(s->timer[1], offset - 0x120, value); + return; + } else if (offset >= 0x140 && offset < 0x160) { + mcf_uart_write(s->uart[0], offset - 0x140, value, size); + return; + } else if (offset >= 0x180 && offset < 0x1a0) { + mcf_uart_write(s->uart[1], offset - 0x180, value, size); + return; + } + switch (offset) { + case 0x03: + s->scr = value; + break; + case 0x14 ... 0x20: + s->icr[offset - 0x13] = value; + m5206_mbar_update(s); + break; + case 0x36: + s->imr = value; + m5206_mbar_update(s); + break; + case 0x40: + s->rsr &= ~value; + break; + case 0x41: + /* TODO: implement watchdog. */ + break; + case 0x42: + s->swivr = value; + break; + case 0xcb: + s->par = value; + break; + case 0x170: + s->uivr[0] = value; + break; + case 0x178: case 0x17c: case 0x1c8: case 0x1bc: + /* Not implemented: UART Output port bits. */ + break; + case 0x1b0: + s->uivr[1] = value; + break; + default: + hw_error("Bad MBAR write offset 0x%x", (int)offset); + break; + } +} + +/* Internal peripherals use a variety of register widths. + This lookup table allows a single routine to handle all of them. */ +static const uint8_t m5206_mbar_width[] = +{ + /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, + /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, + /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, + /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset); +static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset); + +static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + if (m5206_mbar_width[offset >> 2] > 1) { + uint16_t val; + val = m5206_mbar_readw(opaque, offset & ~1); + if ((offset & 1) == 0) { + val >>= 8; + } + return val & 0xff; + } + return m5206_mbar_read(s, offset, 1); +} + +static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 2) { + uint32_t val; + val = m5206_mbar_readl(opaque, offset & ~3); + if ((offset & 3) == 0) + val >>= 16; + return val & 0xffff; + } else if (width < 2) { + uint16_t val; + val = m5206_mbar_readb(opaque, offset) << 8; + val |= m5206_mbar_readb(opaque, offset + 1); + return val; + } + return m5206_mbar_read(s, offset, 2); +} + +static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width < 4) { + uint32_t val; + val = m5206_mbar_readw(opaque, offset) << 16; + val |= m5206_mbar_readw(opaque, offset + 2); + return val; + } + return m5206_mbar_read(s, offset, 4); +} + +static void m5206_mbar_writew(void *opaque, hwaddr offset, + uint32_t value); +static void m5206_mbar_writel(void *opaque, hwaddr offset, + uint32_t value); + +static void m5206_mbar_writeb(void *opaque, hwaddr offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 1) { + uint32_t tmp; + tmp = m5206_mbar_readw(opaque, offset & ~1); + if (offset & 1) { + tmp = (tmp & 0xff00) | value; + } else { + tmp = (tmp & 0x00ff) | (value << 8); + } + m5206_mbar_writew(opaque, offset & ~1, tmp); + return; + } + m5206_mbar_write(s, offset, value, 1); +} + +static void m5206_mbar_writew(void *opaque, hwaddr offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 2) { + uint32_t tmp; + tmp = m5206_mbar_readl(opaque, offset & ~3); + if (offset & 3) { + tmp = (tmp & 0xffff0000) | value; + } else { + tmp = (tmp & 0x0000ffff) | (value << 16); + } + m5206_mbar_writel(opaque, offset & ~3, tmp); + return; + } else if (width < 2) { + m5206_mbar_writeb(opaque, offset, value >> 8); + m5206_mbar_writeb(opaque, offset + 1, value & 0xff); + return; + } + m5206_mbar_write(s, offset, value, 2); +} + +static void m5206_mbar_writel(void *opaque, hwaddr offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width < 4) { + m5206_mbar_writew(opaque, offset, value >> 16); + m5206_mbar_writew(opaque, offset + 2, value & 0xffff); + return; + } + m5206_mbar_write(s, offset, value, 4); +} + +static const MemoryRegionOps m5206_mbar_ops = { + .old_mmio = { + .read = { + m5206_mbar_readb, + m5206_mbar_readw, + m5206_mbar_readl, + }, + .write = { + m5206_mbar_writeb, + m5206_mbar_writew, + m5206_mbar_writel, + }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, M68kCPU *cpu) +{ + m5206_mbar_state *s; + qemu_irq *pic; + + s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state)); + + memory_region_init_io(&s->iomem, &m5206_mbar_ops, s, + "mbar", 0x00001000); + memory_region_add_subregion(sysmem, base, &s->iomem); + + pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); + s->timer[0] = m5206_timer_init(pic[9]); + s->timer[1] = m5206_timer_init(pic[10]); + s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); + s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); + s->cpu = cpu; + + m5206_mbar_reset(s); + return pic; +} diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c new file mode 100644 index 0000000000..fff27b34aa --- /dev/null +++ b/hw/m68k/mcf_intc.c @@ -0,0 +1,154 @@ +/* + * ColdFire Interrupt Controller emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ +#include "hw/hw.h" +#include "hw/mcf.h" +#include "exec/address-spaces.h" + +typedef struct { + MemoryRegion iomem; + uint64_t ipr; + uint64_t imr; + uint64_t ifr; + uint64_t enabled; + uint8_t icr[64]; + M68kCPU *cpu; + int active_vector; +} mcf_intc_state; + +static void mcf_intc_update(mcf_intc_state *s) +{ + uint64_t active; + int i; + int best; + int best_level; + + active = (s->ipr | s->ifr) & s->enabled & ~s->imr; + best_level = 0; + best = 64; + if (active) { + for (i = 0; i < 64; i++) { + if ((active & 1) != 0 && s->icr[i] >= best_level) { + best_level = s->icr[i]; + best = i; + } + active >>= 1; + } + } + s->active_vector = ((best == 64) ? 24 : (best + 64)); + m68k_set_irq_level(s->cpu, best_level, s->active_vector); +} + +static uint64_t mcf_intc_read(void *opaque, hwaddr addr, + unsigned size) +{ + int offset; + mcf_intc_state *s = (mcf_intc_state *)opaque; + offset = addr & 0xff; + if (offset >= 0x40 && offset < 0x80) { + return s->icr[offset - 0x40]; + } + switch (offset) { + case 0x00: + return (uint32_t)(s->ipr >> 32); + case 0x04: + return (uint32_t)s->ipr; + case 0x08: + return (uint32_t)(s->imr >> 32); + case 0x0c: + return (uint32_t)s->imr; + case 0x10: + return (uint32_t)(s->ifr >> 32); + case 0x14: + return (uint32_t)s->ifr; + case 0xe0: /* SWIACK. */ + return s->active_vector; + case 0xe1: case 0xe2: case 0xe3: case 0xe4: + case 0xe5: case 0xe6: case 0xe7: + /* LnIACK */ + hw_error("mcf_intc_read: LnIACK not implemented\n"); + default: + return 0; + } +} + +static void mcf_intc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + int offset; + mcf_intc_state *s = (mcf_intc_state *)opaque; + offset = addr & 0xff; + if (offset >= 0x40 && offset < 0x80) { + int n = offset - 0x40; + s->icr[n] = val; + if (val == 0) + s->enabled &= ~(1ull << n); + else + s->enabled |= (1ull << n); + mcf_intc_update(s); + return; + } + switch (offset) { + case 0x00: case 0x04: + /* Ignore IPR writes. */ + return; + case 0x08: + s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32); + break; + case 0x0c: + s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val; + break; + default: + hw_error("mcf_intc_write: Bad write offset %d\n", offset); + break; + } + mcf_intc_update(s); +} + +static void mcf_intc_set_irq(void *opaque, int irq, int level) +{ + mcf_intc_state *s = (mcf_intc_state *)opaque; + if (irq >= 64) + return; + if (level) + s->ipr |= 1ull << irq; + else + s->ipr &= ~(1ull << irq); + mcf_intc_update(s); +} + +static void mcf_intc_reset(mcf_intc_state *s) +{ + s->imr = ~0ull; + s->ipr = 0; + s->ifr = 0; + s->enabled = 0; + memset(s->icr, 0, 64); + s->active_vector = 24; +} + +static const MemoryRegionOps mcf_intc_ops = { + .read = mcf_intc_read, + .write = mcf_intc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +qemu_irq *mcf_intc_init(MemoryRegion *sysmem, + hwaddr base, + M68kCPU *cpu) +{ + mcf_intc_state *s; + + s = g_malloc0(sizeof(mcf_intc_state)); + s->cpu = cpu; + mcf_intc_reset(s); + + memory_region_init_io(&s->iomem, &mcf_intc_ops, s, "mcf", 0x100); + memory_region_add_subregion(sysmem, base, &s->iomem); + + return qemu_allocate_irqs(mcf_intc_set_irq, s, 64); +} diff --git a/hw/mcf5206.c b/hw/mcf5206.c deleted file mode 100644 index 58cd8d46c9..0000000000 --- a/hw/mcf5206.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ -#include "hw/hw.h" -#include "hw/mcf.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "sysemu/sysemu.h" -#include "exec/address-spaces.h" - -/* General purpose timer module. */ -typedef struct { - uint16_t tmr; - uint16_t trr; - uint16_t tcr; - uint16_t ter; - ptimer_state *timer; - qemu_irq irq; - int irq_state; -} m5206_timer_state; - -#define TMR_RST 0x01 -#define TMR_CLK 0x06 -#define TMR_FRR 0x08 -#define TMR_ORI 0x10 -#define TMR_OM 0x20 -#define TMR_CE 0xc0 - -#define TER_CAP 0x01 -#define TER_REF 0x02 - -static void m5206_timer_update(m5206_timer_state *s) -{ - if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF)) - qemu_irq_raise(s->irq); - else - qemu_irq_lower(s->irq); -} - -static void m5206_timer_reset(m5206_timer_state *s) -{ - s->tmr = 0; - s->trr = 0; -} - -static void m5206_timer_recalibrate(m5206_timer_state *s) -{ - int prescale; - int mode; - - ptimer_stop(s->timer); - - if ((s->tmr & TMR_RST) == 0) - return; - - prescale = (s->tmr >> 8) + 1; - mode = (s->tmr >> 1) & 3; - if (mode == 2) - prescale *= 16; - - if (mode == 3 || mode == 0) - hw_error("m5206_timer: mode %d not implemented\n", mode); - if ((s->tmr & TMR_FRR) == 0) - hw_error("m5206_timer: free running mode not implemented\n"); - - /* Assume 66MHz system clock. */ - ptimer_set_freq(s->timer, 66000000 / prescale); - - ptimer_set_limit(s->timer, s->trr, 0); - - ptimer_run(s->timer, 0); -} - -static void m5206_timer_trigger(void *opaque) -{ - m5206_timer_state *s = (m5206_timer_state *)opaque; - s->ter |= TER_REF; - m5206_timer_update(s); -} - -static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr) -{ - switch (addr) { - case 0: - return s->tmr; - case 4: - return s->trr; - case 8: - return s->tcr; - case 0xc: - return s->trr - ptimer_get_count(s->timer); - case 0x11: - return s->ter; - default: - return 0; - } -} - -static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0: - if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) { - m5206_timer_reset(s); - } - s->tmr = val; - m5206_timer_recalibrate(s); - break; - case 4: - s->trr = val; - m5206_timer_recalibrate(s); - break; - case 8: - s->tcr = val; - break; - case 0xc: - ptimer_set_count(s->timer, val); - break; - case 0x11: - s->ter &= ~val; - break; - default: - break; - } - m5206_timer_update(s); -} - -static m5206_timer_state *m5206_timer_init(qemu_irq irq) -{ - m5206_timer_state *s; - QEMUBH *bh; - - s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state)); - bh = qemu_bh_new(m5206_timer_trigger, s); - s->timer = ptimer_init(bh); - s->irq = irq; - m5206_timer_reset(s); - return s; -} - -/* System Integration Module. */ - -typedef struct { - M68kCPU *cpu; - MemoryRegion iomem; - m5206_timer_state *timer[2]; - void *uart[2]; - uint8_t scr; - uint8_t icr[14]; - uint16_t imr; /* 1 == interrupt is masked. */ - uint16_t ipr; - uint8_t rsr; - uint8_t swivr; - uint8_t par; - /* Include the UART vector registers here. */ - uint8_t uivr[2]; -} m5206_mbar_state; - -/* Interrupt controller. */ - -static int m5206_find_pending_irq(m5206_mbar_state *s) -{ - int level; - int vector; - uint16_t active; - int i; - - level = 0; - vector = 0; - active = s->ipr & ~s->imr; - if (!active) - return 0; - - for (i = 1; i < 14; i++) { - if (active & (1 << i)) { - if ((s->icr[i] & 0x1f) > level) { - level = s->icr[i] & 0x1f; - vector = i; - } - } - } - - if (level < 4) - vector = 0; - - return vector; -} - -static void m5206_mbar_update(m5206_mbar_state *s) -{ - int irq; - int vector; - int level; - - irq = m5206_find_pending_irq(s); - if (irq) { - int tmp; - tmp = s->icr[irq]; - level = (tmp >> 2) & 7; - if (tmp & 0x80) { - /* Autovector. */ - vector = 24 + level; - } else { - switch (irq) { - case 8: /* SWT */ - vector = s->swivr; - break; - case 12: /* UART1 */ - vector = s->uivr[0]; - break; - case 13: /* UART2 */ - vector = s->uivr[1]; - break; - default: - /* Unknown vector. */ - fprintf(stderr, "Unhandled vector for IRQ %d\n", irq); - vector = 0xf; - break; - } - } - } else { - level = 0; - vector = 0; - } - m68k_set_irq_level(s->cpu, level, vector); -} - -static void m5206_mbar_set_irq(void *opaque, int irq, int level) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - if (level) { - s->ipr |= 1 << irq; - } else { - s->ipr &= ~(1 << irq); - } - m5206_mbar_update(s); -} - -/* System Integration Module. */ - -static void m5206_mbar_reset(m5206_mbar_state *s) -{ - s->scr = 0xc0; - s->icr[1] = 0x04; - s->icr[2] = 0x08; - s->icr[3] = 0x0c; - s->icr[4] = 0x10; - s->icr[5] = 0x14; - s->icr[6] = 0x18; - s->icr[7] = 0x1c; - s->icr[8] = 0x1c; - s->icr[9] = 0x80; - s->icr[10] = 0x80; - s->icr[11] = 0x80; - s->icr[12] = 0x00; - s->icr[13] = 0x00; - s->imr = 0x3ffe; - s->rsr = 0x80; - s->swivr = 0x0f; - s->par = 0; -} - -static uint64_t m5206_mbar_read(m5206_mbar_state *s, - uint64_t offset, unsigned size) -{ - if (offset >= 0x100 && offset < 0x120) { - return m5206_timer_read(s->timer[0], offset - 0x100); - } else if (offset >= 0x120 && offset < 0x140) { - return m5206_timer_read(s->timer[1], offset - 0x120); - } else if (offset >= 0x140 && offset < 0x160) { - return mcf_uart_read(s->uart[0], offset - 0x140, size); - } else if (offset >= 0x180 && offset < 0x1a0) { - return mcf_uart_read(s->uart[1], offset - 0x180, size); - } - switch (offset) { - case 0x03: return s->scr; - case 0x14 ... 0x20: return s->icr[offset - 0x13]; - case 0x36: return s->imr; - case 0x3a: return s->ipr; - case 0x40: return s->rsr; - case 0x41: return 0; - case 0x42: return s->swivr; - case 0x50: - /* DRAM mask register. */ - /* FIXME: currently hardcoded to 128Mb. */ - { - uint32_t mask = ~0; - while (mask > ram_size) - mask >>= 1; - return mask & 0x0ffe0000; - } - case 0x5c: return 1; /* DRAM bank 1 empty. */ - case 0xcb: return s->par; - case 0x170: return s->uivr[0]; - case 0x1b0: return s->uivr[1]; - } - hw_error("Bad MBAR read offset 0x%x", (int)offset); - return 0; -} - -static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, - uint64_t value, unsigned size) -{ - if (offset >= 0x100 && offset < 0x120) { - m5206_timer_write(s->timer[0], offset - 0x100, value); - return; - } else if (offset >= 0x120 && offset < 0x140) { - m5206_timer_write(s->timer[1], offset - 0x120, value); - return; - } else if (offset >= 0x140 && offset < 0x160) { - mcf_uart_write(s->uart[0], offset - 0x140, value, size); - return; - } else if (offset >= 0x180 && offset < 0x1a0) { - mcf_uart_write(s->uart[1], offset - 0x180, value, size); - return; - } - switch (offset) { - case 0x03: - s->scr = value; - break; - case 0x14 ... 0x20: - s->icr[offset - 0x13] = value; - m5206_mbar_update(s); - break; - case 0x36: - s->imr = value; - m5206_mbar_update(s); - break; - case 0x40: - s->rsr &= ~value; - break; - case 0x41: - /* TODO: implement watchdog. */ - break; - case 0x42: - s->swivr = value; - break; - case 0xcb: - s->par = value; - break; - case 0x170: - s->uivr[0] = value; - break; - case 0x178: case 0x17c: case 0x1c8: case 0x1bc: - /* Not implemented: UART Output port bits. */ - break; - case 0x1b0: - s->uivr[1] = value; - break; - default: - hw_error("Bad MBAR write offset 0x%x", (int)offset); - break; - } -} - -/* Internal peripherals use a variety of register widths. - This lookup table allows a single routine to handle all of them. */ -static const uint8_t m5206_mbar_width[] = -{ - /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, - /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, - /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, - /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -}; - -static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset); -static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset); - -static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); - } - if (m5206_mbar_width[offset >> 2] > 1) { - uint16_t val; - val = m5206_mbar_readw(opaque, offset & ~1); - if ((offset & 1) == 0) { - val >>= 8; - } - return val & 0xff; - } - return m5206_mbar_read(s, offset, 1); -} - -static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width > 2) { - uint32_t val; - val = m5206_mbar_readl(opaque, offset & ~3); - if ((offset & 3) == 0) - val >>= 16; - return val & 0xffff; - } else if (width < 2) { - uint16_t val; - val = m5206_mbar_readb(opaque, offset) << 8; - val |= m5206_mbar_readb(opaque, offset + 1); - return val; - } - return m5206_mbar_read(s, offset, 2); -} - -static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width < 4) { - uint32_t val; - val = m5206_mbar_readw(opaque, offset) << 16; - val |= m5206_mbar_readw(opaque, offset + 2); - return val; - } - return m5206_mbar_read(s, offset, 4); -} - -static void m5206_mbar_writew(void *opaque, hwaddr offset, - uint32_t value); -static void m5206_mbar_writel(void *opaque, hwaddr offset, - uint32_t value); - -static void m5206_mbar_writeb(void *opaque, hwaddr offset, - uint32_t value) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width > 1) { - uint32_t tmp; - tmp = m5206_mbar_readw(opaque, offset & ~1); - if (offset & 1) { - tmp = (tmp & 0xff00) | value; - } else { - tmp = (tmp & 0x00ff) | (value << 8); - } - m5206_mbar_writew(opaque, offset & ~1, tmp); - return; - } - m5206_mbar_write(s, offset, value, 1); -} - -static void m5206_mbar_writew(void *opaque, hwaddr offset, - uint32_t value) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width > 2) { - uint32_t tmp; - tmp = m5206_mbar_readl(opaque, offset & ~3); - if (offset & 3) { - tmp = (tmp & 0xffff0000) | value; - } else { - tmp = (tmp & 0x0000ffff) | (value << 16); - } - m5206_mbar_writel(opaque, offset & ~3, tmp); - return; - } else if (width < 2) { - m5206_mbar_writeb(opaque, offset, value >> 8); - m5206_mbar_writeb(opaque, offset + 1, value & 0xff); - return; - } - m5206_mbar_write(s, offset, value, 2); -} - -static void m5206_mbar_writel(void *opaque, hwaddr offset, - uint32_t value) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width < 4) { - m5206_mbar_writew(opaque, offset, value >> 16); - m5206_mbar_writew(opaque, offset + 2, value & 0xffff); - return; - } - m5206_mbar_write(s, offset, value, 4); -} - -static const MemoryRegionOps m5206_mbar_ops = { - .old_mmio = { - .read = { - m5206_mbar_readb, - m5206_mbar_readw, - m5206_mbar_readl, - }, - .write = { - m5206_mbar_writeb, - m5206_mbar_writew, - m5206_mbar_writel, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, M68kCPU *cpu) -{ - m5206_mbar_state *s; - qemu_irq *pic; - - s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state)); - - memory_region_init_io(&s->iomem, &m5206_mbar_ops, s, - "mbar", 0x00001000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); - s->timer[0] = m5206_timer_init(pic[9]); - s->timer[1] = m5206_timer_init(pic[10]); - s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); - s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); - s->cpu = cpu; - - m5206_mbar_reset(s); - return pic; -} diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c deleted file mode 100644 index fff27b34aa..0000000000 --- a/hw/mcf_intc.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ColdFire Interrupt Controller emulation. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ -#include "hw/hw.h" -#include "hw/mcf.h" -#include "exec/address-spaces.h" - -typedef struct { - MemoryRegion iomem; - uint64_t ipr; - uint64_t imr; - uint64_t ifr; - uint64_t enabled; - uint8_t icr[64]; - M68kCPU *cpu; - int active_vector; -} mcf_intc_state; - -static void mcf_intc_update(mcf_intc_state *s) -{ - uint64_t active; - int i; - int best; - int best_level; - - active = (s->ipr | s->ifr) & s->enabled & ~s->imr; - best_level = 0; - best = 64; - if (active) { - for (i = 0; i < 64; i++) { - if ((active & 1) != 0 && s->icr[i] >= best_level) { - best_level = s->icr[i]; - best = i; - } - active >>= 1; - } - } - s->active_vector = ((best == 64) ? 24 : (best + 64)); - m68k_set_irq_level(s->cpu, best_level, s->active_vector); -} - -static uint64_t mcf_intc_read(void *opaque, hwaddr addr, - unsigned size) -{ - int offset; - mcf_intc_state *s = (mcf_intc_state *)opaque; - offset = addr & 0xff; - if (offset >= 0x40 && offset < 0x80) { - return s->icr[offset - 0x40]; - } - switch (offset) { - case 0x00: - return (uint32_t)(s->ipr >> 32); - case 0x04: - return (uint32_t)s->ipr; - case 0x08: - return (uint32_t)(s->imr >> 32); - case 0x0c: - return (uint32_t)s->imr; - case 0x10: - return (uint32_t)(s->ifr >> 32); - case 0x14: - return (uint32_t)s->ifr; - case 0xe0: /* SWIACK. */ - return s->active_vector; - case 0xe1: case 0xe2: case 0xe3: case 0xe4: - case 0xe5: case 0xe6: case 0xe7: - /* LnIACK */ - hw_error("mcf_intc_read: LnIACK not implemented\n"); - default: - return 0; - } -} - -static void mcf_intc_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - int offset; - mcf_intc_state *s = (mcf_intc_state *)opaque; - offset = addr & 0xff; - if (offset >= 0x40 && offset < 0x80) { - int n = offset - 0x40; - s->icr[n] = val; - if (val == 0) - s->enabled &= ~(1ull << n); - else - s->enabled |= (1ull << n); - mcf_intc_update(s); - return; - } - switch (offset) { - case 0x00: case 0x04: - /* Ignore IPR writes. */ - return; - case 0x08: - s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32); - break; - case 0x0c: - s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val; - break; - default: - hw_error("mcf_intc_write: Bad write offset %d\n", offset); - break; - } - mcf_intc_update(s); -} - -static void mcf_intc_set_irq(void *opaque, int irq, int level) -{ - mcf_intc_state *s = (mcf_intc_state *)opaque; - if (irq >= 64) - return; - if (level) - s->ipr |= 1ull << irq; - else - s->ipr &= ~(1ull << irq); - mcf_intc_update(s); -} - -static void mcf_intc_reset(mcf_intc_state *s) -{ - s->imr = ~0ull; - s->ipr = 0; - s->ifr = 0; - s->enabled = 0; - memset(s->icr, 0, 64); - s->active_vector = 24; -} - -static const MemoryRegionOps mcf_intc_ops = { - .read = mcf_intc_read, - .write = mcf_intc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -qemu_irq *mcf_intc_init(MemoryRegion *sysmem, - hwaddr base, - M68kCPU *cpu) -{ - mcf_intc_state *s; - - s = g_malloc0(sizeof(mcf_intc_state)); - s->cpu = cpu; - mcf_intc_reset(s); - - memory_region_init_io(&s->iomem, &mcf_intc_ops, s, "mcf", 0x100); - memory_region_add_subregion(sysmem, base, &s->iomem); - - return qemu_allocate_irqs(mcf_intc_set_irq, s, 64); -} -- cgit v1.2.3 From c68c4a56e93f54b374c5207f0185f8e9fa2aec3b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: ppc: move files referencing CPU to hw/ppc/ Signed-off-by: Paolo Bonzini --- hw/mpc8544_guts.c | 143 ---------- hw/ppc/Makefile.objs | 13 +- hw/ppc/mpc8544_guts.c | 143 ++++++++++ hw/ppc/ppc4xx_devs.c | 721 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/ppce500_spin.c | 222 ++++++++++++++++ hw/ppc/spapr_vio.c | 649 +++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/xics.c | 588 ++++++++++++++++++++++++++++++++++++++++ hw/ppc4xx_devs.c | 721 -------------------------------------------------- hw/ppce500_spin.c | 222 ---------------- hw/spapr_vio.c | 649 --------------------------------------------- hw/xics.c | 588 ---------------------------------------- 11 files changed, 2329 insertions(+), 2330 deletions(-) delete mode 100644 hw/mpc8544_guts.c create mode 100644 hw/ppc/mpc8544_guts.c create mode 100644 hw/ppc/ppc4xx_devs.c create mode 100644 hw/ppc/ppce500_spin.c create mode 100644 hw/ppc/spapr_vio.c create mode 100644 hw/ppc/xics.c delete mode 100644 hw/ppc4xx_devs.c delete mode 100644 hw/ppce500_spin.c delete mode 100644 hw/spapr_vio.c delete mode 100644 hw/xics.c diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c deleted file mode 100644 index 193beab2c2..0000000000 --- a/hw/mpc8544_guts.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * QEMU PowerPC MPC8544 global util pseudo-device - * - * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: Alexander Graf, - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * ***************************************************************** - * - * The documentation for this device is noted in the MPC8544 documentation, - * file name "MPC8544ERM.pdf". You can easily find it on the web. - * - */ - -#include "hw/hw.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" - -#define MPC8544_GUTS_MMIO_SIZE 0x1000 -#define MPC8544_GUTS_RSTCR_RESET 0x02 - -#define MPC8544_GUTS_ADDR_PORPLLSR 0x00 -#define MPC8544_GUTS_ADDR_PORBMSR 0x04 -#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08 -#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C -#define MPC8544_GUTS_ADDR_PORDBGMSR 0x10 -#define MPC8544_GUTS_ADDR_PORDEVSR2 0x14 -#define MPC8544_GUTS_ADDR_GPPORCR 0x20 -#define MPC8544_GUTS_ADDR_GPIOCR 0x30 -#define MPC8544_GUTS_ADDR_GPOUTDR 0x40 -#define MPC8544_GUTS_ADDR_GPINDR 0x50 -#define MPC8544_GUTS_ADDR_PMUXCR 0x60 -#define MPC8544_GUTS_ADDR_DEVDISR 0x70 -#define MPC8544_GUTS_ADDR_POWMGTCSR 0x80 -#define MPC8544_GUTS_ADDR_MCPSUMR 0x90 -#define MPC8544_GUTS_ADDR_RSTRSCR 0x94 -#define MPC8544_GUTS_ADDR_PVR 0xA0 -#define MPC8544_GUTS_ADDR_SVR 0xA4 -#define MPC8544_GUTS_ADDR_RSTCR 0xB0 -#define MPC8544_GUTS_ADDR_IOVSELSR 0xC0 -#define MPC8544_GUTS_ADDR_DDRCSR 0xB20 -#define MPC8544_GUTS_ADDR_DDRCDR 0xB24 -#define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28 -#define MPC8544_GUTS_ADDR_CLKOCR 0xE00 -#define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04 -#define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10 -#define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18 - -struct GutsState { - SysBusDevice busdev; - MemoryRegion iomem; -}; - -typedef struct GutsState GutsState; - -static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr, - unsigned size) -{ - uint32_t value = 0; - CPUPPCState *env = cpu_single_env; - - addr &= MPC8544_GUTS_MMIO_SIZE - 1; - switch (addr) { - case MPC8544_GUTS_ADDR_PVR: - value = env->spr[SPR_PVR]; - break; - case MPC8544_GUTS_ADDR_SVR: - value = env->spr[SPR_E500_SVR]; - break; - default: - fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr); - break; - } - - return value; -} - -static void mpc8544_guts_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - addr &= MPC8544_GUTS_MMIO_SIZE - 1; - - switch (addr) { - case MPC8544_GUTS_ADDR_RSTCR: - if (value & MPC8544_GUTS_RSTCR_RESET) { - qemu_system_reset_request(); - } - break; - default: - fprintf(stderr, "guts: Unknown register write: %x = %x\n", - (int)addr, (unsigned)value); - break; - } -} - -static const MemoryRegionOps mpc8544_guts_ops = { - .read = mpc8544_guts_read, - .write = mpc8544_guts_write, - .endianness = DEVICE_BIG_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static int mpc8544_guts_initfn(SysBusDevice *dev) -{ - GutsState *s; - - s = FROM_SYSBUS(GutsState, SYS_BUS_DEVICE(dev)); - - memory_region_init_io(&s->iomem, &mpc8544_guts_ops, s, - "mpc6544.guts", MPC8544_GUTS_MMIO_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void mpc8544_guts_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mpc8544_guts_initfn; -} - -static const TypeInfo mpc8544_guts_info = { - .name = "mpc8544-guts", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(GutsState), - .class_init = mpc8544_guts_class_init, -}; - -static void mpc8544_guts_register_types(void) -{ - type_register_static(&mpc8544_guts_info); -} - -type_init(mpc8544_guts_register_types) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 294d0de211..acc9961ab0 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,14 +1,12 @@ # PREP target obj-y += mc146818rtc.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o spapr_vio.o -obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o +obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o +obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o # PowerPC 4xx boards -obj-y += ppc4xx_devs.o ppc4xx_pci.o -# PowerPC E500 boards -obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o +obj-y += ppc4xx_pci.o # PowerPC OpenPIC obj-y += openpic.o @@ -20,9 +18,9 @@ obj-y := $(addprefix ../,$(obj-y)) # shared objects obj-y += ppc.o ppc_booke.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr.o +obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o # PowerPC 4xx boards -obj-y += ppc405_boards.o ppc405_uc.o ppc440_bamboo.o +obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o # PReP obj-y += prep.o # OldWorld PowerMac @@ -31,5 +29,6 @@ obj-y += mac_oldworld.o obj-y += mac_newworld.o # e500 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o +obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o # PowerPC 440 Xilinx ML507 reference board. obj-y += virtex_ml507.o diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c new file mode 100644 index 0000000000..193beab2c2 --- /dev/null +++ b/hw/ppc/mpc8544_guts.c @@ -0,0 +1,143 @@ +/* + * QEMU PowerPC MPC8544 global util pseudo-device + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ***************************************************************** + * + * The documentation for this device is noted in the MPC8544 documentation, + * file name "MPC8544ERM.pdf". You can easily find it on the web. + * + */ + +#include "hw/hw.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" + +#define MPC8544_GUTS_MMIO_SIZE 0x1000 +#define MPC8544_GUTS_RSTCR_RESET 0x02 + +#define MPC8544_GUTS_ADDR_PORPLLSR 0x00 +#define MPC8544_GUTS_ADDR_PORBMSR 0x04 +#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08 +#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C +#define MPC8544_GUTS_ADDR_PORDBGMSR 0x10 +#define MPC8544_GUTS_ADDR_PORDEVSR2 0x14 +#define MPC8544_GUTS_ADDR_GPPORCR 0x20 +#define MPC8544_GUTS_ADDR_GPIOCR 0x30 +#define MPC8544_GUTS_ADDR_GPOUTDR 0x40 +#define MPC8544_GUTS_ADDR_GPINDR 0x50 +#define MPC8544_GUTS_ADDR_PMUXCR 0x60 +#define MPC8544_GUTS_ADDR_DEVDISR 0x70 +#define MPC8544_GUTS_ADDR_POWMGTCSR 0x80 +#define MPC8544_GUTS_ADDR_MCPSUMR 0x90 +#define MPC8544_GUTS_ADDR_RSTRSCR 0x94 +#define MPC8544_GUTS_ADDR_PVR 0xA0 +#define MPC8544_GUTS_ADDR_SVR 0xA4 +#define MPC8544_GUTS_ADDR_RSTCR 0xB0 +#define MPC8544_GUTS_ADDR_IOVSELSR 0xC0 +#define MPC8544_GUTS_ADDR_DDRCSR 0xB20 +#define MPC8544_GUTS_ADDR_DDRCDR 0xB24 +#define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28 +#define MPC8544_GUTS_ADDR_CLKOCR 0xE00 +#define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04 +#define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10 +#define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18 + +struct GutsState { + SysBusDevice busdev; + MemoryRegion iomem; +}; + +typedef struct GutsState GutsState; + +static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr, + unsigned size) +{ + uint32_t value = 0; + CPUPPCState *env = cpu_single_env; + + addr &= MPC8544_GUTS_MMIO_SIZE - 1; + switch (addr) { + case MPC8544_GUTS_ADDR_PVR: + value = env->spr[SPR_PVR]; + break; + case MPC8544_GUTS_ADDR_SVR: + value = env->spr[SPR_E500_SVR]; + break; + default: + fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr); + break; + } + + return value; +} + +static void mpc8544_guts_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + addr &= MPC8544_GUTS_MMIO_SIZE - 1; + + switch (addr) { + case MPC8544_GUTS_ADDR_RSTCR: + if (value & MPC8544_GUTS_RSTCR_RESET) { + qemu_system_reset_request(); + } + break; + default: + fprintf(stderr, "guts: Unknown register write: %x = %x\n", + (int)addr, (unsigned)value); + break; + } +} + +static const MemoryRegionOps mpc8544_guts_ops = { + .read = mpc8544_guts_read, + .write = mpc8544_guts_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static int mpc8544_guts_initfn(SysBusDevice *dev) +{ + GutsState *s; + + s = FROM_SYSBUS(GutsState, SYS_BUS_DEVICE(dev)); + + memory_region_init_io(&s->iomem, &mpc8544_guts_ops, s, + "mpc6544.guts", MPC8544_GUTS_MMIO_SIZE); + sysbus_init_mmio(dev, &s->iomem); + + return 0; +} + +static void mpc8544_guts_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mpc8544_guts_initfn; +} + +static const TypeInfo mpc8544_guts_info = { + .name = "mpc8544-guts", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GutsState), + .class_init = mpc8544_guts_class_init, +}; + +static void mpc8544_guts_register_types(void) +{ + type_register_static(&mpc8544_guts_info); +} + +type_init(mpc8544_guts_register_types) diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c new file mode 100644 index 0000000000..49ec728a7b --- /dev/null +++ b/hw/ppc/ppc4xx_devs.c @@ -0,0 +1,721 @@ +/* + * QEMU PowerPC 4xx embedded processors shared devices emulation + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc4xx.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" + +//#define DEBUG_MMIO +//#define DEBUG_UNASSIGNED +#define DEBUG_UIC + + +#ifdef DEBUG_UIC +# define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) +#else +# define LOG_UIC(...) do { } while (0) +#endif + +static void ppc4xx_reset(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +/*****************************************************************************/ +/* Generic PowerPC 4xx processor instantiation */ +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk) +{ + PowerPCCPU *cpu; + CPUPPCState *env; + + /* init CPUs */ + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find PowerPC %s CPU definition\n", + cpu_model); + exit(1); + } + env = &cpu->env; + + cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ + cpu_clk->opaque = env; + /* Set time-base frequency to sysclk */ + tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT); + tb_clk->opaque = env; + ppc_dcr_init(env, NULL, NULL); + /* Register qemu callbacks */ + qemu_register_reset(ppc4xx_reset, cpu); + + return cpu; +} + +/*****************************************************************************/ +/* "Universal" Interrupt controller */ +enum { + DCR_UICSR = 0x000, + DCR_UICSRS = 0x001, + DCR_UICER = 0x002, + DCR_UICCR = 0x003, + DCR_UICPR = 0x004, + DCR_UICTR = 0x005, + DCR_UICMSR = 0x006, + DCR_UICVR = 0x007, + DCR_UICVCR = 0x008, + DCR_UICMAX = 0x009, +}; + +#define UIC_MAX_IRQ 32 +typedef struct ppcuic_t ppcuic_t; +struct ppcuic_t { + uint32_t dcr_base; + int use_vectors; + uint32_t level; /* Remembers the state of level-triggered interrupts. */ + uint32_t uicsr; /* Status register */ + uint32_t uicer; /* Enable register */ + uint32_t uiccr; /* Critical register */ + uint32_t uicpr; /* Polarity register */ + uint32_t uictr; /* Triggering register */ + uint32_t uicvcr; /* Vector configuration register */ + uint32_t uicvr; + qemu_irq *irqs; +}; + +static void ppcuic_trigger_irq (ppcuic_t *uic) +{ + uint32_t ir, cr; + int start, end, inc, i; + + /* Trigger interrupt if any is pending */ + ir = uic->uicsr & uic->uicer & (~uic->uiccr); + cr = uic->uicsr & uic->uicer & uic->uiccr; + LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32 + " uiccr %08" PRIx32 "\n" + " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", + __func__, uic->uicsr, uic->uicer, uic->uiccr, + uic->uicsr & uic->uicer, ir, cr); + if (ir != 0x0000000) { + LOG_UIC("Raise UIC interrupt\n"); + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); + } else { + LOG_UIC("Lower UIC interrupt\n"); + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); + } + /* Trigger critical interrupt if any is pending and update vector */ + if (cr != 0x0000000) { + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); + if (uic->use_vectors) { + /* Compute critical IRQ vector */ + if (uic->uicvcr & 1) { + start = 31; + end = 0; + inc = -1; + } else { + start = 0; + end = 31; + inc = 1; + } + uic->uicvr = uic->uicvcr & 0xFFFFFFFC; + for (i = start; i <= end; i += inc) { + if (cr & (1 << i)) { + uic->uicvr += (i - start) * 512 * inc; + break; + } + } + } + LOG_UIC("Raise UIC critical interrupt - " + "vector %08" PRIx32 "\n", uic->uicvr); + } else { + LOG_UIC("Lower UIC critical interrupt\n"); + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); + uic->uicvr = 0x00000000; + } +} + +static void ppcuic_set_irq (void *opaque, int irq_num, int level) +{ + ppcuic_t *uic; + uint32_t mask, sr; + + uic = opaque; + mask = 1 << (31-irq_num); + LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 + " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", + __func__, irq_num, level, + uic->uicsr, mask, uic->uicsr & mask, level << irq_num); + if (irq_num < 0 || irq_num > 31) + return; + sr = uic->uicsr; + + /* Update status register */ + if (uic->uictr & mask) { + /* Edge sensitive interrupt */ + if (level == 1) + uic->uicsr |= mask; + } else { + /* Level sensitive interrupt */ + if (level == 1) { + uic->uicsr |= mask; + uic->level |= mask; + } else { + uic->uicsr &= ~mask; + uic->level &= ~mask; + } + } + LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => " + "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); + if (sr != uic->uicsr) + ppcuic_trigger_irq(uic); +} + +static uint32_t dcr_read_uic (void *opaque, int dcrn) +{ + ppcuic_t *uic; + uint32_t ret; + + uic = opaque; + dcrn -= uic->dcr_base; + switch (dcrn) { + case DCR_UICSR: + case DCR_UICSRS: + ret = uic->uicsr; + break; + case DCR_UICER: + ret = uic->uicer; + break; + case DCR_UICCR: + ret = uic->uiccr; + break; + case DCR_UICPR: + ret = uic->uicpr; + break; + case DCR_UICTR: + ret = uic->uictr; + break; + case DCR_UICMSR: + ret = uic->uicsr & uic->uicer; + break; + case DCR_UICVR: + if (!uic->use_vectors) + goto no_read; + ret = uic->uicvr; + break; + case DCR_UICVCR: + if (!uic->use_vectors) + goto no_read; + ret = uic->uicvcr; + break; + default: + no_read: + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_uic (void *opaque, int dcrn, uint32_t val) +{ + ppcuic_t *uic; + + uic = opaque; + dcrn -= uic->dcr_base; + LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val); + switch (dcrn) { + case DCR_UICSR: + uic->uicsr &= ~val; + uic->uicsr |= uic->level; + ppcuic_trigger_irq(uic); + break; + case DCR_UICSRS: + uic->uicsr |= val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICER: + uic->uicer = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICCR: + uic->uiccr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICPR: + uic->uicpr = val; + break; + case DCR_UICTR: + uic->uictr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICMSR: + break; + case DCR_UICVR: + break; + case DCR_UICVCR: + uic->uicvcr = val & 0xFFFFFFFD; + ppcuic_trigger_irq(uic); + break; + } +} + +static void ppcuic_reset (void *opaque) +{ + ppcuic_t *uic; + + uic = opaque; + uic->uiccr = 0x00000000; + uic->uicer = 0x00000000; + uic->uicpr = 0x00000000; + uic->uicsr = 0x00000000; + uic->uictr = 0x00000000; + if (uic->use_vectors) { + uic->uicvcr = 0x00000000; + uic->uicvr = 0x0000000; + } +} + +qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, + uint32_t dcr_base, int has_ssr, int has_vr) +{ + ppcuic_t *uic; + int i; + + uic = g_malloc0(sizeof(ppcuic_t)); + uic->dcr_base = dcr_base; + uic->irqs = irqs; + if (has_vr) + uic->use_vectors = 1; + for (i = 0; i < DCR_UICMAX; i++) { + ppc_dcr_register(env, dcr_base + i, uic, + &dcr_read_uic, &dcr_write_uic); + } + qemu_register_reset(ppcuic_reset, uic); + + return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); +} + +/*****************************************************************************/ +/* SDRAM controller */ +typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; +struct ppc4xx_sdram_t { + uint32_t addr; + int nbanks; + MemoryRegion containers[4]; /* used for clipping */ + MemoryRegion *ram_memories; + hwaddr ram_bases[4]; + hwaddr ram_sizes[4]; + uint32_t besr0; + uint32_t besr1; + uint32_t bear; + uint32_t cfg; + uint32_t status; + uint32_t rtr; + uint32_t pmit; + uint32_t bcr[4]; + uint32_t tr; + uint32_t ecccfg; + uint32_t eccesr; + qemu_irq irq; +}; + +enum { + SDRAM0_CFGADDR = 0x010, + SDRAM0_CFGDATA = 0x011, +}; + +/* XXX: TOFIX: some patches have made this code become inconsistent: + * there are type inconsistencies, mixing hwaddr, target_ulong + * and uint32_t + */ +static uint32_t sdram_bcr (hwaddr ram_base, + hwaddr ram_size) +{ + uint32_t bcr; + + switch (ram_size) { + case (4 * 1024 * 1024): + bcr = 0x00000000; + break; + case (8 * 1024 * 1024): + bcr = 0x00020000; + break; + case (16 * 1024 * 1024): + bcr = 0x00040000; + break; + case (32 * 1024 * 1024): + bcr = 0x00060000; + break; + case (64 * 1024 * 1024): + bcr = 0x00080000; + break; + case (128 * 1024 * 1024): + bcr = 0x000A0000; + break; + case (256 * 1024 * 1024): + bcr = 0x000C0000; + break; + default: + printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__, + ram_size); + return 0x00000000; + } + bcr |= ram_base & 0xFF800000; + bcr |= 1; + + return bcr; +} + +static inline hwaddr sdram_base(uint32_t bcr) +{ + return bcr & 0xFF800000; +} + +static target_ulong sdram_size (uint32_t bcr) +{ + target_ulong size; + int sh; + + sh = (bcr >> 17) & 0x7; + if (sh == 7) + size = -1; + else + size = (4 * 1024 * 1024) << sh; + + return size; +} + +static void sdram_set_bcr(ppc4xx_sdram_t *sdram, + uint32_t *bcrp, uint32_t bcr, int enabled) +{ + unsigned n = bcrp - sdram->bcr; + + if (*bcrp & 0x00000001) { + /* Unmap RAM */ +#ifdef DEBUG_SDRAM + printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + __func__, sdram_base(*bcrp), sdram_size(*bcrp)); +#endif + memory_region_del_subregion(get_system_memory(), + &sdram->containers[n]); + memory_region_del_subregion(&sdram->containers[n], + &sdram->ram_memories[n]); + memory_region_destroy(&sdram->containers[n]); + } + *bcrp = bcr & 0xFFDEE001; + if (enabled && (bcr & 0x00000001)) { +#ifdef DEBUG_SDRAM + printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + __func__, sdram_base(bcr), sdram_size(bcr)); +#endif + memory_region_init(&sdram->containers[n], "sdram-containers", + sdram_size(bcr)); + memory_region_add_subregion(&sdram->containers[n], 0, + &sdram->ram_memories[n]); + memory_region_add_subregion(get_system_memory(), + sdram_base(bcr), + &sdram->containers[n]); + } +} + +static void sdram_map_bcr (ppc4xx_sdram_t *sdram) +{ + int i; + + for (i = 0; i < sdram->nbanks; i++) { + if (sdram->ram_sizes[i] != 0) { + sdram_set_bcr(sdram, + &sdram->bcr[i], + sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]), + 1); + } else { + sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0); + } + } +} + +static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) +{ + int i; + + for (i = 0; i < sdram->nbanks; i++) { +#ifdef DEBUG_SDRAM + printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); +#endif + memory_region_del_subregion(get_system_memory(), + &sdram->ram_memories[i]); + } +} + +static uint32_t dcr_read_sdram (void *opaque, int dcrn) +{ + ppc4xx_sdram_t *sdram; + uint32_t ret; + + sdram = opaque; + switch (dcrn) { + case SDRAM0_CFGADDR: + ret = sdram->addr; + break; + case SDRAM0_CFGDATA: + switch (sdram->addr) { + case 0x00: /* SDRAM_BESR0 */ + ret = sdram->besr0; + break; + case 0x08: /* SDRAM_BESR1 */ + ret = sdram->besr1; + break; + case 0x10: /* SDRAM_BEAR */ + ret = sdram->bear; + break; + case 0x20: /* SDRAM_CFG */ + ret = sdram->cfg; + break; + case 0x24: /* SDRAM_STATUS */ + ret = sdram->status; + break; + case 0x30: /* SDRAM_RTR */ + ret = sdram->rtr; + break; + case 0x34: /* SDRAM_PMIT */ + ret = sdram->pmit; + break; + case 0x40: /* SDRAM_B0CR */ + ret = sdram->bcr[0]; + break; + case 0x44: /* SDRAM_B1CR */ + ret = sdram->bcr[1]; + break; + case 0x48: /* SDRAM_B2CR */ + ret = sdram->bcr[2]; + break; + case 0x4C: /* SDRAM_B3CR */ + ret = sdram->bcr[3]; + break; + case 0x80: /* SDRAM_TR */ + ret = -1; /* ? */ + break; + case 0x94: /* SDRAM_ECCCFG */ + ret = sdram->ecccfg; + break; + case 0x98: /* SDRAM_ECCESR */ + ret = sdram->eccesr; + break; + default: /* Error */ + ret = -1; + break; + } + break; + default: + /* Avoid gcc warning */ + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) +{ + ppc4xx_sdram_t *sdram; + + sdram = opaque; + switch (dcrn) { + case SDRAM0_CFGADDR: + sdram->addr = val; + break; + case SDRAM0_CFGDATA: + switch (sdram->addr) { + case 0x00: /* SDRAM_BESR0 */ + sdram->besr0 &= ~val; + break; + case 0x08: /* SDRAM_BESR1 */ + sdram->besr1 &= ~val; + break; + case 0x10: /* SDRAM_BEAR */ + sdram->bear = val; + break; + case 0x20: /* SDRAM_CFG */ + val &= 0xFFE00000; + if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { +#ifdef DEBUG_SDRAM + printf("%s: enable SDRAM controller\n", __func__); +#endif + /* validate all RAM mappings */ + sdram_map_bcr(sdram); + sdram->status &= ~0x80000000; + } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { +#ifdef DEBUG_SDRAM + printf("%s: disable SDRAM controller\n", __func__); +#endif + /* invalidate all RAM mappings */ + sdram_unmap_bcr(sdram); + sdram->status |= 0x80000000; + } + if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) + sdram->status |= 0x40000000; + else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) + sdram->status &= ~0x40000000; + sdram->cfg = val; + break; + case 0x24: /* SDRAM_STATUS */ + /* Read-only register */ + break; + case 0x30: /* SDRAM_RTR */ + sdram->rtr = val & 0x3FF80000; + break; + case 0x34: /* SDRAM_PMIT */ + sdram->pmit = (val & 0xF8000000) | 0x07C00000; + break; + case 0x40: /* SDRAM_B0CR */ + sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000); + break; + case 0x44: /* SDRAM_B1CR */ + sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000); + break; + case 0x48: /* SDRAM_B2CR */ + sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000); + break; + case 0x4C: /* SDRAM_B3CR */ + sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000); + break; + case 0x80: /* SDRAM_TR */ + sdram->tr = val & 0x018FC01F; + break; + case 0x94: /* SDRAM_ECCCFG */ + sdram->ecccfg = val & 0x00F00000; + break; + case 0x98: /* SDRAM_ECCESR */ + val &= 0xFFF0F000; + if (sdram->eccesr == 0 && val != 0) + qemu_irq_raise(sdram->irq); + else if (sdram->eccesr != 0 && val == 0) + qemu_irq_lower(sdram->irq); + sdram->eccesr = val; + break; + default: /* Error */ + break; + } + break; + } +} + +static void sdram_reset (void *opaque) +{ + ppc4xx_sdram_t *sdram; + + sdram = opaque; + sdram->addr = 0x00000000; + sdram->bear = 0x00000000; + sdram->besr0 = 0x00000000; /* No error */ + sdram->besr1 = 0x00000000; /* No error */ + sdram->cfg = 0x00000000; + sdram->ecccfg = 0x00000000; /* No ECC */ + sdram->eccesr = 0x00000000; /* No error */ + sdram->pmit = 0x07C00000; + sdram->rtr = 0x05F00000; + sdram->tr = 0x00854009; + /* We pre-initialize RAM banks */ + sdram->status = 0x00000000; + sdram->cfg = 0x00800000; +} + +void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, + MemoryRegion *ram_memories, + hwaddr *ram_bases, + hwaddr *ram_sizes, + int do_init) +{ + ppc4xx_sdram_t *sdram; + + sdram = g_malloc0(sizeof(ppc4xx_sdram_t)); + sdram->irq = irq; + sdram->nbanks = nbanks; + sdram->ram_memories = ram_memories; + memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); + memcpy(sdram->ram_bases, ram_bases, + nbanks * sizeof(hwaddr)); + memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); + memcpy(sdram->ram_sizes, ram_sizes, + nbanks * sizeof(hwaddr)); + qemu_register_reset(&sdram_reset, sdram); + ppc_dcr_register(env, SDRAM0_CFGADDR, + sdram, &dcr_read_sdram, &dcr_write_sdram); + ppc_dcr_register(env, SDRAM0_CFGDATA, + sdram, &dcr_read_sdram, &dcr_write_sdram); + if (do_init) + sdram_map_bcr(sdram); +} + +/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. + * + * sdram_bank_sizes[] must be 0-terminated. + * + * The 4xx SDRAM controller supports a small number of banks, and each bank + * must be one of a small set of sizes. The number of banks and the supported + * sizes varies by SoC. */ +ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, + MemoryRegion ram_memories[], + hwaddr ram_bases[], + hwaddr ram_sizes[], + const unsigned int sdram_bank_sizes[]) +{ + ram_addr_t size_left = ram_size; + ram_addr_t base = 0; + int i; + int j; + + for (i = 0; i < nr_banks; i++) { + for (j = 0; sdram_bank_sizes[j] != 0; j++) { + unsigned int bank_size = sdram_bank_sizes[j]; + + if (bank_size <= size_left) { + char name[32]; + snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); + memory_region_init_ram(&ram_memories[i], name, bank_size); + vmstate_register_ram_global(&ram_memories[i]); + ram_bases[i] = base; + ram_sizes[i] = bank_size; + base += bank_size; + size_left -= bank_size; + break; + } + } + + if (!size_left) { + /* No need to use the remaining banks. */ + break; + } + } + + ram_size -= size_left; + if (size_left) + printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n", + (int)(ram_size >> 20)); + + return ram_size; +} diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c new file mode 100644 index 0000000000..d904fbe176 --- /dev/null +++ b/hw/ppc/ppce500_spin.c @@ -0,0 +1,222 @@ +/* + * QEMU PowerPC e500v2 ePAPR spinning code + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * This code is not really a device, but models an interface that usually + * firmware takes care of. It's used when QEMU plays the role of firmware. + * + * Specification: + * + * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf + * + */ + +#include "hw/hw.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "sysemu/kvm.h" + +#define MAX_CPUS 32 + +typedef struct spin_info { + uint64_t addr; + uint64_t r3; + uint32_t resv; + uint32_t pir; + uint64_t reserved; +} QEMU_PACKED SpinInfo; + +typedef struct spin_state { + SysBusDevice busdev; + MemoryRegion iomem; + SpinInfo spin[MAX_CPUS]; +} SpinState; + +typedef struct spin_kick { + PowerPCCPU *cpu; + SpinInfo *spin; +} SpinKick; + +static void spin_reset(void *opaque) +{ + SpinState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + SpinInfo *info = &s->spin[i]; + + info->pir = i; + info->r3 = i; + info->addr = 1; + } +} + +/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ +static inline hwaddr booke206_page_size_to_tlb(uint64_t size) +{ + return (ffs(size >> 10) - 1) >> 1; +} + +static void mmubooke_create_initial_mapping(CPUPPCState *env, + target_ulong va, + hwaddr pa, + hwaddr len) +{ + ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1); + hwaddr size; + + size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT); + tlb->mas1 = MAS1_VALID | size; + tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M; + tlb->mas7_3 = pa & TARGET_PAGE_MASK; + tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; + env->tlb_dirty = true; +} + +static void spin_kick(void *data) +{ + SpinKick *kick = data; + CPUState *cpu = CPU(kick->cpu); + CPUPPCState *env = &kick->cpu->env; + SpinInfo *curspin = kick->spin; + hwaddr map_size = 64 * 1024 * 1024; + hwaddr map_start; + + cpu_synchronize_state(env); + stl_p(&curspin->pir, env->spr[SPR_PIR]); + env->nip = ldq_p(&curspin->addr) & (map_size - 1); + env->gpr[3] = ldq_p(&curspin->r3); + env->gpr[4] = 0; + env->gpr[5] = 0; + env->gpr[6] = 0; + env->gpr[7] = map_size; + env->gpr[8] = 0; + env->gpr[9] = 0; + + map_start = ldq_p(&curspin->addr) & ~(map_size - 1); + mmubooke_create_initial_mapping(env, 0, map_start, map_size); + + env->halted = 0; + env->exception_index = -1; + cpu->stopped = false; + qemu_cpu_kick(cpu); +} + +static void spin_write(void *opaque, hwaddr addr, uint64_t value, + unsigned len) +{ + SpinState *s = opaque; + int env_idx = addr / sizeof(SpinInfo); + CPUState *cpu; + SpinInfo *curspin = &s->spin[env_idx]; + uint8_t *curspin_p = (uint8_t*)curspin; + + cpu = qemu_get_cpu(env_idx); + if (cpu == NULL) { + /* Unknown CPU */ + return; + } + + if (cpu->cpu_index == 0) { + /* primary CPU doesn't spin */ + return; + } + + curspin_p = &curspin_p[addr % sizeof(SpinInfo)]; + switch (len) { + case 1: + stb_p(curspin_p, value); + break; + case 2: + stw_p(curspin_p, value); + break; + case 4: + stl_p(curspin_p, value); + break; + } + + if (!(ldq_p(&curspin->addr) & 1)) { + /* run CPU */ + SpinKick kick = { + .cpu = POWERPC_CPU(cpu), + .spin = curspin, + }; + + run_on_cpu(cpu, spin_kick, &kick); + } +} + +static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len) +{ + SpinState *s = opaque; + uint8_t *spin_p = &((uint8_t*)s->spin)[addr]; + + switch (len) { + case 1: + return ldub_p(spin_p); + case 2: + return lduw_p(spin_p); + case 4: + return ldl_p(spin_p); + default: + hw_error("ppce500: unexpected %s with len = %u", __func__, len); + } +} + +static const MemoryRegionOps spin_rw_ops = { + .read = spin_read, + .write = spin_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static int ppce500_spin_initfn(SysBusDevice *dev) +{ + SpinState *s; + + s = FROM_SYSBUS(SpinState, SYS_BUS_DEVICE(dev)); + + memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device", + sizeof(SpinInfo) * MAX_CPUS); + sysbus_init_mmio(dev, &s->iomem); + + qemu_register_reset(spin_reset, s); + + return 0; +} + +static void ppce500_spin_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ppce500_spin_initfn; +} + +static const TypeInfo ppce500_spin_info = { + .name = "e500-spin", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SpinState), + .class_init = ppce500_spin_class_init, +}; + +static void ppce500_spin_register_types(void) +{ + type_register_static(&ppce500_spin_info); +} + +type_init(ppce500_spin_register_types) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c new file mode 100644 index 0000000000..6eb3ab5482 --- /dev/null +++ b/hw/ppc/spapr_vio.c @@ -0,0 +1,649 @@ +/* + * QEMU sPAPR VIO code + * + * Copyright (c) 2010 David Gibson, IBM Corporation + * Based on the s390 virtio bus code: + * Copyright (c) 2009 Alexander Graf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "hw/hw.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "monitor/monitor.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/sysbus.h" +#include "sysemu/kvm.h" +#include "sysemu/device_tree.h" +#include "kvm_ppc.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" +#include "hw/xics.h" + +#ifdef CONFIG_FDT +#include +#endif /* CONFIG_FDT */ + +/* #define DEBUG_SPAPR */ + +#ifdef DEBUG_SPAPR +#define dprintf(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +static Property spapr_vio_props[] = { + DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \ + DEFINE_PROP_END_OF_LIST(), +}; + +static const TypeInfo spapr_vio_bus_info = { + .name = TYPE_SPAPR_VIO_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(VIOsPAPRBus), +}; + +VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) +{ + BusChild *kid; + VIOsPAPRDevice *dev = NULL; + + QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { + dev = (VIOsPAPRDevice *)kid->child; + if (dev->reg == reg) { + return dev; + } + } + + return NULL; +} + +static char *vio_format_dev_name(VIOsPAPRDevice *dev) +{ + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + char *name; + + /* Device tree style name device@reg */ + name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg); + + return name; +} + +#ifdef CONFIG_FDT +static int vio_make_devnode(VIOsPAPRDevice *dev, + void *fdt) +{ + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + int vdevice_off, node_off, ret; + char *dt_name; + + vdevice_off = fdt_path_offset(fdt, "/vdevice"); + if (vdevice_off < 0) { + return vdevice_off; + } + + dt_name = vio_format_dev_name(dev); + node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); + g_free(dt_name); + if (node_off < 0) { + return node_off; + } + + ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg); + if (ret < 0) { + return ret; + } + + if (pc->dt_type) { + ret = fdt_setprop_string(fdt, node_off, "device_type", + pc->dt_type); + if (ret < 0) { + return ret; + } + } + + if (pc->dt_compatible) { + ret = fdt_setprop_string(fdt, node_off, "compatible", + pc->dt_compatible); + if (ret < 0) { + return ret; + } + } + + if (dev->irq) { + uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0}; + + ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, + sizeof(ints_prop)); + if (ret < 0) { + return ret; + } + } + + ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma); + if (ret < 0) { + return ret; + } + + if (pc->devnode) { + ret = (pc->devnode)(dev, fdt, node_off); + if (ret < 0) { + return ret; + } + } + + return node_off; +} +#endif /* CONFIG_FDT */ + +/* + * CRQ handling + */ +static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong queue_addr = args[1]; + target_ulong queue_len = args[2]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + + if (!dev) { + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); + return H_PARAMETER; + } + + /* We can't grok a queue size bigger than 256M for now */ + if (queue_len < 0x1000 || queue_len > 0x10000000) { + hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx + ")\n", queue_len); + return H_PARAMETER; + } + + /* Check queue alignment */ + if (queue_addr & 0xfff) { + hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr); + return H_PARAMETER; + } + + /* Check if device supports CRQs */ + if (!dev->crq.SendFunc) { + hcall_dprintf("Device does not support CRQ\n"); + return H_NOT_FOUND; + } + + /* Already a queue ? */ + if (dev->crq.qsize) { + hcall_dprintf("CRQ already registered\n"); + return H_RESOURCE; + } + dev->crq.qladdr = queue_addr; + dev->crq.qsize = queue_len; + dev->crq.qnext = 0; + + dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" + TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n", + reg, queue_addr, queue_len); + return H_SUCCESS; +} + +static target_ulong free_crq(VIOsPAPRDevice *dev) +{ + dev->crq.qladdr = 0; + dev->crq.qsize = 0; + dev->crq.qnext = 0; + + dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); + + return H_SUCCESS; +} + +static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + + if (!dev) { + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); + return H_PARAMETER; + } + + return free_crq(dev); +} + +static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong msg_hi = args[1]; + target_ulong msg_lo = args[2]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + uint64_t crq_mangle[2]; + + if (!dev) { + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); + return H_PARAMETER; + } + crq_mangle[0] = cpu_to_be64(msg_hi); + crq_mangle[1] = cpu_to_be64(msg_lo); + + if (dev->crq.SendFunc) { + return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle); + } + + return H_HARDWARE; +} + +static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + + if (!dev) { + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); + return H_PARAMETER; + } + + return 0; +} + +/* Returns negative error, 0 success, or positive: queue full */ +int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) +{ + int rc; + uint8_t byte; + + if (!dev->crq.qsize) { + fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n"); + return -1; + } + + /* Maybe do a fast path for KVM just writing to the pages */ + rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1); + if (rc) { + return rc; + } + if (byte != 0) { + return 1; + } + + rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, + &crq[8], 8); + if (rc) { + return rc; + } + + kvmppc_eieio(); + + rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8); + if (rc) { + return rc; + } + + dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; + + if (dev->signal_state & 1) { + qemu_irq_pulse(spapr_vio_qirq(dev)); + } + + return 0; +} + +/* "quiesce" handling */ + +static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) +{ + if (dev->dma) { + spapr_tce_reset(dev->dma); + } + free_crq(dev); +} + +static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + VIOsPAPRBus *bus = spapr->vio_bus; + VIOsPAPRDevice *dev; + uint32_t unit, enable; + + if (nargs != 2) { + rtas_st(rets, 0, -3); + return; + } + unit = rtas_ld(args, 0); + enable = rtas_ld(args, 1); + dev = spapr_vio_find_by_reg(bus, unit); + if (!dev) { + rtas_st(rets, 0, -3); + return; + } + + if (!dev->dma) { + rtas_st(rets, 0, -3); + return; + } + + spapr_tce_set_bypass(dev->dma, !!enable); + + rtas_st(rets, 0, 0); +} + +static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + VIOsPAPRBus *bus = spapr->vio_bus; + BusChild *kid; + VIOsPAPRDevice *dev = NULL; + + if (nargs != 0) { + rtas_st(rets, 0, -3); + return; + } + + QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { + dev = (VIOsPAPRDevice *)kid->child; + spapr_vio_quiesce_one(dev); + } + + rtas_st(rets, 0, 0); +} + +static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) +{ + VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus); + BusChild *kid; + VIOsPAPRDevice *other; + + /* + * Check for a device other than the given one which is already + * using the requested address. We have to open code this because + * the given dev might already be in the list. + */ + QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { + other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child); + + if (other != dev && other->reg == dev->reg) { + return other; + } + } + + return 0; +} + +static void spapr_vio_busdev_reset(DeviceState *qdev) +{ + VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + + /* Shut down the request queue and TCEs if necessary */ + spapr_vio_quiesce_one(dev); + + dev->signal_state = 0; + + if (pc->reset) { + pc->reset(dev); + } +} + +static int spapr_vio_busdev_init(DeviceState *qdev) +{ + VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + char *id; + + if (dev->reg != -1) { + /* + * Explicitly assigned address, just verify that no-one else + * is using it. other mechanism). We have to open code this + * rather than using spapr_vio_find_by_reg() because sdev + * itself is already in the list. + */ + VIOsPAPRDevice *other = reg_conflict(dev); + + if (other) { + fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n", + object_get_typename(OBJECT(qdev)), + object_get_typename(OBJECT(&other->qdev)), + dev->reg); + return -1; + } + } else { + /* Need to assign an address */ + VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus); + + do { + dev->reg = bus->next_reg++; + } while (reg_conflict(dev)); + } + + /* Don't overwrite ids assigned on the command line */ + if (!dev->qdev.id) { + id = vio_format_dev_name(dev); + dev->qdev.id = id; + } + + dev->irq = spapr_allocate_msi(dev->irq); + if (!dev->irq) { + return -1; + } + + if (pc->rtce_window_size) { + uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; + dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + } + + return pc->init(dev); +} + +static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong mode = args[1]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRDeviceClass *pc; + + if (!dev) { + return H_PARAMETER; + } + + pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + + if (mode & ~pc->signal_mask) { + return H_PARAMETER; + } + + dev->signal_state = mode; + + return H_SUCCESS; +} + +VIOsPAPRBus *spapr_vio_bus_init(void) +{ + VIOsPAPRBus *bus; + BusState *qbus; + DeviceState *dev; + + /* Create bridge device */ + dev = qdev_create(NULL, "spapr-vio-bridge"); + qdev_init_nofail(dev); + + /* Create bus on bridge device */ + + qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); + bus = DO_UPCAST(VIOsPAPRBus, bus, qbus); + bus->next_reg = 0x71000000; + + /* hcall-vio */ + spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); + + /* hcall-crq */ + spapr_register_hypercall(H_REG_CRQ, h_reg_crq); + spapr_register_hypercall(H_FREE_CRQ, h_free_crq); + spapr_register_hypercall(H_SEND_CRQ, h_send_crq); + spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); + + /* RTAS calls */ + spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass); + spapr_rtas_register("quiesce", rtas_quiesce); + + return bus; +} + +/* Represents sPAPR hcall VIO devices */ + +static int spapr_vio_bridge_init(SysBusDevice *dev) +{ + /* nothing */ + return 0; +} + +static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = spapr_vio_bridge_init; + dc->no_user = 1; +} + +static const TypeInfo spapr_vio_bridge_info = { + .name = "spapr-vio-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = spapr_vio_bridge_class_init, +}; + +static void vio_spapr_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = spapr_vio_busdev_init; + k->reset = spapr_vio_busdev_reset; + k->bus_type = TYPE_SPAPR_VIO_BUS; + k->props = spapr_vio_props; +} + +static const TypeInfo spapr_vio_type_info = { + .name = TYPE_VIO_SPAPR_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VIOsPAPRDevice), + .abstract = true, + .class_size = sizeof(VIOsPAPRDeviceClass), + .class_init = vio_spapr_device_class_init, +}; + +static void spapr_vio_register_types(void) +{ + type_register_static(&spapr_vio_bus_info); + type_register_static(&spapr_vio_bridge_info); + type_register_static(&spapr_vio_type_info); +} + +type_init(spapr_vio_register_types) + +#ifdef CONFIG_FDT +static int compare_reg(const void *p1, const void *p2) +{ + VIOsPAPRDevice const *dev1, *dev2; + + dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1; + dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2; + + if (dev1->reg < dev2->reg) { + return -1; + } + if (dev1->reg == dev2->reg) { + return 0; + } + + /* dev1->reg > dev2->reg */ + return 1; +} + +int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt) +{ + DeviceState *qdev, **qdevs; + BusChild *kid; + int i, num, ret = 0; + + /* Count qdevs on the bus list */ + num = 0; + QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { + num++; + } + + /* Copy out into an array of pointers */ + qdevs = g_malloc(sizeof(qdev) * num); + num = 0; + QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { + qdevs[num++] = kid->child; + } + + /* Sort the array */ + qsort(qdevs, num, sizeof(qdev), compare_reg); + + /* Hack alert. Give the devices to libfdt in reverse order, we happen + * to know that will mean they are in forward order in the tree. */ + for (i = num - 1; i >= 0; i--) { + VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]); + + ret = vio_make_devnode(dev, fdt); + + if (ret < 0) { + goto out; + } + } + + ret = 0; +out: + free(qdevs); + + return ret; +} + +int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus) +{ + VIOsPAPRDevice *dev; + char *name, *path; + int ret, offset; + + dev = spapr_vty_get_default(bus); + if (!dev) + return 0; + + offset = fdt_path_offset(fdt, "/chosen"); + if (offset < 0) { + return offset; + } + + name = vio_format_dev_name(dev); + path = g_strdup_printf("/vdevice/%s", name); + + ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path); + + g_free(name); + g_free(path); + + return ret; +} +#endif /* CONFIG_FDT */ diff --git a/hw/ppc/xics.c b/hw/ppc/xics.c new file mode 100644 index 0000000000..c3ef12fff4 --- /dev/null +++ b/hw/ppc/xics.c @@ -0,0 +1,588 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics + * + * Copyright (c) 2010,2011 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "hw/hw.h" +#include "trace.h" +#include "hw/spapr.h" +#include "hw/xics.h" + +/* + * ICP: Presentation layer + */ + +struct icp_server_state { + uint32_t xirr; + uint8_t pending_priority; + uint8_t mfrr; + qemu_irq output; +}; + +#define XISR_MASK 0x00ffffff +#define CPPR_MASK 0xff000000 + +#define XISR(ss) (((ss)->xirr) & XISR_MASK) +#define CPPR(ss) (((ss)->xirr) >> 24) + +struct ics_state; + +struct icp_state { + long nr_servers; + struct icp_server_state *ss; + struct ics_state *ics; +}; + +static void ics_reject(struct ics_state *ics, int nr); +static void ics_resend(struct ics_state *ics); +static void ics_eoi(struct ics_state *ics, int nr); + +static void icp_check_ipi(struct icp_state *icp, int server) +{ + struct icp_server_state *ss = icp->ss + server; + + if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { + return; + } + + trace_xics_icp_check_ipi(server, ss->mfrr); + + if (XISR(ss)) { + ics_reject(icp->ics, XISR(ss)); + } + + ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; + ss->pending_priority = ss->mfrr; + qemu_irq_raise(ss->output); +} + +static void icp_resend(struct icp_state *icp, int server) +{ + struct icp_server_state *ss = icp->ss + server; + + if (ss->mfrr < CPPR(ss)) { + icp_check_ipi(icp, server); + } + ics_resend(icp->ics); +} + +static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) +{ + struct icp_server_state *ss = icp->ss + server; + uint8_t old_cppr; + uint32_t old_xisr; + + old_cppr = CPPR(ss); + ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24); + + if (cppr < old_cppr) { + if (XISR(ss) && (cppr <= ss->pending_priority)) { + old_xisr = XISR(ss); + ss->xirr &= ~XISR_MASK; /* Clear XISR */ + qemu_irq_lower(ss->output); + ics_reject(icp->ics, old_xisr); + } + } else { + if (!XISR(ss)) { + icp_resend(icp, server); + } + } +} + +static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr) +{ + struct icp_server_state *ss = icp->ss + server; + + ss->mfrr = mfrr; + if (mfrr < CPPR(ss)) { + icp_check_ipi(icp, server); + } +} + +static uint32_t icp_accept(struct icp_server_state *ss) +{ + uint32_t xirr = ss->xirr; + + qemu_irq_lower(ss->output); + ss->xirr = ss->pending_priority << 24; + + trace_xics_icp_accept(xirr, ss->xirr); + + return xirr; +} + +static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) +{ + struct icp_server_state *ss = icp->ss + server; + + /* Send EOI -> ICS */ + ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); + trace_xics_icp_eoi(server, xirr, ss->xirr); + ics_eoi(icp->ics, xirr & XISR_MASK); + if (!XISR(ss)) { + icp_resend(icp, server); + } +} + +static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) +{ + struct icp_server_state *ss = icp->ss + server; + + trace_xics_icp_irq(server, nr, priority); + + if ((priority >= CPPR(ss)) + || (XISR(ss) && (ss->pending_priority <= priority))) { + ics_reject(icp->ics, nr); + } else { + if (XISR(ss)) { + ics_reject(icp->ics, XISR(ss)); + } + ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); + ss->pending_priority = priority; + trace_xics_icp_raise(ss->xirr, ss->pending_priority); + qemu_irq_raise(ss->output); + } +} + +/* + * ICS: Source layer + */ + +struct ics_irq_state { + int server; + uint8_t priority; + uint8_t saved_priority; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; +}; + +struct ics_state { + int nr_irqs; + int offset; + qemu_irq *qirqs; + bool *islsi; + struct ics_irq_state *irqs; + struct icp_state *icp; +}; + +static int ics_valid_irq(struct ics_state *ics, uint32_t nr) +{ + return (nr >= ics->offset) + && (nr < (ics->offset + ics->nr_irqs)); +} + +static void resend_msi(struct ics_state *ics, int srcno) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + /* FIXME: filter by server#? */ + if (irq->status & XICS_STATUS_REJECTED) { + irq->status &= ~XICS_STATUS_REJECTED; + if (irq->priority != 0xff) { + icp_irq(ics->icp, irq->server, srcno + ics->offset, + irq->priority); + } + } +} + +static void resend_lsi(struct ics_state *ics, int srcno) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + if ((irq->priority != 0xff) + && (irq->status & XICS_STATUS_ASSERTED) + && !(irq->status & XICS_STATUS_SENT)) { + irq->status |= XICS_STATUS_SENT; + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); + } +} + +static void set_irq_msi(struct ics_state *ics, int srcno, int val) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + trace_xics_set_irq_msi(srcno, srcno + ics->offset); + + if (val) { + if (irq->priority == 0xff) { + irq->status |= XICS_STATUS_MASKED_PENDING; + trace_xics_masked_pending(); + } else { + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); + } + } +} + +static void set_irq_lsi(struct ics_state *ics, int srcno, int val) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + trace_xics_set_irq_lsi(srcno, srcno + ics->offset); + if (val) { + irq->status |= XICS_STATUS_ASSERTED; + } else { + irq->status &= ~XICS_STATUS_ASSERTED; + } + resend_lsi(ics, srcno); +} + +static void ics_set_irq(void *opaque, int srcno, int val) +{ + struct ics_state *ics = (struct ics_state *)opaque; + + if (ics->islsi[srcno]) { + set_irq_lsi(ics, srcno, val); + } else { + set_irq_msi(ics, srcno, val); + } +} + +static void write_xive_msi(struct ics_state *ics, int srcno) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + if (!(irq->status & XICS_STATUS_MASKED_PENDING) + || (irq->priority == 0xff)) { + return; + } + + irq->status &= ~XICS_STATUS_MASKED_PENDING; + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); +} + +static void write_xive_lsi(struct ics_state *ics, int srcno) +{ + resend_lsi(ics, srcno); +} + +static void ics_write_xive(struct ics_state *ics, int nr, int server, + uint8_t priority, uint8_t saved_priority) +{ + int srcno = nr - ics->offset; + struct ics_irq_state *irq = ics->irqs + srcno; + + irq->server = server; + irq->priority = priority; + irq->saved_priority = saved_priority; + + trace_xics_ics_write_xive(nr, srcno, server, priority); + + if (ics->islsi[srcno]) { + write_xive_lsi(ics, srcno); + } else { + write_xive_msi(ics, srcno); + } +} + +static void ics_reject(struct ics_state *ics, int nr) +{ + struct ics_irq_state *irq = ics->irqs + nr - ics->offset; + + trace_xics_ics_reject(nr, nr - ics->offset); + irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ + irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ +} + +static void ics_resend(struct ics_state *ics) +{ + int i; + + for (i = 0; i < ics->nr_irqs; i++) { + /* FIXME: filter by server#? */ + if (ics->islsi[i]) { + resend_lsi(ics, i); + } else { + resend_msi(ics, i); + } + } +} + +static void ics_eoi(struct ics_state *ics, int nr) +{ + int srcno = nr - ics->offset; + struct ics_irq_state *irq = ics->irqs + srcno; + + trace_xics_ics_eoi(nr); + + if (ics->islsi[srcno]) { + irq->status &= ~XICS_STATUS_SENT; + } +} + +/* + * Exported functions + */ + +qemu_irq xics_get_qirq(struct icp_state *icp, int irq) +{ + if (!ics_valid_irq(icp->ics, irq)) { + return NULL; + } + + return icp->ics->qirqs[irq - icp->ics->offset]; +} + +void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) +{ + assert(ics_valid_irq(icp->ics, irq)); + + icp->ics->islsi[irq - icp->ics->offset] = lsi; +} + +static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + target_ulong cppr = args[0]; + + icp_set_cppr(spapr->icp, cs->cpu_index, cppr); + return H_SUCCESS; +} + +static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong server = args[0]; + target_ulong mfrr = args[1]; + + if (server >= spapr->icp->nr_servers) { + return H_PARAMETER; + } + + icp_set_mfrr(spapr->icp, server, mfrr); + return H_SUCCESS; +} + +static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); + + args[0] = xirr; + return H_SUCCESS; +} + +static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + target_ulong xirr = args[0]; + + icp_eoi(spapr->icp, cs->cpu_index, xirr); + return H_SUCCESS; +} + +static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr, server, priority; + + if ((nargs != 3) || (nret != 1)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + server = rtas_ld(args, 1); + priority = rtas_ld(args, 2); + + if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) + || (priority > 0xff)) { + rtas_st(rets, 0, -3); + return; + } + + ics_write_xive(ics, nr, server, priority, priority); + + rtas_st(rets, 0, 0); /* Success */ +} + +static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 3)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, -3); + return; + } + + rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); + rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); +} + +static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, -3); + return; + } + + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, + ics->irqs[nr - ics->offset].priority); + + rtas_st(rets, 0, 0); /* Success */ +} + +static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, -3); + return; + } + + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, + ics->irqs[nr - ics->offset].saved_priority, + ics->irqs[nr - ics->offset].saved_priority); + + rtas_st(rets, 0, 0); /* Success */ +} + +static void xics_reset(void *opaque) +{ + struct icp_state *icp = (struct icp_state *)opaque; + struct ics_state *ics = icp->ics; + int i; + + for (i = 0; i < icp->nr_servers; i++) { + icp->ss[i].xirr = 0; + icp->ss[i].pending_priority = 0xff; + icp->ss[i].mfrr = 0xff; + /* Make all outputs are deasserted */ + qemu_set_irq(icp->ss[i].output, 0); + } + + memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs); + for (i = 0; i < ics->nr_irqs; i++) { + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } +} + +struct icp_state *xics_system_init(int nr_irqs) +{ + CPUPPCState *env; + CPUState *cpu; + int max_server_num; + struct icp_state *icp; + struct ics_state *ics; + + max_server_num = -1; + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index > max_server_num) { + max_server_num = cpu->cpu_index; + } + } + + icp = g_malloc0(sizeof(*icp)); + icp->nr_servers = max_server_num + 1; + icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = CPU(ppc_env_get_cpu(env)); + struct icp_server_state *ss = &icp->ss[cpu->cpu_index]; + + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_POWER7: + ss->output = env->irq_inputs[POWER7_INPUT_INT]; + break; + + case PPC_FLAGS_INPUT_970: + ss->output = env->irq_inputs[PPC970_INPUT_INT]; + break; + + default: + hw_error("XICS interrupt model does not support this CPU bus " + "model\n"); + exit(1); + } + } + + ics = g_malloc0(sizeof(*ics)); + ics->nr_irqs = nr_irqs; + ics->offset = XICS_IRQ_BASE; + ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state)); + ics->islsi = g_malloc0(nr_irqs * sizeof(bool)); + + icp->ics = ics; + ics->icp = icp; + + ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); + + spapr_register_hypercall(H_CPPR, h_cppr); + spapr_register_hypercall(H_IPI, h_ipi); + spapr_register_hypercall(H_XIRR, h_xirr); + spapr_register_hypercall(H_EOI, h_eoi); + + spapr_rtas_register("ibm,set-xive", rtas_set_xive); + spapr_rtas_register("ibm,get-xive", rtas_get_xive); + spapr_rtas_register("ibm,int-off", rtas_int_off); + spapr_rtas_register("ibm,int-on", rtas_int_on); + + qemu_register_reset(xics_reset, icp); + + return icp; +} diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c deleted file mode 100644 index 49ec728a7b..0000000000 --- a/hw/ppc4xx_devs.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * QEMU PowerPC 4xx embedded processors shared devices emulation - * - * Copyright (c) 2007 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/ppc.h" -#include "hw/ppc4xx.h" -#include "qemu/log.h" -#include "exec/address-spaces.h" - -//#define DEBUG_MMIO -//#define DEBUG_UNASSIGNED -#define DEBUG_UIC - - -#ifdef DEBUG_UIC -# define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) -#else -# define LOG_UIC(...) do { } while (0) -#endif - -static void ppc4xx_reset(void *opaque) -{ - PowerPCCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -/*****************************************************************************/ -/* Generic PowerPC 4xx processor instantiation */ -PowerPCCPU *ppc4xx_init(const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - - /* init CPUs */ - cpu = cpu_ppc_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find PowerPC %s CPU definition\n", - cpu_model); - exit(1); - } - env = &cpu->env; - - cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ - cpu_clk->opaque = env; - /* Set time-base frequency to sysclk */ - tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT); - tb_clk->opaque = env; - ppc_dcr_init(env, NULL, NULL); - /* Register qemu callbacks */ - qemu_register_reset(ppc4xx_reset, cpu); - - return cpu; -} - -/*****************************************************************************/ -/* "Universal" Interrupt controller */ -enum { - DCR_UICSR = 0x000, - DCR_UICSRS = 0x001, - DCR_UICER = 0x002, - DCR_UICCR = 0x003, - DCR_UICPR = 0x004, - DCR_UICTR = 0x005, - DCR_UICMSR = 0x006, - DCR_UICVR = 0x007, - DCR_UICVCR = 0x008, - DCR_UICMAX = 0x009, -}; - -#define UIC_MAX_IRQ 32 -typedef struct ppcuic_t ppcuic_t; -struct ppcuic_t { - uint32_t dcr_base; - int use_vectors; - uint32_t level; /* Remembers the state of level-triggered interrupts. */ - uint32_t uicsr; /* Status register */ - uint32_t uicer; /* Enable register */ - uint32_t uiccr; /* Critical register */ - uint32_t uicpr; /* Polarity register */ - uint32_t uictr; /* Triggering register */ - uint32_t uicvcr; /* Vector configuration register */ - uint32_t uicvr; - qemu_irq *irqs; -}; - -static void ppcuic_trigger_irq (ppcuic_t *uic) -{ - uint32_t ir, cr; - int start, end, inc, i; - - /* Trigger interrupt if any is pending */ - ir = uic->uicsr & uic->uicer & (~uic->uiccr); - cr = uic->uicsr & uic->uicer & uic->uiccr; - LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32 - " uiccr %08" PRIx32 "\n" - " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", - __func__, uic->uicsr, uic->uicer, uic->uiccr, - uic->uicsr & uic->uicer, ir, cr); - if (ir != 0x0000000) { - LOG_UIC("Raise UIC interrupt\n"); - qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); - } else { - LOG_UIC("Lower UIC interrupt\n"); - qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); - } - /* Trigger critical interrupt if any is pending and update vector */ - if (cr != 0x0000000) { - qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); - if (uic->use_vectors) { - /* Compute critical IRQ vector */ - if (uic->uicvcr & 1) { - start = 31; - end = 0; - inc = -1; - } else { - start = 0; - end = 31; - inc = 1; - } - uic->uicvr = uic->uicvcr & 0xFFFFFFFC; - for (i = start; i <= end; i += inc) { - if (cr & (1 << i)) { - uic->uicvr += (i - start) * 512 * inc; - break; - } - } - } - LOG_UIC("Raise UIC critical interrupt - " - "vector %08" PRIx32 "\n", uic->uicvr); - } else { - LOG_UIC("Lower UIC critical interrupt\n"); - qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); - uic->uicvr = 0x00000000; - } -} - -static void ppcuic_set_irq (void *opaque, int irq_num, int level) -{ - ppcuic_t *uic; - uint32_t mask, sr; - - uic = opaque; - mask = 1 << (31-irq_num); - LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 - " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", - __func__, irq_num, level, - uic->uicsr, mask, uic->uicsr & mask, level << irq_num); - if (irq_num < 0 || irq_num > 31) - return; - sr = uic->uicsr; - - /* Update status register */ - if (uic->uictr & mask) { - /* Edge sensitive interrupt */ - if (level == 1) - uic->uicsr |= mask; - } else { - /* Level sensitive interrupt */ - if (level == 1) { - uic->uicsr |= mask; - uic->level |= mask; - } else { - uic->uicsr &= ~mask; - uic->level &= ~mask; - } - } - LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => " - "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); - if (sr != uic->uicsr) - ppcuic_trigger_irq(uic); -} - -static uint32_t dcr_read_uic (void *opaque, int dcrn) -{ - ppcuic_t *uic; - uint32_t ret; - - uic = opaque; - dcrn -= uic->dcr_base; - switch (dcrn) { - case DCR_UICSR: - case DCR_UICSRS: - ret = uic->uicsr; - break; - case DCR_UICER: - ret = uic->uicer; - break; - case DCR_UICCR: - ret = uic->uiccr; - break; - case DCR_UICPR: - ret = uic->uicpr; - break; - case DCR_UICTR: - ret = uic->uictr; - break; - case DCR_UICMSR: - ret = uic->uicsr & uic->uicer; - break; - case DCR_UICVR: - if (!uic->use_vectors) - goto no_read; - ret = uic->uicvr; - break; - case DCR_UICVCR: - if (!uic->use_vectors) - goto no_read; - ret = uic->uicvcr; - break; - default: - no_read: - ret = 0x00000000; - break; - } - - return ret; -} - -static void dcr_write_uic (void *opaque, int dcrn, uint32_t val) -{ - ppcuic_t *uic; - - uic = opaque; - dcrn -= uic->dcr_base; - LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val); - switch (dcrn) { - case DCR_UICSR: - uic->uicsr &= ~val; - uic->uicsr |= uic->level; - ppcuic_trigger_irq(uic); - break; - case DCR_UICSRS: - uic->uicsr |= val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICER: - uic->uicer = val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICCR: - uic->uiccr = val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICPR: - uic->uicpr = val; - break; - case DCR_UICTR: - uic->uictr = val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICMSR: - break; - case DCR_UICVR: - break; - case DCR_UICVCR: - uic->uicvcr = val & 0xFFFFFFFD; - ppcuic_trigger_irq(uic); - break; - } -} - -static void ppcuic_reset (void *opaque) -{ - ppcuic_t *uic; - - uic = opaque; - uic->uiccr = 0x00000000; - uic->uicer = 0x00000000; - uic->uicpr = 0x00000000; - uic->uicsr = 0x00000000; - uic->uictr = 0x00000000; - if (uic->use_vectors) { - uic->uicvcr = 0x00000000; - uic->uicvr = 0x0000000; - } -} - -qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, - uint32_t dcr_base, int has_ssr, int has_vr) -{ - ppcuic_t *uic; - int i; - - uic = g_malloc0(sizeof(ppcuic_t)); - uic->dcr_base = dcr_base; - uic->irqs = irqs; - if (has_vr) - uic->use_vectors = 1; - for (i = 0; i < DCR_UICMAX; i++) { - ppc_dcr_register(env, dcr_base + i, uic, - &dcr_read_uic, &dcr_write_uic); - } - qemu_register_reset(ppcuic_reset, uic); - - return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); -} - -/*****************************************************************************/ -/* SDRAM controller */ -typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; -struct ppc4xx_sdram_t { - uint32_t addr; - int nbanks; - MemoryRegion containers[4]; /* used for clipping */ - MemoryRegion *ram_memories; - hwaddr ram_bases[4]; - hwaddr ram_sizes[4]; - uint32_t besr0; - uint32_t besr1; - uint32_t bear; - uint32_t cfg; - uint32_t status; - uint32_t rtr; - uint32_t pmit; - uint32_t bcr[4]; - uint32_t tr; - uint32_t ecccfg; - uint32_t eccesr; - qemu_irq irq; -}; - -enum { - SDRAM0_CFGADDR = 0x010, - SDRAM0_CFGDATA = 0x011, -}; - -/* XXX: TOFIX: some patches have made this code become inconsistent: - * there are type inconsistencies, mixing hwaddr, target_ulong - * and uint32_t - */ -static uint32_t sdram_bcr (hwaddr ram_base, - hwaddr ram_size) -{ - uint32_t bcr; - - switch (ram_size) { - case (4 * 1024 * 1024): - bcr = 0x00000000; - break; - case (8 * 1024 * 1024): - bcr = 0x00020000; - break; - case (16 * 1024 * 1024): - bcr = 0x00040000; - break; - case (32 * 1024 * 1024): - bcr = 0x00060000; - break; - case (64 * 1024 * 1024): - bcr = 0x00080000; - break; - case (128 * 1024 * 1024): - bcr = 0x000A0000; - break; - case (256 * 1024 * 1024): - bcr = 0x000C0000; - break; - default: - printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__, - ram_size); - return 0x00000000; - } - bcr |= ram_base & 0xFF800000; - bcr |= 1; - - return bcr; -} - -static inline hwaddr sdram_base(uint32_t bcr) -{ - return bcr & 0xFF800000; -} - -static target_ulong sdram_size (uint32_t bcr) -{ - target_ulong size; - int sh; - - sh = (bcr >> 17) & 0x7; - if (sh == 7) - size = -1; - else - size = (4 * 1024 * 1024) << sh; - - return size; -} - -static void sdram_set_bcr(ppc4xx_sdram_t *sdram, - uint32_t *bcrp, uint32_t bcr, int enabled) -{ - unsigned n = bcrp - sdram->bcr; - - if (*bcrp & 0x00000001) { - /* Unmap RAM */ -#ifdef DEBUG_SDRAM - printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", - __func__, sdram_base(*bcrp), sdram_size(*bcrp)); -#endif - memory_region_del_subregion(get_system_memory(), - &sdram->containers[n]); - memory_region_del_subregion(&sdram->containers[n], - &sdram->ram_memories[n]); - memory_region_destroy(&sdram->containers[n]); - } - *bcrp = bcr & 0xFFDEE001; - if (enabled && (bcr & 0x00000001)) { -#ifdef DEBUG_SDRAM - printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", - __func__, sdram_base(bcr), sdram_size(bcr)); -#endif - memory_region_init(&sdram->containers[n], "sdram-containers", - sdram_size(bcr)); - memory_region_add_subregion(&sdram->containers[n], 0, - &sdram->ram_memories[n]); - memory_region_add_subregion(get_system_memory(), - sdram_base(bcr), - &sdram->containers[n]); - } -} - -static void sdram_map_bcr (ppc4xx_sdram_t *sdram) -{ - int i; - - for (i = 0; i < sdram->nbanks; i++) { - if (sdram->ram_sizes[i] != 0) { - sdram_set_bcr(sdram, - &sdram->bcr[i], - sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]), - 1); - } else { - sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0); - } - } -} - -static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) -{ - int i; - - for (i = 0; i < sdram->nbanks; i++) { -#ifdef DEBUG_SDRAM - printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", - __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); -#endif - memory_region_del_subregion(get_system_memory(), - &sdram->ram_memories[i]); - } -} - -static uint32_t dcr_read_sdram (void *opaque, int dcrn) -{ - ppc4xx_sdram_t *sdram; - uint32_t ret; - - sdram = opaque; - switch (dcrn) { - case SDRAM0_CFGADDR: - ret = sdram->addr; - break; - case SDRAM0_CFGDATA: - switch (sdram->addr) { - case 0x00: /* SDRAM_BESR0 */ - ret = sdram->besr0; - break; - case 0x08: /* SDRAM_BESR1 */ - ret = sdram->besr1; - break; - case 0x10: /* SDRAM_BEAR */ - ret = sdram->bear; - break; - case 0x20: /* SDRAM_CFG */ - ret = sdram->cfg; - break; - case 0x24: /* SDRAM_STATUS */ - ret = sdram->status; - break; - case 0x30: /* SDRAM_RTR */ - ret = sdram->rtr; - break; - case 0x34: /* SDRAM_PMIT */ - ret = sdram->pmit; - break; - case 0x40: /* SDRAM_B0CR */ - ret = sdram->bcr[0]; - break; - case 0x44: /* SDRAM_B1CR */ - ret = sdram->bcr[1]; - break; - case 0x48: /* SDRAM_B2CR */ - ret = sdram->bcr[2]; - break; - case 0x4C: /* SDRAM_B3CR */ - ret = sdram->bcr[3]; - break; - case 0x80: /* SDRAM_TR */ - ret = -1; /* ? */ - break; - case 0x94: /* SDRAM_ECCCFG */ - ret = sdram->ecccfg; - break; - case 0x98: /* SDRAM_ECCESR */ - ret = sdram->eccesr; - break; - default: /* Error */ - ret = -1; - break; - } - break; - default: - /* Avoid gcc warning */ - ret = 0x00000000; - break; - } - - return ret; -} - -static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) -{ - ppc4xx_sdram_t *sdram; - - sdram = opaque; - switch (dcrn) { - case SDRAM0_CFGADDR: - sdram->addr = val; - break; - case SDRAM0_CFGDATA: - switch (sdram->addr) { - case 0x00: /* SDRAM_BESR0 */ - sdram->besr0 &= ~val; - break; - case 0x08: /* SDRAM_BESR1 */ - sdram->besr1 &= ~val; - break; - case 0x10: /* SDRAM_BEAR */ - sdram->bear = val; - break; - case 0x20: /* SDRAM_CFG */ - val &= 0xFFE00000; - if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { -#ifdef DEBUG_SDRAM - printf("%s: enable SDRAM controller\n", __func__); -#endif - /* validate all RAM mappings */ - sdram_map_bcr(sdram); - sdram->status &= ~0x80000000; - } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { -#ifdef DEBUG_SDRAM - printf("%s: disable SDRAM controller\n", __func__); -#endif - /* invalidate all RAM mappings */ - sdram_unmap_bcr(sdram); - sdram->status |= 0x80000000; - } - if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) - sdram->status |= 0x40000000; - else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) - sdram->status &= ~0x40000000; - sdram->cfg = val; - break; - case 0x24: /* SDRAM_STATUS */ - /* Read-only register */ - break; - case 0x30: /* SDRAM_RTR */ - sdram->rtr = val & 0x3FF80000; - break; - case 0x34: /* SDRAM_PMIT */ - sdram->pmit = (val & 0xF8000000) | 0x07C00000; - break; - case 0x40: /* SDRAM_B0CR */ - sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000); - break; - case 0x44: /* SDRAM_B1CR */ - sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000); - break; - case 0x48: /* SDRAM_B2CR */ - sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000); - break; - case 0x4C: /* SDRAM_B3CR */ - sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000); - break; - case 0x80: /* SDRAM_TR */ - sdram->tr = val & 0x018FC01F; - break; - case 0x94: /* SDRAM_ECCCFG */ - sdram->ecccfg = val & 0x00F00000; - break; - case 0x98: /* SDRAM_ECCESR */ - val &= 0xFFF0F000; - if (sdram->eccesr == 0 && val != 0) - qemu_irq_raise(sdram->irq); - else if (sdram->eccesr != 0 && val == 0) - qemu_irq_lower(sdram->irq); - sdram->eccesr = val; - break; - default: /* Error */ - break; - } - break; - } -} - -static void sdram_reset (void *opaque) -{ - ppc4xx_sdram_t *sdram; - - sdram = opaque; - sdram->addr = 0x00000000; - sdram->bear = 0x00000000; - sdram->besr0 = 0x00000000; /* No error */ - sdram->besr1 = 0x00000000; /* No error */ - sdram->cfg = 0x00000000; - sdram->ecccfg = 0x00000000; /* No ECC */ - sdram->eccesr = 0x00000000; /* No error */ - sdram->pmit = 0x07C00000; - sdram->rtr = 0x05F00000; - sdram->tr = 0x00854009; - /* We pre-initialize RAM banks */ - sdram->status = 0x00000000; - sdram->cfg = 0x00800000; -} - -void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, - MemoryRegion *ram_memories, - hwaddr *ram_bases, - hwaddr *ram_sizes, - int do_init) -{ - ppc4xx_sdram_t *sdram; - - sdram = g_malloc0(sizeof(ppc4xx_sdram_t)); - sdram->irq = irq; - sdram->nbanks = nbanks; - sdram->ram_memories = ram_memories; - memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); - memcpy(sdram->ram_bases, ram_bases, - nbanks * sizeof(hwaddr)); - memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); - memcpy(sdram->ram_sizes, ram_sizes, - nbanks * sizeof(hwaddr)); - qemu_register_reset(&sdram_reset, sdram); - ppc_dcr_register(env, SDRAM0_CFGADDR, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM0_CFGDATA, - sdram, &dcr_read_sdram, &dcr_write_sdram); - if (do_init) - sdram_map_bcr(sdram); -} - -/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. - * - * sdram_bank_sizes[] must be 0-terminated. - * - * The 4xx SDRAM controller supports a small number of banks, and each bank - * must be one of a small set of sizes. The number of banks and the supported - * sizes varies by SoC. */ -ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, - MemoryRegion ram_memories[], - hwaddr ram_bases[], - hwaddr ram_sizes[], - const unsigned int sdram_bank_sizes[]) -{ - ram_addr_t size_left = ram_size; - ram_addr_t base = 0; - int i; - int j; - - for (i = 0; i < nr_banks; i++) { - for (j = 0; sdram_bank_sizes[j] != 0; j++) { - unsigned int bank_size = sdram_bank_sizes[j]; - - if (bank_size <= size_left) { - char name[32]; - snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); - memory_region_init_ram(&ram_memories[i], name, bank_size); - vmstate_register_ram_global(&ram_memories[i]); - ram_bases[i] = base; - ram_sizes[i] = bank_size; - base += bank_size; - size_left -= bank_size; - break; - } - } - - if (!size_left) { - /* No need to use the remaining banks. */ - break; - } - } - - ram_size -= size_left; - if (size_left) - printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n", - (int)(ram_size >> 20)); - - return ram_size; -} diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c deleted file mode 100644 index d904fbe176..0000000000 --- a/hw/ppce500_spin.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * QEMU PowerPC e500v2 ePAPR spinning code - * - * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: Alexander Graf, - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * This code is not really a device, but models an interface that usually - * firmware takes care of. It's used when QEMU plays the role of firmware. - * - * Specification: - * - * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf - * - */ - -#include "hw/hw.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "sysemu/kvm.h" - -#define MAX_CPUS 32 - -typedef struct spin_info { - uint64_t addr; - uint64_t r3; - uint32_t resv; - uint32_t pir; - uint64_t reserved; -} QEMU_PACKED SpinInfo; - -typedef struct spin_state { - SysBusDevice busdev; - MemoryRegion iomem; - SpinInfo spin[MAX_CPUS]; -} SpinState; - -typedef struct spin_kick { - PowerPCCPU *cpu; - SpinInfo *spin; -} SpinKick; - -static void spin_reset(void *opaque) -{ - SpinState *s = opaque; - int i; - - for (i = 0; i < MAX_CPUS; i++) { - SpinInfo *info = &s->spin[i]; - - info->pir = i; - info->r3 = i; - info->addr = 1; - } -} - -/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ -static inline hwaddr booke206_page_size_to_tlb(uint64_t size) -{ - return (ffs(size >> 10) - 1) >> 1; -} - -static void mmubooke_create_initial_mapping(CPUPPCState *env, - target_ulong va, - hwaddr pa, - hwaddr len) -{ - ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1); - hwaddr size; - - size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT); - tlb->mas1 = MAS1_VALID | size; - tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M; - tlb->mas7_3 = pa & TARGET_PAGE_MASK; - tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; - env->tlb_dirty = true; -} - -static void spin_kick(void *data) -{ - SpinKick *kick = data; - CPUState *cpu = CPU(kick->cpu); - CPUPPCState *env = &kick->cpu->env; - SpinInfo *curspin = kick->spin; - hwaddr map_size = 64 * 1024 * 1024; - hwaddr map_start; - - cpu_synchronize_state(env); - stl_p(&curspin->pir, env->spr[SPR_PIR]); - env->nip = ldq_p(&curspin->addr) & (map_size - 1); - env->gpr[3] = ldq_p(&curspin->r3); - env->gpr[4] = 0; - env->gpr[5] = 0; - env->gpr[6] = 0; - env->gpr[7] = map_size; - env->gpr[8] = 0; - env->gpr[9] = 0; - - map_start = ldq_p(&curspin->addr) & ~(map_size - 1); - mmubooke_create_initial_mapping(env, 0, map_start, map_size); - - env->halted = 0; - env->exception_index = -1; - cpu->stopped = false; - qemu_cpu_kick(cpu); -} - -static void spin_write(void *opaque, hwaddr addr, uint64_t value, - unsigned len) -{ - SpinState *s = opaque; - int env_idx = addr / sizeof(SpinInfo); - CPUState *cpu; - SpinInfo *curspin = &s->spin[env_idx]; - uint8_t *curspin_p = (uint8_t*)curspin; - - cpu = qemu_get_cpu(env_idx); - if (cpu == NULL) { - /* Unknown CPU */ - return; - } - - if (cpu->cpu_index == 0) { - /* primary CPU doesn't spin */ - return; - } - - curspin_p = &curspin_p[addr % sizeof(SpinInfo)]; - switch (len) { - case 1: - stb_p(curspin_p, value); - break; - case 2: - stw_p(curspin_p, value); - break; - case 4: - stl_p(curspin_p, value); - break; - } - - if (!(ldq_p(&curspin->addr) & 1)) { - /* run CPU */ - SpinKick kick = { - .cpu = POWERPC_CPU(cpu), - .spin = curspin, - }; - - run_on_cpu(cpu, spin_kick, &kick); - } -} - -static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len) -{ - SpinState *s = opaque; - uint8_t *spin_p = &((uint8_t*)s->spin)[addr]; - - switch (len) { - case 1: - return ldub_p(spin_p); - case 2: - return lduw_p(spin_p); - case 4: - return ldl_p(spin_p); - default: - hw_error("ppce500: unexpected %s with len = %u", __func__, len); - } -} - -static const MemoryRegionOps spin_rw_ops = { - .read = spin_read, - .write = spin_write, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static int ppce500_spin_initfn(SysBusDevice *dev) -{ - SpinState *s; - - s = FROM_SYSBUS(SpinState, SYS_BUS_DEVICE(dev)); - - memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device", - sizeof(SpinInfo) * MAX_CPUS); - sysbus_init_mmio(dev, &s->iomem); - - qemu_register_reset(spin_reset, s); - - return 0; -} - -static void ppce500_spin_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = ppce500_spin_initfn; -} - -static const TypeInfo ppce500_spin_info = { - .name = "e500-spin", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SpinState), - .class_init = ppce500_spin_class_init, -}; - -static void ppce500_spin_register_types(void) -{ - type_register_static(&ppce500_spin_info); -} - -type_init(ppce500_spin_register_types) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c deleted file mode 100644 index 6eb3ab5482..0000000000 --- a/hw/spapr_vio.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * QEMU sPAPR VIO code - * - * Copyright (c) 2010 David Gibson, IBM Corporation - * Based on the s390 virtio bus code: - * Copyright (c) 2009 Alexander Graf - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/hw.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "monitor/monitor.h" -#include "hw/loader.h" -#include "elf.h" -#include "hw/sysbus.h" -#include "sysemu/kvm.h" -#include "sysemu/device_tree.h" -#include "kvm_ppc.h" - -#include "hw/spapr.h" -#include "hw/spapr_vio.h" -#include "hw/xics.h" - -#ifdef CONFIG_FDT -#include -#endif /* CONFIG_FDT */ - -/* #define DEBUG_SPAPR */ - -#ifdef DEBUG_SPAPR -#define dprintf(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define dprintf(fmt, ...) \ - do { } while (0) -#endif - -static Property spapr_vio_props[] = { - DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \ - DEFINE_PROP_END_OF_LIST(), -}; - -static const TypeInfo spapr_vio_bus_info = { - .name = TYPE_SPAPR_VIO_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(VIOsPAPRBus), -}; - -VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) -{ - BusChild *kid; - VIOsPAPRDevice *dev = NULL; - - QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { - dev = (VIOsPAPRDevice *)kid->child; - if (dev->reg == reg) { - return dev; - } - } - - return NULL; -} - -static char *vio_format_dev_name(VIOsPAPRDevice *dev) -{ - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - char *name; - - /* Device tree style name device@reg */ - name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg); - - return name; -} - -#ifdef CONFIG_FDT -static int vio_make_devnode(VIOsPAPRDevice *dev, - void *fdt) -{ - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - int vdevice_off, node_off, ret; - char *dt_name; - - vdevice_off = fdt_path_offset(fdt, "/vdevice"); - if (vdevice_off < 0) { - return vdevice_off; - } - - dt_name = vio_format_dev_name(dev); - node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); - g_free(dt_name); - if (node_off < 0) { - return node_off; - } - - ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg); - if (ret < 0) { - return ret; - } - - if (pc->dt_type) { - ret = fdt_setprop_string(fdt, node_off, "device_type", - pc->dt_type); - if (ret < 0) { - return ret; - } - } - - if (pc->dt_compatible) { - ret = fdt_setprop_string(fdt, node_off, "compatible", - pc->dt_compatible); - if (ret < 0) { - return ret; - } - } - - if (dev->irq) { - uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0}; - - ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, - sizeof(ints_prop)); - if (ret < 0) { - return ret; - } - } - - ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma); - if (ret < 0) { - return ret; - } - - if (pc->devnode) { - ret = (pc->devnode)(dev, fdt, node_off); - if (ret < 0) { - return ret; - } - } - - return node_off; -} -#endif /* CONFIG_FDT */ - -/* - * CRQ handling - */ -static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong reg = args[0]; - target_ulong queue_addr = args[1]; - target_ulong queue_len = args[2]; - VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - - if (!dev) { - hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); - return H_PARAMETER; - } - - /* We can't grok a queue size bigger than 256M for now */ - if (queue_len < 0x1000 || queue_len > 0x10000000) { - hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx - ")\n", queue_len); - return H_PARAMETER; - } - - /* Check queue alignment */ - if (queue_addr & 0xfff) { - hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr); - return H_PARAMETER; - } - - /* Check if device supports CRQs */ - if (!dev->crq.SendFunc) { - hcall_dprintf("Device does not support CRQ\n"); - return H_NOT_FOUND; - } - - /* Already a queue ? */ - if (dev->crq.qsize) { - hcall_dprintf("CRQ already registered\n"); - return H_RESOURCE; - } - dev->crq.qladdr = queue_addr; - dev->crq.qsize = queue_len; - dev->crq.qnext = 0; - - dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" - TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n", - reg, queue_addr, queue_len); - return H_SUCCESS; -} - -static target_ulong free_crq(VIOsPAPRDevice *dev) -{ - dev->crq.qladdr = 0; - dev->crq.qsize = 0; - dev->crq.qnext = 0; - - dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); - - return H_SUCCESS; -} - -static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong reg = args[0]; - VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - - if (!dev) { - hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); - return H_PARAMETER; - } - - return free_crq(dev); -} - -static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong reg = args[0]; - target_ulong msg_hi = args[1]; - target_ulong msg_lo = args[2]; - VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - uint64_t crq_mangle[2]; - - if (!dev) { - hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); - return H_PARAMETER; - } - crq_mangle[0] = cpu_to_be64(msg_hi); - crq_mangle[1] = cpu_to_be64(msg_lo); - - if (dev->crq.SendFunc) { - return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle); - } - - return H_HARDWARE; -} - -static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong reg = args[0]; - VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - - if (!dev) { - hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); - return H_PARAMETER; - } - - return 0; -} - -/* Returns negative error, 0 success, or positive: queue full */ -int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) -{ - int rc; - uint8_t byte; - - if (!dev->crq.qsize) { - fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n"); - return -1; - } - - /* Maybe do a fast path for KVM just writing to the pages */ - rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1); - if (rc) { - return rc; - } - if (byte != 0) { - return 1; - } - - rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, - &crq[8], 8); - if (rc) { - return rc; - } - - kvmppc_eieio(); - - rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8); - if (rc) { - return rc; - } - - dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; - - if (dev->signal_state & 1) { - qemu_irq_pulse(spapr_vio_qirq(dev)); - } - - return 0; -} - -/* "quiesce" handling */ - -static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) -{ - if (dev->dma) { - spapr_tce_reset(dev->dma); - } - free_crq(dev); -} - -static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - VIOsPAPRBus *bus = spapr->vio_bus; - VIOsPAPRDevice *dev; - uint32_t unit, enable; - - if (nargs != 2) { - rtas_st(rets, 0, -3); - return; - } - unit = rtas_ld(args, 0); - enable = rtas_ld(args, 1); - dev = spapr_vio_find_by_reg(bus, unit); - if (!dev) { - rtas_st(rets, 0, -3); - return; - } - - if (!dev->dma) { - rtas_st(rets, 0, -3); - return; - } - - spapr_tce_set_bypass(dev->dma, !!enable); - - rtas_st(rets, 0, 0); -} - -static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - VIOsPAPRBus *bus = spapr->vio_bus; - BusChild *kid; - VIOsPAPRDevice *dev = NULL; - - if (nargs != 0) { - rtas_st(rets, 0, -3); - return; - } - - QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { - dev = (VIOsPAPRDevice *)kid->child; - spapr_vio_quiesce_one(dev); - } - - rtas_st(rets, 0, 0); -} - -static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) -{ - VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus); - BusChild *kid; - VIOsPAPRDevice *other; - - /* - * Check for a device other than the given one which is already - * using the requested address. We have to open code this because - * the given dev might already be in the list. - */ - QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { - other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child); - - if (other != dev && other->reg == dev->reg) { - return other; - } - } - - return 0; -} - -static void spapr_vio_busdev_reset(DeviceState *qdev) -{ - VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - - /* Shut down the request queue and TCEs if necessary */ - spapr_vio_quiesce_one(dev); - - dev->signal_state = 0; - - if (pc->reset) { - pc->reset(dev); - } -} - -static int spapr_vio_busdev_init(DeviceState *qdev) -{ - VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - char *id; - - if (dev->reg != -1) { - /* - * Explicitly assigned address, just verify that no-one else - * is using it. other mechanism). We have to open code this - * rather than using spapr_vio_find_by_reg() because sdev - * itself is already in the list. - */ - VIOsPAPRDevice *other = reg_conflict(dev); - - if (other) { - fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n", - object_get_typename(OBJECT(qdev)), - object_get_typename(OBJECT(&other->qdev)), - dev->reg); - return -1; - } - } else { - /* Need to assign an address */ - VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus); - - do { - dev->reg = bus->next_reg++; - } while (reg_conflict(dev)); - } - - /* Don't overwrite ids assigned on the command line */ - if (!dev->qdev.id) { - id = vio_format_dev_name(dev); - dev->qdev.id = id; - } - - dev->irq = spapr_allocate_msi(dev->irq); - if (!dev->irq) { - return -1; - } - - if (pc->rtce_window_size) { - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); - } - - return pc->init(dev); -} - -static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, - target_ulong *args) -{ - target_ulong reg = args[0]; - target_ulong mode = args[1]; - VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - VIOsPAPRDeviceClass *pc; - - if (!dev) { - return H_PARAMETER; - } - - pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - - if (mode & ~pc->signal_mask) { - return H_PARAMETER; - } - - dev->signal_state = mode; - - return H_SUCCESS; -} - -VIOsPAPRBus *spapr_vio_bus_init(void) -{ - VIOsPAPRBus *bus; - BusState *qbus; - DeviceState *dev; - - /* Create bridge device */ - dev = qdev_create(NULL, "spapr-vio-bridge"); - qdev_init_nofail(dev); - - /* Create bus on bridge device */ - - qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); - bus = DO_UPCAST(VIOsPAPRBus, bus, qbus); - bus->next_reg = 0x71000000; - - /* hcall-vio */ - spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); - - /* hcall-crq */ - spapr_register_hypercall(H_REG_CRQ, h_reg_crq); - spapr_register_hypercall(H_FREE_CRQ, h_free_crq); - spapr_register_hypercall(H_SEND_CRQ, h_send_crq); - spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); - - /* RTAS calls */ - spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass); - spapr_rtas_register("quiesce", rtas_quiesce); - - return bus; -} - -/* Represents sPAPR hcall VIO devices */ - -static int spapr_vio_bridge_init(SysBusDevice *dev) -{ - /* nothing */ - return 0; -} - -static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = spapr_vio_bridge_init; - dc->no_user = 1; -} - -static const TypeInfo spapr_vio_bridge_info = { - .name = "spapr-vio-bridge", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SysBusDevice), - .class_init = spapr_vio_bridge_class_init, -}; - -static void vio_spapr_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *k = DEVICE_CLASS(klass); - k->init = spapr_vio_busdev_init; - k->reset = spapr_vio_busdev_reset; - k->bus_type = TYPE_SPAPR_VIO_BUS; - k->props = spapr_vio_props; -} - -static const TypeInfo spapr_vio_type_info = { - .name = TYPE_VIO_SPAPR_DEVICE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(VIOsPAPRDevice), - .abstract = true, - .class_size = sizeof(VIOsPAPRDeviceClass), - .class_init = vio_spapr_device_class_init, -}; - -static void spapr_vio_register_types(void) -{ - type_register_static(&spapr_vio_bus_info); - type_register_static(&spapr_vio_bridge_info); - type_register_static(&spapr_vio_type_info); -} - -type_init(spapr_vio_register_types) - -#ifdef CONFIG_FDT -static int compare_reg(const void *p1, const void *p2) -{ - VIOsPAPRDevice const *dev1, *dev2; - - dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1; - dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2; - - if (dev1->reg < dev2->reg) { - return -1; - } - if (dev1->reg == dev2->reg) { - return 0; - } - - /* dev1->reg > dev2->reg */ - return 1; -} - -int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt) -{ - DeviceState *qdev, **qdevs; - BusChild *kid; - int i, num, ret = 0; - - /* Count qdevs on the bus list */ - num = 0; - QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { - num++; - } - - /* Copy out into an array of pointers */ - qdevs = g_malloc(sizeof(qdev) * num); - num = 0; - QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { - qdevs[num++] = kid->child; - } - - /* Sort the array */ - qsort(qdevs, num, sizeof(qdev), compare_reg); - - /* Hack alert. Give the devices to libfdt in reverse order, we happen - * to know that will mean they are in forward order in the tree. */ - for (i = num - 1; i >= 0; i--) { - VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]); - - ret = vio_make_devnode(dev, fdt); - - if (ret < 0) { - goto out; - } - } - - ret = 0; -out: - free(qdevs); - - return ret; -} - -int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus) -{ - VIOsPAPRDevice *dev; - char *name, *path; - int ret, offset; - - dev = spapr_vty_get_default(bus); - if (!dev) - return 0; - - offset = fdt_path_offset(fdt, "/chosen"); - if (offset < 0) { - return offset; - } - - name = vio_format_dev_name(dev); - path = g_strdup_printf("/vdevice/%s", name); - - ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path); - - g_free(name); - g_free(path); - - return ret; -} -#endif /* CONFIG_FDT */ diff --git a/hw/xics.c b/hw/xics.c deleted file mode 100644 index c3ef12fff4..0000000000 --- a/hw/xics.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator - * - * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics - * - * Copyright (c) 2010,2011 David Gibson, IBM Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#include "hw/hw.h" -#include "trace.h" -#include "hw/spapr.h" -#include "hw/xics.h" - -/* - * ICP: Presentation layer - */ - -struct icp_server_state { - uint32_t xirr; - uint8_t pending_priority; - uint8_t mfrr; - qemu_irq output; -}; - -#define XISR_MASK 0x00ffffff -#define CPPR_MASK 0xff000000 - -#define XISR(ss) (((ss)->xirr) & XISR_MASK) -#define CPPR(ss) (((ss)->xirr) >> 24) - -struct ics_state; - -struct icp_state { - long nr_servers; - struct icp_server_state *ss; - struct ics_state *ics; -}; - -static void ics_reject(struct ics_state *ics, int nr); -static void ics_resend(struct ics_state *ics); -static void ics_eoi(struct ics_state *ics, int nr); - -static void icp_check_ipi(struct icp_state *icp, int server) -{ - struct icp_server_state *ss = icp->ss + server; - - if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { - return; - } - - trace_xics_icp_check_ipi(server, ss->mfrr); - - if (XISR(ss)) { - ics_reject(icp->ics, XISR(ss)); - } - - ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; - ss->pending_priority = ss->mfrr; - qemu_irq_raise(ss->output); -} - -static void icp_resend(struct icp_state *icp, int server) -{ - struct icp_server_state *ss = icp->ss + server; - - if (ss->mfrr < CPPR(ss)) { - icp_check_ipi(icp, server); - } - ics_resend(icp->ics); -} - -static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) -{ - struct icp_server_state *ss = icp->ss + server; - uint8_t old_cppr; - uint32_t old_xisr; - - old_cppr = CPPR(ss); - ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24); - - if (cppr < old_cppr) { - if (XISR(ss) && (cppr <= ss->pending_priority)) { - old_xisr = XISR(ss); - ss->xirr &= ~XISR_MASK; /* Clear XISR */ - qemu_irq_lower(ss->output); - ics_reject(icp->ics, old_xisr); - } - } else { - if (!XISR(ss)) { - icp_resend(icp, server); - } - } -} - -static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr) -{ - struct icp_server_state *ss = icp->ss + server; - - ss->mfrr = mfrr; - if (mfrr < CPPR(ss)) { - icp_check_ipi(icp, server); - } -} - -static uint32_t icp_accept(struct icp_server_state *ss) -{ - uint32_t xirr = ss->xirr; - - qemu_irq_lower(ss->output); - ss->xirr = ss->pending_priority << 24; - - trace_xics_icp_accept(xirr, ss->xirr); - - return xirr; -} - -static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) -{ - struct icp_server_state *ss = icp->ss + server; - - /* Send EOI -> ICS */ - ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); - trace_xics_icp_eoi(server, xirr, ss->xirr); - ics_eoi(icp->ics, xirr & XISR_MASK); - if (!XISR(ss)) { - icp_resend(icp, server); - } -} - -static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) -{ - struct icp_server_state *ss = icp->ss + server; - - trace_xics_icp_irq(server, nr, priority); - - if ((priority >= CPPR(ss)) - || (XISR(ss) && (ss->pending_priority <= priority))) { - ics_reject(icp->ics, nr); - } else { - if (XISR(ss)) { - ics_reject(icp->ics, XISR(ss)); - } - ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); - ss->pending_priority = priority; - trace_xics_icp_raise(ss->xirr, ss->pending_priority); - qemu_irq_raise(ss->output); - } -} - -/* - * ICS: Source layer - */ - -struct ics_irq_state { - int server; - uint8_t priority; - uint8_t saved_priority; -#define XICS_STATUS_ASSERTED 0x1 -#define XICS_STATUS_SENT 0x2 -#define XICS_STATUS_REJECTED 0x4 -#define XICS_STATUS_MASKED_PENDING 0x8 - uint8_t status; -}; - -struct ics_state { - int nr_irqs; - int offset; - qemu_irq *qirqs; - bool *islsi; - struct ics_irq_state *irqs; - struct icp_state *icp; -}; - -static int ics_valid_irq(struct ics_state *ics, uint32_t nr) -{ - return (nr >= ics->offset) - && (nr < (ics->offset + ics->nr_irqs)); -} - -static void resend_msi(struct ics_state *ics, int srcno) -{ - struct ics_irq_state *irq = ics->irqs + srcno; - - /* FIXME: filter by server#? */ - if (irq->status & XICS_STATUS_REJECTED) { - irq->status &= ~XICS_STATUS_REJECTED; - if (irq->priority != 0xff) { - icp_irq(ics->icp, irq->server, srcno + ics->offset, - irq->priority); - } - } -} - -static void resend_lsi(struct ics_state *ics, int srcno) -{ - struct ics_irq_state *irq = ics->irqs + srcno; - - if ((irq->priority != 0xff) - && (irq->status & XICS_STATUS_ASSERTED) - && !(irq->status & XICS_STATUS_SENT)) { - irq->status |= XICS_STATUS_SENT; - icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); - } -} - -static void set_irq_msi(struct ics_state *ics, int srcno, int val) -{ - struct ics_irq_state *irq = ics->irqs + srcno; - - trace_xics_set_irq_msi(srcno, srcno + ics->offset); - - if (val) { - if (irq->priority == 0xff) { - irq->status |= XICS_STATUS_MASKED_PENDING; - trace_xics_masked_pending(); - } else { - icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); - } - } -} - -static void set_irq_lsi(struct ics_state *ics, int srcno, int val) -{ - struct ics_irq_state *irq = ics->irqs + srcno; - - trace_xics_set_irq_lsi(srcno, srcno + ics->offset); - if (val) { - irq->status |= XICS_STATUS_ASSERTED; - } else { - irq->status &= ~XICS_STATUS_ASSERTED; - } - resend_lsi(ics, srcno); -} - -static void ics_set_irq(void *opaque, int srcno, int val) -{ - struct ics_state *ics = (struct ics_state *)opaque; - - if (ics->islsi[srcno]) { - set_irq_lsi(ics, srcno, val); - } else { - set_irq_msi(ics, srcno, val); - } -} - -static void write_xive_msi(struct ics_state *ics, int srcno) -{ - struct ics_irq_state *irq = ics->irqs + srcno; - - if (!(irq->status & XICS_STATUS_MASKED_PENDING) - || (irq->priority == 0xff)) { - return; - } - - irq->status &= ~XICS_STATUS_MASKED_PENDING; - icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); -} - -static void write_xive_lsi(struct ics_state *ics, int srcno) -{ - resend_lsi(ics, srcno); -} - -static void ics_write_xive(struct ics_state *ics, int nr, int server, - uint8_t priority, uint8_t saved_priority) -{ - int srcno = nr - ics->offset; - struct ics_irq_state *irq = ics->irqs + srcno; - - irq->server = server; - irq->priority = priority; - irq->saved_priority = saved_priority; - - trace_xics_ics_write_xive(nr, srcno, server, priority); - - if (ics->islsi[srcno]) { - write_xive_lsi(ics, srcno); - } else { - write_xive_msi(ics, srcno); - } -} - -static void ics_reject(struct ics_state *ics, int nr) -{ - struct ics_irq_state *irq = ics->irqs + nr - ics->offset; - - trace_xics_ics_reject(nr, nr - ics->offset); - irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ - irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ -} - -static void ics_resend(struct ics_state *ics) -{ - int i; - - for (i = 0; i < ics->nr_irqs; i++) { - /* FIXME: filter by server#? */ - if (ics->islsi[i]) { - resend_lsi(ics, i); - } else { - resend_msi(ics, i); - } - } -} - -static void ics_eoi(struct ics_state *ics, int nr) -{ - int srcno = nr - ics->offset; - struct ics_irq_state *irq = ics->irqs + srcno; - - trace_xics_ics_eoi(nr); - - if (ics->islsi[srcno]) { - irq->status &= ~XICS_STATUS_SENT; - } -} - -/* - * Exported functions - */ - -qemu_irq xics_get_qirq(struct icp_state *icp, int irq) -{ - if (!ics_valid_irq(icp->ics, irq)) { - return NULL; - } - - return icp->ics->qirqs[irq - icp->ics->offset]; -} - -void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) -{ - assert(ics_valid_irq(icp->ics, irq)); - - icp->ics->islsi[irq - icp->ics->offset] = lsi; -} - -static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - target_ulong cppr = args[0]; - - icp_set_cppr(spapr->icp, cs->cpu_index, cppr); - return H_SUCCESS; -} - -static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong server = args[0]; - target_ulong mfrr = args[1]; - - if (server >= spapr->icp->nr_servers) { - return H_PARAMETER; - } - - icp_set_mfrr(spapr->icp, server, mfrr); - return H_SUCCESS; -} - -static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); - - args[0] = xirr; - return H_SUCCESS; -} - -static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - target_ulong xirr = args[0]; - - icp_eoi(spapr->icp, cs->cpu_index, xirr); - return H_SUCCESS; -} - -static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - struct ics_state *ics = spapr->icp->ics; - uint32_t nr, server, priority; - - if ((nargs != 3) || (nret != 1)) { - rtas_st(rets, 0, -3); - return; - } - - nr = rtas_ld(args, 0); - server = rtas_ld(args, 1); - priority = rtas_ld(args, 2); - - if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) - || (priority > 0xff)) { - rtas_st(rets, 0, -3); - return; - } - - ics_write_xive(ics, nr, server, priority, priority); - - rtas_st(rets, 0, 0); /* Success */ -} - -static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - struct ics_state *ics = spapr->icp->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 3)) { - rtas_st(rets, 0, -3); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, -3); - return; - } - - rtas_st(rets, 0, 0); /* Success */ - rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); - rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); -} - -static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - struct ics_state *ics = spapr->icp->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, -3); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, -3); - return; - } - - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, - ics->irqs[nr - ics->offset].priority); - - rtas_st(rets, 0, 0); /* Success */ -} - -static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - struct ics_state *ics = spapr->icp->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, -3); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, -3); - return; - } - - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, - ics->irqs[nr - ics->offset].saved_priority, - ics->irqs[nr - ics->offset].saved_priority); - - rtas_st(rets, 0, 0); /* Success */ -} - -static void xics_reset(void *opaque) -{ - struct icp_state *icp = (struct icp_state *)opaque; - struct ics_state *ics = icp->ics; - int i; - - for (i = 0; i < icp->nr_servers; i++) { - icp->ss[i].xirr = 0; - icp->ss[i].pending_priority = 0xff; - icp->ss[i].mfrr = 0xff; - /* Make all outputs are deasserted */ - qemu_set_irq(icp->ss[i].output, 0); - } - - memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs); - for (i = 0; i < ics->nr_irqs; i++) { - ics->irqs[i].priority = 0xff; - ics->irqs[i].saved_priority = 0xff; - } -} - -struct icp_state *xics_system_init(int nr_irqs) -{ - CPUPPCState *env; - CPUState *cpu; - int max_server_num; - struct icp_state *icp; - struct ics_state *ics; - - max_server_num = -1; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - if (cpu->cpu_index > max_server_num) { - max_server_num = cpu->cpu_index; - } - } - - icp = g_malloc0(sizeof(*icp)); - icp->nr_servers = max_server_num + 1; - icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - struct icp_server_state *ss = &icp->ss[cpu->cpu_index]; - - switch (PPC_INPUT(env)) { - case PPC_FLAGS_INPUT_POWER7: - ss->output = env->irq_inputs[POWER7_INPUT_INT]; - break; - - case PPC_FLAGS_INPUT_970: - ss->output = env->irq_inputs[PPC970_INPUT_INT]; - break; - - default: - hw_error("XICS interrupt model does not support this CPU bus " - "model\n"); - exit(1); - } - } - - ics = g_malloc0(sizeof(*ics)); - ics->nr_irqs = nr_irqs; - ics->offset = XICS_IRQ_BASE; - ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state)); - ics->islsi = g_malloc0(nr_irqs * sizeof(bool)); - - icp->ics = ics; - ics->icp = icp; - - ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); - - spapr_register_hypercall(H_CPPR, h_cppr); - spapr_register_hypercall(H_IPI, h_ipi); - spapr_register_hypercall(H_XIRR, h_xirr); - spapr_register_hypercall(H_EOI, h_eoi); - - spapr_rtas_register("ibm,set-xive", rtas_set_xive); - spapr_rtas_register("ibm,get-xive", rtas_get_xive); - spapr_rtas_register("ibm,int-off", rtas_int_off); - spapr_rtas_register("ibm,int-on", rtas_int_on); - - qemu_register_reset(xics_reset, icp); - - return icp; -} -- cgit v1.2.3 From 9f64bd8aec7c31c76fa0954aaee1475d482662b4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:20:00 +0100 Subject: ppc: move more files to hw/ppc These sPAPR files do not implement devices, move them over. Signed-off-by: Paolo Bonzini --- hw/ppc/Makefile.objs | 8 +- hw/ppc/spapr_events.c | 321 ++++++++++++++++++++++ hw/ppc/spapr_hcall.c | 741 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_iommu.c | 293 ++++++++++++++++++++ hw/ppc/spapr_rtas.c | 334 +++++++++++++++++++++++ hw/spapr_events.c | 321 ---------------------- hw/spapr_hcall.c | 741 -------------------------------------------------- hw/spapr_iommu.c | 293 -------------------- hw/spapr_rtas.c | 334 ----------------------- 9 files changed, 1693 insertions(+), 1693 deletions(-) create mode 100644 hw/ppc/spapr_events.c create mode 100644 hw/ppc/spapr_hcall.c create mode 100644 hw/ppc/spapr_iommu.c create mode 100644 hw/ppc/spapr_rtas.c delete mode 100644 hw/spapr_events.c delete mode 100644 hw/spapr_hcall.c delete mode 100644 hw/spapr_iommu.c delete mode 100644 hw/spapr_rtas.c diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index acc9961ab0..4de02098e2 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,10 +1,9 @@ # PREP target obj-y += mc146818rtc.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o -obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o -obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o +obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o +obj-$(CONFIG_PSERIES) += spapr_nvram.o # PowerPC 4xx boards obj-y += ppc4xx_pci.o # PowerPC OpenPIC @@ -18,7 +17,8 @@ obj-y := $(addprefix ../,$(obj-y)) # shared objects obj-y += ppc.o ppc_booke.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o +obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o spapr_events.o +obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o # PowerPC 4xx boards obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o # PReP diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c new file mode 100644 index 0000000000..ce78f0922e --- /dev/null +++ b/hw/ppc/spapr_events.c @@ -0,0 +1,321 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * RTAS events handling + * + * Copyright (c) 2012 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "cpu.h" +#include "sysemu/sysemu.h" +#include "char/char.h" +#include "hw/qdev.h" +#include "sysemu/device_tree.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#include + +struct rtas_error_log { + uint32_t summary; +#define RTAS_LOG_VERSION_MASK 0xff000000 +#define RTAS_LOG_VERSION_6 0x06000000 +#define RTAS_LOG_SEVERITY_MASK 0x00e00000 +#define RTAS_LOG_SEVERITY_ALREADY_REPORTED 0x00c00000 +#define RTAS_LOG_SEVERITY_FATAL 0x00a00000 +#define RTAS_LOG_SEVERITY_ERROR 0x00800000 +#define RTAS_LOG_SEVERITY_ERROR_SYNC 0x00600000 +#define RTAS_LOG_SEVERITY_WARNING 0x00400000 +#define RTAS_LOG_SEVERITY_EVENT 0x00200000 +#define RTAS_LOG_SEVERITY_NO_ERROR 0x00000000 +#define RTAS_LOG_DISPOSITION_MASK 0x00180000 +#define RTAS_LOG_DISPOSITION_FULLY_RECOVERED 0x00000000 +#define RTAS_LOG_DISPOSITION_LIMITED_RECOVERY 0x00080000 +#define RTAS_LOG_DISPOSITION_NOT_RECOVERED 0x00100000 +#define RTAS_LOG_OPTIONAL_PART_PRESENT 0x00040000 +#define RTAS_LOG_INITIATOR_MASK 0x0000f000 +#define RTAS_LOG_INITIATOR_UNKNOWN 0x00000000 +#define RTAS_LOG_INITIATOR_CPU 0x00001000 +#define RTAS_LOG_INITIATOR_PCI 0x00002000 +#define RTAS_LOG_INITIATOR_MEMORY 0x00004000 +#define RTAS_LOG_INITIATOR_HOTPLUG 0x00006000 +#define RTAS_LOG_TARGET_MASK 0x00000f00 +#define RTAS_LOG_TARGET_UNKNOWN 0x00000000 +#define RTAS_LOG_TARGET_CPU 0x00000100 +#define RTAS_LOG_TARGET_PCI 0x00000200 +#define RTAS_LOG_TARGET_MEMORY 0x00000400 +#define RTAS_LOG_TARGET_HOTPLUG 0x00000600 +#define RTAS_LOG_TYPE_MASK 0x000000ff +#define RTAS_LOG_TYPE_OTHER 0x00000000 +#define RTAS_LOG_TYPE_RETRY 0x00000001 +#define RTAS_LOG_TYPE_TCE_ERR 0x00000002 +#define RTAS_LOG_TYPE_INTERN_DEV_FAIL 0x00000003 +#define RTAS_LOG_TYPE_TIMEOUT 0x00000004 +#define RTAS_LOG_TYPE_DATA_PARITY 0x00000005 +#define RTAS_LOG_TYPE_ADDR_PARITY 0x00000006 +#define RTAS_LOG_TYPE_CACHE_PARITY 0x00000007 +#define RTAS_LOG_TYPE_ADDR_INVALID 0x00000008 +#define RTAS_LOG_TYPE_ECC_UNCORR 0x00000009 +#define RTAS_LOG_TYPE_ECC_CORR 0x0000000a +#define RTAS_LOG_TYPE_EPOW 0x00000040 + uint32_t extended_length; +} QEMU_PACKED; + +struct rtas_event_log_v6 { + uint8_t b0; +#define RTAS_LOG_V6_B0_VALID 0x80 +#define RTAS_LOG_V6_B0_UNRECOVERABLE_ERROR 0x40 +#define RTAS_LOG_V6_B0_RECOVERABLE_ERROR 0x20 +#define RTAS_LOG_V6_B0_DEGRADED_OPERATION 0x10 +#define RTAS_LOG_V6_B0_PREDICTIVE_ERROR 0x08 +#define RTAS_LOG_V6_B0_NEW_LOG 0x04 +#define RTAS_LOG_V6_B0_BIGENDIAN 0x02 + uint8_t _resv1; + uint8_t b2; +#define RTAS_LOG_V6_B2_POWERPC_FORMAT 0x80 +#define RTAS_LOG_V6_B2_LOG_FORMAT_MASK 0x0f +#define RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT 0x0e + uint8_t _resv2[9]; + uint32_t company; +#define RTAS_LOG_V6_COMPANY_IBM 0x49424d00 /* IBM */ +} QEMU_PACKED; + +struct rtas_event_log_v6_section_header { + uint16_t section_id; + uint16_t section_length; + uint8_t section_version; + uint8_t section_subtype; + uint16_t creator_component_id; +} QEMU_PACKED; + +struct rtas_event_log_v6_maina { +#define RTAS_LOG_V6_SECTION_ID_MAINA 0x5048 /* PH */ + struct rtas_event_log_v6_section_header hdr; + uint32_t creation_date; /* BCD: YYYYMMDD */ + uint32_t creation_time; /* BCD: HHMMSS00 */ + uint8_t _platform1[8]; + char creator_id; + uint8_t _resv1[2]; + uint8_t section_count; + uint8_t _resv2[4]; + uint8_t _platform2[8]; + uint32_t plid; + uint8_t _platform3[4]; +} QEMU_PACKED; + +struct rtas_event_log_v6_mainb { +#define RTAS_LOG_V6_SECTION_ID_MAINB 0x5548 /* UH */ + struct rtas_event_log_v6_section_header hdr; + uint8_t subsystem_id; + uint8_t _platform1; + uint8_t event_severity; + uint8_t event_subtype; + uint8_t _platform2[4]; + uint8_t _resv1[2]; + uint16_t action_flags; + uint8_t _resv2[4]; +} QEMU_PACKED; + +struct rtas_event_log_v6_epow { +#define RTAS_LOG_V6_SECTION_ID_EPOW 0x4550 /* EP */ + struct rtas_event_log_v6_section_header hdr; + uint8_t sensor_value; +#define RTAS_LOG_V6_EPOW_ACTION_RESET 0 +#define RTAS_LOG_V6_EPOW_ACTION_WARN_COOLING 1 +#define RTAS_LOG_V6_EPOW_ACTION_WARN_POWER 2 +#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN 3 +#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_HALT 4 +#define RTAS_LOG_V6_EPOW_ACTION_MAIN_ENCLOSURE 5 +#define RTAS_LOG_V6_EPOW_ACTION_POWER_OFF 7 + uint8_t event_modifier; +#define RTAS_LOG_V6_EPOW_MODIFIER_NORMAL 1 +#define RTAS_LOG_V6_EPOW_MODIFIER_ON_UPS 2 +#define RTAS_LOG_V6_EPOW_MODIFIER_CRITICAL 3 +#define RTAS_LOG_V6_EPOW_MODIFIER_TEMPERATURE 4 + uint8_t extended_modifier; +#define RTAS_LOG_V6_EPOW_XMODIFIER_SYSTEM_WIDE 0 +#define RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC 1 + uint8_t _resv; + uint64_t reason_code; +} QEMU_PACKED; + +struct epow_log_full { + struct rtas_error_log hdr; + struct rtas_event_log_v6 v6hdr; + struct rtas_event_log_v6_maina maina; + struct rtas_event_log_v6_mainb mainb; + struct rtas_event_log_v6_epow epow; +} QEMU_PACKED; + +#define EVENT_MASK_INTERNAL_ERRORS 0x80000000 +#define EVENT_MASK_EPOW 0x40000000 +#define EVENT_MASK_HOTPLUG 0x10000000 +#define EVENT_MASK_IO 0x08000000 + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + +void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq) +{ + uint32_t epow_irq_ranges[] = {cpu_to_be32(epow_irq), cpu_to_be32(1)}; + uint32_t epow_interrupts[] = {cpu_to_be32(epow_irq), 0}; + + _FDT((fdt_begin_node(fdt, "event-sources"))); + + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); + _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); + _FDT((fdt_property(fdt, "interrupt-ranges", + epow_irq_ranges, sizeof(epow_irq_ranges)))); + + _FDT((fdt_begin_node(fdt, "epow-events"))); + _FDT((fdt_property(fdt, "interrupts", + epow_interrupts, sizeof(epow_interrupts)))); + _FDT((fdt_end_node(fdt))); + + _FDT((fdt_end_node(fdt))); +} + +static struct epow_log_full *pending_epow; +static uint32_t next_plid; + +static void spapr_powerdown_req(Notifier *n, void *opaque) +{ + sPAPREnvironment *spapr = container_of(n, sPAPREnvironment, epow_notifier); + struct rtas_error_log *hdr; + struct rtas_event_log_v6 *v6hdr; + struct rtas_event_log_v6_maina *maina; + struct rtas_event_log_v6_mainb *mainb; + struct rtas_event_log_v6_epow *epow; + struct tm tm; + int year; + + if (pending_epow) { + /* For now, we just throw away earlier events if two come + * along before any are consumed. This is sufficient for our + * powerdown messages, but we'll need more if we do more + * general error/event logging */ + g_free(pending_epow); + } + pending_epow = g_malloc0(sizeof(*pending_epow)); + hdr = &pending_epow->hdr; + v6hdr = &pending_epow->v6hdr; + maina = &pending_epow->maina; + mainb = &pending_epow->mainb; + epow = &pending_epow->epow; + + hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6 + | RTAS_LOG_SEVERITY_EVENT + | RTAS_LOG_DISPOSITION_NOT_RECOVERED + | RTAS_LOG_OPTIONAL_PART_PRESENT + | RTAS_LOG_TYPE_EPOW); + hdr->extended_length = cpu_to_be32(sizeof(*pending_epow) + - sizeof(pending_epow->hdr)); + + v6hdr->b0 = RTAS_LOG_V6_B0_VALID | RTAS_LOG_V6_B0_NEW_LOG + | RTAS_LOG_V6_B0_BIGENDIAN; + v6hdr->b2 = RTAS_LOG_V6_B2_POWERPC_FORMAT + | RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT; + v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM); + + maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA); + maina->hdr.section_length = cpu_to_be16(sizeof(*maina)); + /* FIXME: section version, subtype and creator id? */ + qemu_get_timedate(&tm, spapr->rtc_offset); + year = tm.tm_year + 1900; + maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24) + | (to_bcd(year % 100) << 16) + | (to_bcd(tm.tm_mon + 1) << 8) + | to_bcd(tm.tm_mday)); + maina->creation_time = cpu_to_be32((to_bcd(tm.tm_hour) << 24) + | (to_bcd(tm.tm_min) << 16) + | (to_bcd(tm.tm_sec) << 8)); + maina->creator_id = 'H'; /* Hypervisor */ + maina->section_count = 3; /* Main-A, Main-B and EPOW */ + maina->plid = next_plid++; + + mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB); + mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb)); + /* FIXME: section version, subtype and creator id? */ + mainb->subsystem_id = 0xa0; /* External environment */ + mainb->event_severity = 0x00; /* Informational / non-error */ + mainb->event_subtype = 0xd0; /* Normal shutdown */ + + epow->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_EPOW); + epow->hdr.section_length = cpu_to_be16(sizeof(*epow)); + epow->hdr.section_version = 2; /* includes extended modifier */ + /* FIXME: section subtype and creator id? */ + epow->sensor_value = RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN; + epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL; + epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC; + + qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->epow_irq)); +} + +static void check_exception(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t mask, buf, len; + uint64_t xinfo; + + if ((nargs < 6) || (nargs > 7) || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + + xinfo = rtas_ld(args, 1); + mask = rtas_ld(args, 2); + buf = rtas_ld(args, 4); + len = rtas_ld(args, 5); + if (nargs == 7) { + xinfo |= (uint64_t)rtas_ld(args, 6) << 32; + } + + if ((mask & EVENT_MASK_EPOW) && pending_epow) { + if (sizeof(*pending_epow) < len) { + len = sizeof(*pending_epow); + } + + cpu_physical_memory_write(buf, pending_epow, len); + g_free(pending_epow); + pending_epow = NULL; + rtas_st(rets, 0, 0); + } else { + rtas_st(rets, 0, 1); + } +} + +void spapr_events_init(sPAPREnvironment *spapr) +{ + spapr->epow_irq = spapr_allocate_msi(0); + spapr->epow_notifier.notify = spapr_powerdown_req; + qemu_register_powerdown_notifier(&spapr->epow_notifier); + spapr_rtas_register("check-exception", check_exception); +} diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c new file mode 100644 index 0000000000..7b8959488e --- /dev/null +++ b/hw/ppc/spapr_hcall.c @@ -0,0 +1,741 @@ +#include "sysemu/sysemu.h" +#include "cpu.h" +#include "sysemu/sysemu.h" +#include "helper_regs.h" +#include "hw/spapr.h" + +#define HPTES_PER_GROUP 8 + +#define HPTE_V_SSIZE_SHIFT 62 +#define HPTE_V_AVPN_SHIFT 7 +#define HPTE_V_AVPN 0x3fffffffffffff80ULL +#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT) +#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL)) +#define HPTE_V_BOLTED 0x0000000000000010ULL +#define HPTE_V_LOCK 0x0000000000000008ULL +#define HPTE_V_LARGE 0x0000000000000004ULL +#define HPTE_V_SECONDARY 0x0000000000000002ULL +#define HPTE_V_VALID 0x0000000000000001ULL + +#define HPTE_R_PP0 0x8000000000000000ULL +#define HPTE_R_TS 0x4000000000000000ULL +#define HPTE_R_KEY_HI 0x3000000000000000ULL +#define HPTE_R_RPN_SHIFT 12 +#define HPTE_R_RPN 0x3ffffffffffff000ULL +#define HPTE_R_FLAGS 0x00000000000003ffULL +#define HPTE_R_PP 0x0000000000000003ULL +#define HPTE_R_N 0x0000000000000004ULL +#define HPTE_R_G 0x0000000000000008ULL +#define HPTE_R_M 0x0000000000000010ULL +#define HPTE_R_I 0x0000000000000020ULL +#define HPTE_R_W 0x0000000000000040ULL +#define HPTE_R_WIMG 0x0000000000000078ULL +#define HPTE_R_C 0x0000000000000080ULL +#define HPTE_R_R 0x0000000000000100ULL +#define HPTE_R_KEY_LO 0x0000000000000e00ULL + +#define HPTE_V_1TB_SEG 0x4000000000000000ULL +#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL + +static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, + target_ulong pte_index) +{ + target_ulong rb, va_low; + + rb = (v & ~0x7fULL) << 16; /* AVA field */ + va_low = pte_index >> 3; + if (v & HPTE_V_SECONDARY) { + va_low = ~va_low; + } + /* xor vsid from AVA */ + if (!(v & HPTE_V_1TB_SEG)) { + va_low ^= v >> 12; + } else { + va_low ^= v >> 24; + } + va_low &= 0x7ff; + if (v & HPTE_V_LARGE) { + rb |= 1; /* L field */ +#if 0 /* Disable that P7 specific bit for now */ + if (r & 0xff000) { + /* non-16MB large page, must be 64k */ + /* (masks depend on page size) */ + rb |= 0x1000; /* page encoding in LP field */ + rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ + rb |= (va_low & 0xfe); /* AVAL field */ + } +#endif + } else { + /* 4kB page */ + rb |= (va_low & 0x7ff) << 12; /* remaining 11b of AVA */ + } + rb |= (v >> 54) & 0x300; /* B field */ + return rb; +} + +static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + target_ulong pteh = args[2]; + target_ulong ptel = args[3]; + target_ulong page_shift = 12; + target_ulong raddr; + target_ulong i; + uint8_t *hpte; + + /* only handle 4k and 16M pages for now */ + if (pteh & HPTE_V_LARGE) { +#if 0 /* We don't support 64k pages yet */ + if ((ptel & 0xf000) == 0x1000) { + /* 64k page */ + } else +#endif + if ((ptel & 0xff000) == 0) { + /* 16M page */ + page_shift = 24; + /* lowest AVA bit must be 0 for 16M pages */ + if (pteh & 0x80) { + return H_PARAMETER; + } + } else { + return H_PARAMETER; + } + } + + raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1); + + if (raddr < spapr->ram_limit) { + /* Regular RAM - should have WIMG=0010 */ + if ((ptel & HPTE_R_WIMG) != HPTE_R_M) { + return H_PARAMETER; + } + } else { + /* Looks like an IO address */ + /* FIXME: What WIMG combinations could be sensible for IO? + * For now we allow WIMG=010x, but are there others? */ + /* FIXME: Should we check against registered IO addresses? */ + if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) { + return H_PARAMETER; + } + } + + pteh &= ~0x60ULL; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + if (likely((flags & H_EXACT) == 0)) { + pte_index &= ~7ULL; + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + for (i = 0; ; ++i) { + if (i == 8) { + return H_PTEG_FULL; + } + if ((ldq_p(hpte) & HPTE_V_VALID) == 0) { + break; + } + hpte += HASH_PTE_SIZE_64; + } + } else { + i = 0; + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + if (ldq_p(hpte) & HPTE_V_VALID) { + return H_PTEG_FULL; + } + } + stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel); + /* eieio(); FIXME: need some sort of barrier for smp? */ + stq_p(hpte, pteh); + + args[0] = pte_index + i; + return H_SUCCESS; +} + +enum { + REMOVE_SUCCESS = 0, + REMOVE_NOT_FOUND = 1, + REMOVE_PARM = 2, + REMOVE_HW = 3, +}; + +static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, + target_ulong avpn, + target_ulong flags, + target_ulong *vp, target_ulong *rp) +{ + uint8_t *hpte; + target_ulong v, r, rb; + + if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return REMOVE_PARM; + } + + hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64); + + v = ldq_p(hpte); + r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + + if ((v & HPTE_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || + ((flags & H_ANDCOND) && (v & avpn) != 0)) { + return REMOVE_NOT_FOUND; + } + *vp = v; + *rp = r; + stq_p(hpte, 0); + rb = compute_tlbie_rb(v, r, ptex); + ppc_tlb_invalidate_one(env, rb); + return REMOVE_SUCCESS; +} + +static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + target_ulong avpn = args[2]; + int ret; + + ret = remove_hpte(env, pte_index, avpn, flags, + &args[0], &args[1]); + + switch (ret) { + case REMOVE_SUCCESS: + return H_SUCCESS; + + case REMOVE_NOT_FOUND: + return H_NOT_FOUND; + + case REMOVE_PARM: + return H_PARAMETER; + + case REMOVE_HW: + return H_HARDWARE; + } + + assert(0); +} + +#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL +#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL +#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL +#define H_BULK_REMOVE_END 0xc000000000000000ULL +#define H_BULK_REMOVE_CODE 0x3000000000000000ULL +#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL +#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL +#define H_BULK_REMOVE_PARM 0x2000000000000000ULL +#define H_BULK_REMOVE_HW 0x3000000000000000ULL +#define H_BULK_REMOVE_RC 0x0c00000000000000ULL +#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL +#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL +#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL +#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL +#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL + +#define H_BULK_REMOVE_MAX_BATCH 4 + +static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + int i; + + for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { + target_ulong *tsh = &args[i*2]; + target_ulong tsl = args[i*2 + 1]; + target_ulong v, r, ret; + + if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { + break; + } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { + return H_PARAMETER; + } + + *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; + *tsh |= H_BULK_REMOVE_RESPONSE; + + if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { + *tsh |= H_BULK_REMOVE_PARM; + return H_PARAMETER; + } + + ret = remove_hpte(env, *tsh & H_BULK_REMOVE_PTEX, tsl, + (*tsh & H_BULK_REMOVE_FLAGS) >> 26, + &v, &r); + + *tsh |= ret << 60; + + switch (ret) { + case REMOVE_SUCCESS: + *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43; + break; + + case REMOVE_PARM: + return H_PARAMETER; + + case REMOVE_HW: + return H_HARDWARE; + } + } + + return H_SUCCESS; +} + +static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + target_ulong avpn = args[2]; + uint8_t *hpte; + target_ulong v, r, rb; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + + v = ldq_p(hpte); + r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + + if ((v & HPTE_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { + return H_NOT_FOUND; + } + + r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | + HPTE_R_KEY_HI | HPTE_R_KEY_LO); + r |= (flags << 55) & HPTE_R_PP0; + r |= (flags << 48) & HPTE_R_KEY_HI; + r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO); + rb = compute_tlbie_rb(v, r, pte_index); + stq_p(hpte, v & ~HPTE_V_VALID); + ppc_tlb_invalidate_one(env, rb); + stq_p(hpte + (HASH_PTE_SIZE_64/2), r); + /* Don't need a memory barrier, due to qemu's global lock */ + stq_p(hpte, v); + return H_SUCCESS; +} + +static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + /* FIXME: actually implement this */ + return H_HARDWARE; +} + +#define FLAGS_REGISTER_VPA 0x0000200000000000ULL +#define FLAGS_REGISTER_DTL 0x0000400000000000ULL +#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL +#define FLAGS_DEREGISTER_VPA 0x0000a00000000000ULL +#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL +#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL + +#define VPA_MIN_SIZE 640 +#define VPA_SIZE_OFFSET 0x4 +#define VPA_SHARED_PROC_OFFSET 0x9 +#define VPA_SHARED_PROC_VAL 0x2 + +static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa) +{ + uint16_t size; + uint8_t tmp; + + if (vpa == 0) { + hcall_dprintf("Can't cope with registering a VPA at logical 0\n"); + return H_HARDWARE; + } + + if (vpa % env->dcache_line_size) { + return H_PARAMETER; + } + /* FIXME: bounds check the address */ + + size = lduw_be_phys(vpa + 0x4); + + if (size < VPA_MIN_SIZE) { + return H_PARAMETER; + } + + /* VPA is not allowed to cross a page boundary */ + if ((vpa / 4096) != ((vpa + size - 1) / 4096)) { + return H_PARAMETER; + } + + env->vpa_addr = vpa; + + tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET); + tmp |= VPA_SHARED_PROC_VAL; + stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp); + + return H_SUCCESS; +} + +static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa) +{ + if (env->slb_shadow_addr) { + return H_RESOURCE; + } + + if (env->dtl_addr) { + return H_RESOURCE; + } + + env->vpa_addr = 0; + return H_SUCCESS; +} + +static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr) +{ + uint32_t size; + + if (addr == 0) { + hcall_dprintf("Can't cope with SLB shadow at logical 0\n"); + return H_HARDWARE; + } + + size = ldl_be_phys(addr + 0x4); + if (size < 0x8) { + return H_PARAMETER; + } + + if ((addr / 4096) != ((addr + size - 1) / 4096)) { + return H_PARAMETER; + } + + if (!env->vpa_addr) { + return H_RESOURCE; + } + + env->slb_shadow_addr = addr; + env->slb_shadow_size = size; + + return H_SUCCESS; +} + +static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr) +{ + env->slb_shadow_addr = 0; + env->slb_shadow_size = 0; + return H_SUCCESS; +} + +static target_ulong register_dtl(CPUPPCState *env, target_ulong addr) +{ + uint32_t size; + + if (addr == 0) { + hcall_dprintf("Can't cope with DTL at logical 0\n"); + return H_HARDWARE; + } + + size = ldl_be_phys(addr + 0x4); + + if (size < 48) { + return H_PARAMETER; + } + + if (!env->vpa_addr) { + return H_RESOURCE; + } + + env->dtl_addr = addr; + env->dtl_size = size; + + return H_SUCCESS; +} + +static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr) +{ + env->dtl_addr = 0; + env->dtl_size = 0; + + return H_SUCCESS; +} + +static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong procno = args[1]; + target_ulong vpa = args[2]; + target_ulong ret = H_PARAMETER; + CPUPPCState *tenv; + CPUState *tcpu; + + tcpu = qemu_get_cpu(procno); + if (!tcpu) { + return H_PARAMETER; + } + tenv = tcpu->env_ptr; + + switch (flags) { + case FLAGS_REGISTER_VPA: + ret = register_vpa(tenv, vpa); + break; + + case FLAGS_DEREGISTER_VPA: + ret = deregister_vpa(tenv, vpa); + break; + + case FLAGS_REGISTER_SLBSHADOW: + ret = register_slb_shadow(tenv, vpa); + break; + + case FLAGS_DEREGISTER_SLBSHADOW: + ret = deregister_slb_shadow(tenv, vpa); + break; + + case FLAGS_REGISTER_DTL: + ret = register_dtl(tenv, vpa); + break; + + case FLAGS_DEREGISTER_DTL: + ret = deregister_dtl(tenv, vpa); + break; + } + + return ret; +} + +static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + env->msr |= (1ULL << MSR_EE); + hreg_compute_hflags(env); + if (!cpu_has_work(cs)) { + env->halted = 1; + env->exception_index = EXCP_HLT; + cs->exit_request = 1; + } + return H_SUCCESS; +} + +static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong rtas_r3 = args[0]; + uint32_t token = ldl_be_phys(rtas_r3); + uint32_t nargs = ldl_be_phys(rtas_r3 + 4); + uint32_t nret = ldl_be_phys(rtas_r3 + 8); + + return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12, + nret, rtas_r3 + 12 + 4*nargs); +} + +static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong size = args[0]; + target_ulong addr = args[1]; + + switch (size) { + case 1: + args[0] = ldub_phys(addr); + return H_SUCCESS; + case 2: + args[0] = lduw_phys(addr); + return H_SUCCESS; + case 4: + args[0] = ldl_phys(addr); + return H_SUCCESS; + case 8: + args[0] = ldq_phys(addr); + return H_SUCCESS; + } + return H_PARAMETER; +} + +static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong size = args[0]; + target_ulong addr = args[1]; + target_ulong val = args[2]; + + switch (size) { + case 1: + stb_phys(addr, val); + return H_SUCCESS; + case 2: + stw_phys(addr, val); + return H_SUCCESS; + case 4: + stl_phys(addr, val); + return H_SUCCESS; + case 8: + stq_phys(addr, val); + return H_SUCCESS; + } + return H_PARAMETER; +} + +static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong dst = args[0]; /* Destination address */ + target_ulong src = args[1]; /* Source address */ + target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */ + target_ulong count = args[3]; /* Element count */ + target_ulong op = args[4]; /* 0 = copy, 1 = invert */ + uint64_t tmp; + unsigned int mask = (1 << esize) - 1; + int step = 1 << esize; + + if (count > 0x80000000) { + return H_PARAMETER; + } + + if ((dst & mask) || (src & mask) || (op > 1)) { + return H_PARAMETER; + } + + if (dst >= src && dst < (src + (count << esize))) { + dst = dst + ((count - 1) << esize); + src = src + ((count - 1) << esize); + step = -step; + } + + while (count--) { + switch (esize) { + case 0: + tmp = ldub_phys(src); + break; + case 1: + tmp = lduw_phys(src); + break; + case 2: + tmp = ldl_phys(src); + break; + case 3: + tmp = ldq_phys(src); + break; + default: + return H_PARAMETER; + } + if (op == 1) { + tmp = ~tmp; + } + switch (esize) { + case 0: + stb_phys(dst, tmp); + break; + case 1: + stw_phys(dst, tmp); + break; + case 2: + stl_phys(dst, tmp); + break; + case 3: + stq_phys(dst, tmp); + break; + } + dst = dst + step; + src = src + step; + } + + return H_SUCCESS; +} + +static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + /* Nothing to do on emulation, KVM will trap this in the kernel */ + return H_SUCCESS; +} + +static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + /* Nothing to do on emulation, KVM will trap this in the kernel */ + return H_SUCCESS; +} + +static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; +static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; + +void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) +{ + spapr_hcall_fn *slot; + + if (opcode <= MAX_HCALL_OPCODE) { + assert((opcode & 0x3) == 0); + + slot = &papr_hypercall_table[opcode / 4]; + } else { + assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)); + + slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; + } + + assert(!(*slot)); + *slot = fn; +} + +target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, + target_ulong *args) +{ + if ((opcode <= MAX_HCALL_OPCODE) + && ((opcode & 0x3) == 0)) { + spapr_hcall_fn fn = papr_hypercall_table[opcode / 4]; + + if (fn) { + return fn(cpu, spapr, opcode, args); + } + } else if ((opcode >= KVMPPC_HCALL_BASE) && + (opcode <= KVMPPC_HCALL_MAX)) { + spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; + + if (fn) { + return fn(cpu, spapr, opcode, args); + } + } + + hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode); + return H_FUNCTION; +} + +static void hypercall_register_types(void) +{ + /* hcall-pft */ + spapr_register_hypercall(H_ENTER, h_enter); + spapr_register_hypercall(H_REMOVE, h_remove); + spapr_register_hypercall(H_PROTECT, h_protect); + + /* hcall-bulk */ + spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); + + /* hcall-dabr */ + spapr_register_hypercall(H_SET_DABR, h_set_dabr); + + /* hcall-splpar */ + spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa); + spapr_register_hypercall(H_CEDE, h_cede); + + /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate + * here between the "CI" and the "CACHE" variants, they will use whatever + * mapping attributes qemu is using. When using KVM, the kernel will + * enforce the attributes more strongly + */ + spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load); + spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store); + spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load); + spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store); + spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi); + spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf); + spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop); + + /* qemu/KVM-PPC specific hcalls */ + spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); +} + +type_init(hypercall_register_types) diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c new file mode 100644 index 0000000000..8d500bf6be --- /dev/null +++ b/hw/ppc/spapr_iommu.c @@ -0,0 +1,293 @@ +/* + * QEMU sPAPR IOMMU (TCE) code + * + * Copyright (c) 2010 David Gibson, IBM Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "hw/hw.h" +#include "sysemu/kvm.h" +#include "hw/qdev.h" +#include "kvm_ppc.h" +#include "sysemu/dma.h" +#include "exec/address-spaces.h" + +#include "hw/spapr.h" + +#include + +/* #define DEBUG_TCE */ + +enum sPAPRTCEAccess { + SPAPR_TCE_FAULT = 0, + SPAPR_TCE_RO = 1, + SPAPR_TCE_WO = 2, + SPAPR_TCE_RW = 3, +}; + +typedef struct sPAPRTCETable sPAPRTCETable; + +struct sPAPRTCETable { + DMAContext dma; + uint32_t liobn; + uint32_t window_size; + sPAPRTCE *table; + bool bypass; + int fd; + QLIST_ENTRY(sPAPRTCETable) list; +}; + + +QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; + +static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) +{ + sPAPRTCETable *tcet; + + QLIST_FOREACH(tcet, &spapr_tce_tables, list) { + if (tcet->liobn == liobn) { + return tcet; + } + } + + return NULL; +} + +static int spapr_tce_translate(DMAContext *dma, + dma_addr_t addr, + hwaddr *paddr, + hwaddr *len, + DMADirection dir) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + enum sPAPRTCEAccess access = (dir == DMA_DIRECTION_FROM_DEVICE) + ? SPAPR_TCE_WO : SPAPR_TCE_RO; + uint64_t tce; + +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_tce_translate liobn=0x%" PRIx32 " addr=0x" + DMA_ADDR_FMT "\n", tcet->liobn, addr); +#endif + + if (tcet->bypass) { + *paddr = addr; + *len = (hwaddr)-1; + return 0; + } + + /* Check if we are in bound */ + if (addr >= tcet->window_size) { +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_tce_translate out of bounds\n"); +#endif + return -EFAULT; + } + + tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce; + + /* Check TCE */ + if (!(tce & access)) { + return -EPERM; + } + + /* How much til end of page ? */ + *len = ((~addr) & SPAPR_TCE_PAGE_MASK) + 1; + + /* Translate */ + *paddr = (tce & ~SPAPR_TCE_PAGE_MASK) | + (addr & SPAPR_TCE_PAGE_MASK); + +#ifdef DEBUG_TCE + fprintf(stderr, " -> *paddr=0x" TARGET_FMT_plx ", *len=0x" + TARGET_FMT_plx "\n", *paddr, *len); +#endif + + return 0; +} + +DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size) +{ + sPAPRTCETable *tcet; + + if (spapr_tce_find_by_liobn(liobn)) { + fprintf(stderr, "Attempted to create TCE table with duplicate" + " LIOBN 0x%x\n", liobn); + return NULL; + } + + if (!window_size) { + return NULL; + } + + tcet = g_malloc0(sizeof(*tcet)); + dma_context_init(&tcet->dma, &address_space_memory, spapr_tce_translate, NULL, NULL); + + tcet->liobn = liobn; + tcet->window_size = window_size; + + if (kvm_enabled()) { + tcet->table = kvmppc_create_spapr_tce(liobn, + window_size, + &tcet->fd); + } + + if (!tcet->table) { + size_t table_size = (window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(sPAPRTCE); + tcet->table = g_malloc0(table_size); + } + +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_iommu: New TCE table, liobn=0x%x, context @ %p, " + "table @ %p, fd=%d\n", liobn, &tcet->dma, tcet->table, tcet->fd); +#endif + + QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); + + return &tcet->dma; +} + +void spapr_tce_free(DMAContext *dma) +{ + + if (dma) { + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + + QLIST_REMOVE(tcet, list); + + if (!kvm_enabled() || + (kvmppc_remove_spapr_tce(tcet->table, tcet->fd, + tcet->window_size) != 0)) { + g_free(tcet->table); + } + + g_free(tcet); + } +} + +void spapr_tce_set_bypass(DMAContext *dma, bool bypass) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + + tcet->bypass = bypass; +} + +void spapr_tce_reset(DMAContext *dma) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(sPAPRTCE); + + tcet->bypass = false; + memset(tcet->table, 0, table_size); +} + +static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, + target_ulong tce) +{ + sPAPRTCE *tcep; + + if (ioba >= tcet->window_size) { + hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x" + TARGET_FMT_lx "\n", ioba); + return H_PARAMETER; + } + + tcep = tcet->table + (ioba >> SPAPR_TCE_PAGE_SHIFT); + tcep->tce = tce; + + return H_SUCCESS; +} + +static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong liobn = args[0]; + target_ulong ioba = args[1]; + target_ulong tce = args[2]; + sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); + + if (liobn & 0xFFFFFFFF00000000ULL) { + hcall_dprintf("spapr_vio_put_tce on out-of-boundsw LIOBN " + TARGET_FMT_lx "\n", liobn); + return H_PARAMETER; + } + + ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1); + + if (tcet) { + return put_tce_emu(tcet, ioba, tce); + } +#ifdef DEBUG_TCE + fprintf(stderr, "%s on liobn=" TARGET_FMT_lx /*%s*/ + " ioba 0x" TARGET_FMT_lx " TCE 0x" TARGET_FMT_lx "\n", + __func__, liobn, /*dev->qdev.id, */ioba, tce); +#endif + + return H_PARAMETER; +} + +void spapr_iommu_init(void) +{ + QLIST_INIT(&spapr_tce_tables); + + /* hcall-tce */ + spapr_register_hypercall(H_PUT_TCE, h_put_tce); +} + +int spapr_dma_dt(void *fdt, int node_off, const char *propname, + uint32_t liobn, uint64_t window, uint32_t size) +{ + uint32_t dma_prop[5]; + int ret; + + dma_prop[0] = cpu_to_be32(liobn); + dma_prop[1] = cpu_to_be32(window >> 32); + dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF); + dma_prop[3] = 0; /* window size is 32 bits */ + dma_prop[4] = cpu_to_be32(size); + + ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2); + if (ret < 0) { + return ret; + } + + ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2); + if (ret < 0) { + return ret; + } + + ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop)); + if (ret < 0) { + return ret; + } + + return 0; +} + +int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, + DMAContext *iommu) +{ + if (!iommu) { + return 0; + } + + if (iommu->translate == spapr_tce_translate) { + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu); + return spapr_dma_dt(fdt, node_off, propname, + tcet->liobn, 0, tcet->window_size); + } + + return -1; +} diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c new file mode 100644 index 0000000000..5ec787f29d --- /dev/null +++ b/hw/ppc/spapr_rtas.c @@ -0,0 +1,334 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * Hypercall based emulated RTAS + * + * Copyright (c) 2010-2011 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "cpu.h" +#include "sysemu/sysemu.h" +#include "char/char.h" +#include "hw/qdev.h" +#include "sysemu/device_tree.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#include + +#define TOKEN_BASE 0x2000 +#define TOKEN_MAX 0x100 + +static void rtas_display_character(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint8_t c = rtas_ld(args, 0); + VIOsPAPRDevice *sdev = vty_lookup(spapr, 0); + + if (!sdev) { + rtas_st(rets, 0, -1); + } else { + vty_putchars(sdev, &c, sizeof(c)); + rtas_st(rets, 0, 0); + } +} + +static void rtas_get_time_of_day(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct tm tm; + + if (nret != 8) { + rtas_st(rets, 0, -3); + return; + } + + qemu_get_timedate(&tm, spapr->rtc_offset); + + rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 1, tm.tm_year + 1900); + rtas_st(rets, 2, tm.tm_mon + 1); + rtas_st(rets, 3, tm.tm_mday); + rtas_st(rets, 4, tm.tm_hour); + rtas_st(rets, 5, tm.tm_min); + rtas_st(rets, 6, tm.tm_sec); + rtas_st(rets, 7, 0); /* we don't do nanoseconds */ +} + +static void rtas_set_time_of_day(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct tm tm; + + tm.tm_year = rtas_ld(args, 0) - 1900; + tm.tm_mon = rtas_ld(args, 1) - 1; + tm.tm_mday = rtas_ld(args, 2); + tm.tm_hour = rtas_ld(args, 3); + tm.tm_min = rtas_ld(args, 4); + tm.tm_sec = rtas_ld(args, 5); + + /* Just generate a monitor event for the change */ + rtc_change_mon_event(&tm); + spapr->rtc_offset = qemu_timedate_diff(&tm); + + rtas_st(rets, 0, 0); /* Success */ +} + +static void rtas_power_off(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + if (nargs != 2 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + qemu_system_shutdown_request(); + rtas_st(rets, 0, 0); +} + +static void rtas_system_reboot(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + if (nargs != 0 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + qemu_system_reset_request(); + rtas_st(rets, 0, 0); +} + +static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong id; + CPUPPCState *env; + CPUState *cpu; + + if (nargs != 1 || nret != 2) { + rtas_st(rets, 0, -3); + return; + } + + id = rtas_ld(args, 0); + for (env = first_cpu; env; env = env->next_cpu) { + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index != id) { + continue; + } + + if (env->halted) { + rtas_st(rets, 1, 0); + } else { + rtas_st(rets, 1, 2); + } + + rtas_st(rets, 0, 0); + return; + } + + /* Didn't find a matching cpu */ + rtas_st(rets, 0, -3); +} + +static void rtas_start_cpu(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong id, start, r3; + CPUState *cpu; + CPUPPCState *env; + + if (nargs != 3 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + + id = rtas_ld(args, 0); + start = rtas_ld(args, 1); + r3 = rtas_ld(args, 2); + + for (env = first_cpu; env; env = env->next_cpu) { + cpu = CPU(ppc_env_get_cpu(env)); + + if (cpu->cpu_index != id) { + continue; + } + + if (!env->halted) { + rtas_st(rets, 0, -1); + return; + } + + /* This will make sure qemu state is up to date with kvm, and + * mark it dirty so our changes get flushed back before the + * new cpu enters */ + kvm_cpu_synchronize_state(env); + + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); + env->nip = start; + env->gpr[3] = r3; + env->halted = 0; + + qemu_cpu_kick(cpu); + + rtas_st(rets, 0, 0); + return; + } + + /* Didn't find a matching cpu */ + rtas_st(rets, 0, -3); +} + +static struct rtas_call { + const char *name; + spapr_rtas_fn fn; +} rtas_table[TOKEN_MAX]; + +struct rtas_call *rtas_next = rtas_table; + +target_ulong spapr_rtas_call(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + if ((token >= TOKEN_BASE) + && ((token - TOKEN_BASE) < TOKEN_MAX)) { + struct rtas_call *call = rtas_table + (token - TOKEN_BASE); + + if (call->fn) { + call->fn(spapr, token, nargs, args, nret, rets); + return H_SUCCESS; + } + } + + /* HACK: Some Linux early debug code uses RTAS display-character, + * but assumes the token value is 0xa (which it is on some real + * machines) without looking it up in the device tree. This + * special case makes this work */ + if (token == 0xa) { + rtas_display_character(spapr, 0xa, nargs, args, nret, rets); + return H_SUCCESS; + } + + hcall_dprintf("Unknown RTAS token 0x%x\n", token); + rtas_st(rets, 0, -3); + return H_PARAMETER; +} + +int spapr_rtas_register(const char *name, spapr_rtas_fn fn) +{ + int i; + + for (i = 0; i < (rtas_next - rtas_table); i++) { + if (strcmp(name, rtas_table[i].name) == 0) { + fprintf(stderr, "RTAS call \"%s\" registered twice\n", name); + exit(1); + } + } + + assert(rtas_next < (rtas_table + TOKEN_MAX)); + + rtas_next->name = name; + rtas_next->fn = fn; + + return (rtas_next++ - rtas_table) + TOKEN_BASE; +} + +int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, + hwaddr rtas_size) +{ + int ret; + int i; + + ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size); + if (ret < 0) { + fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base", + rtas_addr); + if (ret < 0) { + fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry", + rtas_addr); + if (ret < 0) { + fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size", + rtas_size); + if (ret < 0) { + fprintf(stderr, "Couldn't add rtas-size property: %s\n", + fdt_strerror(ret)); + return ret; + } + + for (i = 0; i < TOKEN_MAX; i++) { + struct rtas_call *call = &rtas_table[i]; + + if (!call->name) { + continue; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name, + i + TOKEN_BASE); + if (ret < 0) { + fprintf(stderr, "Couldn't add rtas token for %s: %s\n", + call->name, fdt_strerror(ret)); + return ret; + } + + } + return 0; +} + +static void core_rtas_register_types(void) +{ + spapr_rtas_register("display-character", rtas_display_character); + spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); + spapr_rtas_register("set-time-of-day", rtas_set_time_of_day); + spapr_rtas_register("power-off", rtas_power_off); + spapr_rtas_register("system-reboot", rtas_system_reboot); + spapr_rtas_register("query-cpu-stopped-state", + rtas_query_cpu_stopped_state); + spapr_rtas_register("start-cpu", rtas_start_cpu); +} + +type_init(core_rtas_register_types) diff --git a/hw/spapr_events.c b/hw/spapr_events.c deleted file mode 100644 index ce78f0922e..0000000000 --- a/hw/spapr_events.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator - * - * RTAS events handling - * - * Copyright (c) 2012 David Gibson, IBM Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ -#include "cpu.h" -#include "sysemu/sysemu.h" -#include "char/char.h" -#include "hw/qdev.h" -#include "sysemu/device_tree.h" - -#include "hw/spapr.h" -#include "hw/spapr_vio.h" - -#include - -struct rtas_error_log { - uint32_t summary; -#define RTAS_LOG_VERSION_MASK 0xff000000 -#define RTAS_LOG_VERSION_6 0x06000000 -#define RTAS_LOG_SEVERITY_MASK 0x00e00000 -#define RTAS_LOG_SEVERITY_ALREADY_REPORTED 0x00c00000 -#define RTAS_LOG_SEVERITY_FATAL 0x00a00000 -#define RTAS_LOG_SEVERITY_ERROR 0x00800000 -#define RTAS_LOG_SEVERITY_ERROR_SYNC 0x00600000 -#define RTAS_LOG_SEVERITY_WARNING 0x00400000 -#define RTAS_LOG_SEVERITY_EVENT 0x00200000 -#define RTAS_LOG_SEVERITY_NO_ERROR 0x00000000 -#define RTAS_LOG_DISPOSITION_MASK 0x00180000 -#define RTAS_LOG_DISPOSITION_FULLY_RECOVERED 0x00000000 -#define RTAS_LOG_DISPOSITION_LIMITED_RECOVERY 0x00080000 -#define RTAS_LOG_DISPOSITION_NOT_RECOVERED 0x00100000 -#define RTAS_LOG_OPTIONAL_PART_PRESENT 0x00040000 -#define RTAS_LOG_INITIATOR_MASK 0x0000f000 -#define RTAS_LOG_INITIATOR_UNKNOWN 0x00000000 -#define RTAS_LOG_INITIATOR_CPU 0x00001000 -#define RTAS_LOG_INITIATOR_PCI 0x00002000 -#define RTAS_LOG_INITIATOR_MEMORY 0x00004000 -#define RTAS_LOG_INITIATOR_HOTPLUG 0x00006000 -#define RTAS_LOG_TARGET_MASK 0x00000f00 -#define RTAS_LOG_TARGET_UNKNOWN 0x00000000 -#define RTAS_LOG_TARGET_CPU 0x00000100 -#define RTAS_LOG_TARGET_PCI 0x00000200 -#define RTAS_LOG_TARGET_MEMORY 0x00000400 -#define RTAS_LOG_TARGET_HOTPLUG 0x00000600 -#define RTAS_LOG_TYPE_MASK 0x000000ff -#define RTAS_LOG_TYPE_OTHER 0x00000000 -#define RTAS_LOG_TYPE_RETRY 0x00000001 -#define RTAS_LOG_TYPE_TCE_ERR 0x00000002 -#define RTAS_LOG_TYPE_INTERN_DEV_FAIL 0x00000003 -#define RTAS_LOG_TYPE_TIMEOUT 0x00000004 -#define RTAS_LOG_TYPE_DATA_PARITY 0x00000005 -#define RTAS_LOG_TYPE_ADDR_PARITY 0x00000006 -#define RTAS_LOG_TYPE_CACHE_PARITY 0x00000007 -#define RTAS_LOG_TYPE_ADDR_INVALID 0x00000008 -#define RTAS_LOG_TYPE_ECC_UNCORR 0x00000009 -#define RTAS_LOG_TYPE_ECC_CORR 0x0000000a -#define RTAS_LOG_TYPE_EPOW 0x00000040 - uint32_t extended_length; -} QEMU_PACKED; - -struct rtas_event_log_v6 { - uint8_t b0; -#define RTAS_LOG_V6_B0_VALID 0x80 -#define RTAS_LOG_V6_B0_UNRECOVERABLE_ERROR 0x40 -#define RTAS_LOG_V6_B0_RECOVERABLE_ERROR 0x20 -#define RTAS_LOG_V6_B0_DEGRADED_OPERATION 0x10 -#define RTAS_LOG_V6_B0_PREDICTIVE_ERROR 0x08 -#define RTAS_LOG_V6_B0_NEW_LOG 0x04 -#define RTAS_LOG_V6_B0_BIGENDIAN 0x02 - uint8_t _resv1; - uint8_t b2; -#define RTAS_LOG_V6_B2_POWERPC_FORMAT 0x80 -#define RTAS_LOG_V6_B2_LOG_FORMAT_MASK 0x0f -#define RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT 0x0e - uint8_t _resv2[9]; - uint32_t company; -#define RTAS_LOG_V6_COMPANY_IBM 0x49424d00 /* IBM */ -} QEMU_PACKED; - -struct rtas_event_log_v6_section_header { - uint16_t section_id; - uint16_t section_length; - uint8_t section_version; - uint8_t section_subtype; - uint16_t creator_component_id; -} QEMU_PACKED; - -struct rtas_event_log_v6_maina { -#define RTAS_LOG_V6_SECTION_ID_MAINA 0x5048 /* PH */ - struct rtas_event_log_v6_section_header hdr; - uint32_t creation_date; /* BCD: YYYYMMDD */ - uint32_t creation_time; /* BCD: HHMMSS00 */ - uint8_t _platform1[8]; - char creator_id; - uint8_t _resv1[2]; - uint8_t section_count; - uint8_t _resv2[4]; - uint8_t _platform2[8]; - uint32_t plid; - uint8_t _platform3[4]; -} QEMU_PACKED; - -struct rtas_event_log_v6_mainb { -#define RTAS_LOG_V6_SECTION_ID_MAINB 0x5548 /* UH */ - struct rtas_event_log_v6_section_header hdr; - uint8_t subsystem_id; - uint8_t _platform1; - uint8_t event_severity; - uint8_t event_subtype; - uint8_t _platform2[4]; - uint8_t _resv1[2]; - uint16_t action_flags; - uint8_t _resv2[4]; -} QEMU_PACKED; - -struct rtas_event_log_v6_epow { -#define RTAS_LOG_V6_SECTION_ID_EPOW 0x4550 /* EP */ - struct rtas_event_log_v6_section_header hdr; - uint8_t sensor_value; -#define RTAS_LOG_V6_EPOW_ACTION_RESET 0 -#define RTAS_LOG_V6_EPOW_ACTION_WARN_COOLING 1 -#define RTAS_LOG_V6_EPOW_ACTION_WARN_POWER 2 -#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN 3 -#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_HALT 4 -#define RTAS_LOG_V6_EPOW_ACTION_MAIN_ENCLOSURE 5 -#define RTAS_LOG_V6_EPOW_ACTION_POWER_OFF 7 - uint8_t event_modifier; -#define RTAS_LOG_V6_EPOW_MODIFIER_NORMAL 1 -#define RTAS_LOG_V6_EPOW_MODIFIER_ON_UPS 2 -#define RTAS_LOG_V6_EPOW_MODIFIER_CRITICAL 3 -#define RTAS_LOG_V6_EPOW_MODIFIER_TEMPERATURE 4 - uint8_t extended_modifier; -#define RTAS_LOG_V6_EPOW_XMODIFIER_SYSTEM_WIDE 0 -#define RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC 1 - uint8_t _resv; - uint64_t reason_code; -} QEMU_PACKED; - -struct epow_log_full { - struct rtas_error_log hdr; - struct rtas_event_log_v6 v6hdr; - struct rtas_event_log_v6_maina maina; - struct rtas_event_log_v6_mainb mainb; - struct rtas_event_log_v6_epow epow; -} QEMU_PACKED; - -#define EVENT_MASK_INTERNAL_ERRORS 0x80000000 -#define EVENT_MASK_EPOW 0x40000000 -#define EVENT_MASK_HOTPLUG 0x10000000 -#define EVENT_MASK_IO 0x08000000 - -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) - -void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq) -{ - uint32_t epow_irq_ranges[] = {cpu_to_be32(epow_irq), cpu_to_be32(1)}; - uint32_t epow_interrupts[] = {cpu_to_be32(epow_irq), 0}; - - _FDT((fdt_begin_node(fdt, "event-sources"))); - - _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); - _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); - _FDT((fdt_property(fdt, "interrupt-ranges", - epow_irq_ranges, sizeof(epow_irq_ranges)))); - - _FDT((fdt_begin_node(fdt, "epow-events"))); - _FDT((fdt_property(fdt, "interrupts", - epow_interrupts, sizeof(epow_interrupts)))); - _FDT((fdt_end_node(fdt))); - - _FDT((fdt_end_node(fdt))); -} - -static struct epow_log_full *pending_epow; -static uint32_t next_plid; - -static void spapr_powerdown_req(Notifier *n, void *opaque) -{ - sPAPREnvironment *spapr = container_of(n, sPAPREnvironment, epow_notifier); - struct rtas_error_log *hdr; - struct rtas_event_log_v6 *v6hdr; - struct rtas_event_log_v6_maina *maina; - struct rtas_event_log_v6_mainb *mainb; - struct rtas_event_log_v6_epow *epow; - struct tm tm; - int year; - - if (pending_epow) { - /* For now, we just throw away earlier events if two come - * along before any are consumed. This is sufficient for our - * powerdown messages, but we'll need more if we do more - * general error/event logging */ - g_free(pending_epow); - } - pending_epow = g_malloc0(sizeof(*pending_epow)); - hdr = &pending_epow->hdr; - v6hdr = &pending_epow->v6hdr; - maina = &pending_epow->maina; - mainb = &pending_epow->mainb; - epow = &pending_epow->epow; - - hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6 - | RTAS_LOG_SEVERITY_EVENT - | RTAS_LOG_DISPOSITION_NOT_RECOVERED - | RTAS_LOG_OPTIONAL_PART_PRESENT - | RTAS_LOG_TYPE_EPOW); - hdr->extended_length = cpu_to_be32(sizeof(*pending_epow) - - sizeof(pending_epow->hdr)); - - v6hdr->b0 = RTAS_LOG_V6_B0_VALID | RTAS_LOG_V6_B0_NEW_LOG - | RTAS_LOG_V6_B0_BIGENDIAN; - v6hdr->b2 = RTAS_LOG_V6_B2_POWERPC_FORMAT - | RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT; - v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM); - - maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA); - maina->hdr.section_length = cpu_to_be16(sizeof(*maina)); - /* FIXME: section version, subtype and creator id? */ - qemu_get_timedate(&tm, spapr->rtc_offset); - year = tm.tm_year + 1900; - maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24) - | (to_bcd(year % 100) << 16) - | (to_bcd(tm.tm_mon + 1) << 8) - | to_bcd(tm.tm_mday)); - maina->creation_time = cpu_to_be32((to_bcd(tm.tm_hour) << 24) - | (to_bcd(tm.tm_min) << 16) - | (to_bcd(tm.tm_sec) << 8)); - maina->creator_id = 'H'; /* Hypervisor */ - maina->section_count = 3; /* Main-A, Main-B and EPOW */ - maina->plid = next_plid++; - - mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB); - mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb)); - /* FIXME: section version, subtype and creator id? */ - mainb->subsystem_id = 0xa0; /* External environment */ - mainb->event_severity = 0x00; /* Informational / non-error */ - mainb->event_subtype = 0xd0; /* Normal shutdown */ - - epow->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_EPOW); - epow->hdr.section_length = cpu_to_be16(sizeof(*epow)); - epow->hdr.section_version = 2; /* includes extended modifier */ - /* FIXME: section subtype and creator id? */ - epow->sensor_value = RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN; - epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL; - epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC; - - qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->epow_irq)); -} - -static void check_exception(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - uint32_t mask, buf, len; - uint64_t xinfo; - - if ((nargs < 6) || (nargs > 7) || nret != 1) { - rtas_st(rets, 0, -3); - return; - } - - xinfo = rtas_ld(args, 1); - mask = rtas_ld(args, 2); - buf = rtas_ld(args, 4); - len = rtas_ld(args, 5); - if (nargs == 7) { - xinfo |= (uint64_t)rtas_ld(args, 6) << 32; - } - - if ((mask & EVENT_MASK_EPOW) && pending_epow) { - if (sizeof(*pending_epow) < len) { - len = sizeof(*pending_epow); - } - - cpu_physical_memory_write(buf, pending_epow, len); - g_free(pending_epow); - pending_epow = NULL; - rtas_st(rets, 0, 0); - } else { - rtas_st(rets, 0, 1); - } -} - -void spapr_events_init(sPAPREnvironment *spapr) -{ - spapr->epow_irq = spapr_allocate_msi(0); - spapr->epow_notifier.notify = spapr_powerdown_req; - qemu_register_powerdown_notifier(&spapr->epow_notifier); - spapr_rtas_register("check-exception", check_exception); -} diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c deleted file mode 100644 index 7b8959488e..0000000000 --- a/hw/spapr_hcall.c +++ /dev/null @@ -1,741 +0,0 @@ -#include "sysemu/sysemu.h" -#include "cpu.h" -#include "sysemu/sysemu.h" -#include "helper_regs.h" -#include "hw/spapr.h" - -#define HPTES_PER_GROUP 8 - -#define HPTE_V_SSIZE_SHIFT 62 -#define HPTE_V_AVPN_SHIFT 7 -#define HPTE_V_AVPN 0x3fffffffffffff80ULL -#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT) -#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL)) -#define HPTE_V_BOLTED 0x0000000000000010ULL -#define HPTE_V_LOCK 0x0000000000000008ULL -#define HPTE_V_LARGE 0x0000000000000004ULL -#define HPTE_V_SECONDARY 0x0000000000000002ULL -#define HPTE_V_VALID 0x0000000000000001ULL - -#define HPTE_R_PP0 0x8000000000000000ULL -#define HPTE_R_TS 0x4000000000000000ULL -#define HPTE_R_KEY_HI 0x3000000000000000ULL -#define HPTE_R_RPN_SHIFT 12 -#define HPTE_R_RPN 0x3ffffffffffff000ULL -#define HPTE_R_FLAGS 0x00000000000003ffULL -#define HPTE_R_PP 0x0000000000000003ULL -#define HPTE_R_N 0x0000000000000004ULL -#define HPTE_R_G 0x0000000000000008ULL -#define HPTE_R_M 0x0000000000000010ULL -#define HPTE_R_I 0x0000000000000020ULL -#define HPTE_R_W 0x0000000000000040ULL -#define HPTE_R_WIMG 0x0000000000000078ULL -#define HPTE_R_C 0x0000000000000080ULL -#define HPTE_R_R 0x0000000000000100ULL -#define HPTE_R_KEY_LO 0x0000000000000e00ULL - -#define HPTE_V_1TB_SEG 0x4000000000000000ULL -#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL - -static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, - target_ulong pte_index) -{ - target_ulong rb, va_low; - - rb = (v & ~0x7fULL) << 16; /* AVA field */ - va_low = pte_index >> 3; - if (v & HPTE_V_SECONDARY) { - va_low = ~va_low; - } - /* xor vsid from AVA */ - if (!(v & HPTE_V_1TB_SEG)) { - va_low ^= v >> 12; - } else { - va_low ^= v >> 24; - } - va_low &= 0x7ff; - if (v & HPTE_V_LARGE) { - rb |= 1; /* L field */ -#if 0 /* Disable that P7 specific bit for now */ - if (r & 0xff000) { - /* non-16MB large page, must be 64k */ - /* (masks depend on page size) */ - rb |= 0x1000; /* page encoding in LP field */ - rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ - rb |= (va_low & 0xfe); /* AVAL field */ - } -#endif - } else { - /* 4kB page */ - rb |= (va_low & 0x7ff) << 12; /* remaining 11b of AVA */ - } - rb |= (v >> 54) & 0x300; /* B field */ - return rb; -} - -static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - target_ulong flags = args[0]; - target_ulong pte_index = args[1]; - target_ulong pteh = args[2]; - target_ulong ptel = args[3]; - target_ulong page_shift = 12; - target_ulong raddr; - target_ulong i; - uint8_t *hpte; - - /* only handle 4k and 16M pages for now */ - if (pteh & HPTE_V_LARGE) { -#if 0 /* We don't support 64k pages yet */ - if ((ptel & 0xf000) == 0x1000) { - /* 64k page */ - } else -#endif - if ((ptel & 0xff000) == 0) { - /* 16M page */ - page_shift = 24; - /* lowest AVA bit must be 0 for 16M pages */ - if (pteh & 0x80) { - return H_PARAMETER; - } - } else { - return H_PARAMETER; - } - } - - raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1); - - if (raddr < spapr->ram_limit) { - /* Regular RAM - should have WIMG=0010 */ - if ((ptel & HPTE_R_WIMG) != HPTE_R_M) { - return H_PARAMETER; - } - } else { - /* Looks like an IO address */ - /* FIXME: What WIMG combinations could be sensible for IO? - * For now we allow WIMG=010x, but are there others? */ - /* FIXME: Should we check against registered IO addresses? */ - if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) { - return H_PARAMETER; - } - } - - pteh &= ~0x60ULL; - - if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { - return H_PARAMETER; - } - if (likely((flags & H_EXACT) == 0)) { - pte_index &= ~7ULL; - hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - for (i = 0; ; ++i) { - if (i == 8) { - return H_PTEG_FULL; - } - if ((ldq_p(hpte) & HPTE_V_VALID) == 0) { - break; - } - hpte += HASH_PTE_SIZE_64; - } - } else { - i = 0; - hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - if (ldq_p(hpte) & HPTE_V_VALID) { - return H_PTEG_FULL; - } - } - stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel); - /* eieio(); FIXME: need some sort of barrier for smp? */ - stq_p(hpte, pteh); - - args[0] = pte_index + i; - return H_SUCCESS; -} - -enum { - REMOVE_SUCCESS = 0, - REMOVE_NOT_FOUND = 1, - REMOVE_PARM = 2, - REMOVE_HW = 3, -}; - -static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, - target_ulong avpn, - target_ulong flags, - target_ulong *vp, target_ulong *rp) -{ - uint8_t *hpte; - target_ulong v, r, rb; - - if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) { - return REMOVE_PARM; - } - - hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64); - - v = ldq_p(hpte); - r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); - - if ((v & HPTE_V_VALID) == 0 || - ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || - ((flags & H_ANDCOND) && (v & avpn) != 0)) { - return REMOVE_NOT_FOUND; - } - *vp = v; - *rp = r; - stq_p(hpte, 0); - rb = compute_tlbie_rb(v, r, ptex); - ppc_tlb_invalidate_one(env, rb); - return REMOVE_SUCCESS; -} - -static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - target_ulong flags = args[0]; - target_ulong pte_index = args[1]; - target_ulong avpn = args[2]; - int ret; - - ret = remove_hpte(env, pte_index, avpn, flags, - &args[0], &args[1]); - - switch (ret) { - case REMOVE_SUCCESS: - return H_SUCCESS; - - case REMOVE_NOT_FOUND: - return H_NOT_FOUND; - - case REMOVE_PARM: - return H_PARAMETER; - - case REMOVE_HW: - return H_HARDWARE; - } - - assert(0); -} - -#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL -#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL -#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL -#define H_BULK_REMOVE_END 0xc000000000000000ULL -#define H_BULK_REMOVE_CODE 0x3000000000000000ULL -#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL -#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL -#define H_BULK_REMOVE_PARM 0x2000000000000000ULL -#define H_BULK_REMOVE_HW 0x3000000000000000ULL -#define H_BULK_REMOVE_RC 0x0c00000000000000ULL -#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL -#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL -#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL -#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL -#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL - -#define H_BULK_REMOVE_MAX_BATCH 4 - -static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - int i; - - for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { - target_ulong *tsh = &args[i*2]; - target_ulong tsl = args[i*2 + 1]; - target_ulong v, r, ret; - - if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { - break; - } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { - return H_PARAMETER; - } - - *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; - *tsh |= H_BULK_REMOVE_RESPONSE; - - if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { - *tsh |= H_BULK_REMOVE_PARM; - return H_PARAMETER; - } - - ret = remove_hpte(env, *tsh & H_BULK_REMOVE_PTEX, tsl, - (*tsh & H_BULK_REMOVE_FLAGS) >> 26, - &v, &r); - - *tsh |= ret << 60; - - switch (ret) { - case REMOVE_SUCCESS: - *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43; - break; - - case REMOVE_PARM: - return H_PARAMETER; - - case REMOVE_HW: - return H_HARDWARE; - } - } - - return H_SUCCESS; -} - -static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - target_ulong flags = args[0]; - target_ulong pte_index = args[1]; - target_ulong avpn = args[2]; - uint8_t *hpte; - target_ulong v, r, rb; - - if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { - return H_PARAMETER; - } - - hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - - v = ldq_p(hpte); - r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); - - if ((v & HPTE_V_VALID) == 0 || - ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { - return H_NOT_FOUND; - } - - r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | - HPTE_R_KEY_HI | HPTE_R_KEY_LO); - r |= (flags << 55) & HPTE_R_PP0; - r |= (flags << 48) & HPTE_R_KEY_HI; - r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO); - rb = compute_tlbie_rb(v, r, pte_index); - stq_p(hpte, v & ~HPTE_V_VALID); - ppc_tlb_invalidate_one(env, rb); - stq_p(hpte + (HASH_PTE_SIZE_64/2), r); - /* Don't need a memory barrier, due to qemu's global lock */ - stq_p(hpte, v); - return H_SUCCESS; -} - -static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - /* FIXME: actually implement this */ - return H_HARDWARE; -} - -#define FLAGS_REGISTER_VPA 0x0000200000000000ULL -#define FLAGS_REGISTER_DTL 0x0000400000000000ULL -#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL -#define FLAGS_DEREGISTER_VPA 0x0000a00000000000ULL -#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL -#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL - -#define VPA_MIN_SIZE 640 -#define VPA_SIZE_OFFSET 0x4 -#define VPA_SHARED_PROC_OFFSET 0x9 -#define VPA_SHARED_PROC_VAL 0x2 - -static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa) -{ - uint16_t size; - uint8_t tmp; - - if (vpa == 0) { - hcall_dprintf("Can't cope with registering a VPA at logical 0\n"); - return H_HARDWARE; - } - - if (vpa % env->dcache_line_size) { - return H_PARAMETER; - } - /* FIXME: bounds check the address */ - - size = lduw_be_phys(vpa + 0x4); - - if (size < VPA_MIN_SIZE) { - return H_PARAMETER; - } - - /* VPA is not allowed to cross a page boundary */ - if ((vpa / 4096) != ((vpa + size - 1) / 4096)) { - return H_PARAMETER; - } - - env->vpa_addr = vpa; - - tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET); - tmp |= VPA_SHARED_PROC_VAL; - stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp); - - return H_SUCCESS; -} - -static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa) -{ - if (env->slb_shadow_addr) { - return H_RESOURCE; - } - - if (env->dtl_addr) { - return H_RESOURCE; - } - - env->vpa_addr = 0; - return H_SUCCESS; -} - -static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr) -{ - uint32_t size; - - if (addr == 0) { - hcall_dprintf("Can't cope with SLB shadow at logical 0\n"); - return H_HARDWARE; - } - - size = ldl_be_phys(addr + 0x4); - if (size < 0x8) { - return H_PARAMETER; - } - - if ((addr / 4096) != ((addr + size - 1) / 4096)) { - return H_PARAMETER; - } - - if (!env->vpa_addr) { - return H_RESOURCE; - } - - env->slb_shadow_addr = addr; - env->slb_shadow_size = size; - - return H_SUCCESS; -} - -static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr) -{ - env->slb_shadow_addr = 0; - env->slb_shadow_size = 0; - return H_SUCCESS; -} - -static target_ulong register_dtl(CPUPPCState *env, target_ulong addr) -{ - uint32_t size; - - if (addr == 0) { - hcall_dprintf("Can't cope with DTL at logical 0\n"); - return H_HARDWARE; - } - - size = ldl_be_phys(addr + 0x4); - - if (size < 48) { - return H_PARAMETER; - } - - if (!env->vpa_addr) { - return H_RESOURCE; - } - - env->dtl_addr = addr; - env->dtl_size = size; - - return H_SUCCESS; -} - -static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr) -{ - env->dtl_addr = 0; - env->dtl_size = 0; - - return H_SUCCESS; -} - -static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong flags = args[0]; - target_ulong procno = args[1]; - target_ulong vpa = args[2]; - target_ulong ret = H_PARAMETER; - CPUPPCState *tenv; - CPUState *tcpu; - - tcpu = qemu_get_cpu(procno); - if (!tcpu) { - return H_PARAMETER; - } - tenv = tcpu->env_ptr; - - switch (flags) { - case FLAGS_REGISTER_VPA: - ret = register_vpa(tenv, vpa); - break; - - case FLAGS_DEREGISTER_VPA: - ret = deregister_vpa(tenv, vpa); - break; - - case FLAGS_REGISTER_SLBSHADOW: - ret = register_slb_shadow(tenv, vpa); - break; - - case FLAGS_DEREGISTER_SLBSHADOW: - ret = deregister_slb_shadow(tenv, vpa); - break; - - case FLAGS_REGISTER_DTL: - ret = register_dtl(tenv, vpa); - break; - - case FLAGS_DEREGISTER_DTL: - ret = deregister_dtl(tenv, vpa); - break; - } - - return ret; -} - -static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - CPUState *cs = CPU(cpu); - - env->msr |= (1ULL << MSR_EE); - hreg_compute_hflags(env); - if (!cpu_has_work(cs)) { - env->halted = 1; - env->exception_index = EXCP_HLT; - cs->exit_request = 1; - } - return H_SUCCESS; -} - -static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong rtas_r3 = args[0]; - uint32_t token = ldl_be_phys(rtas_r3); - uint32_t nargs = ldl_be_phys(rtas_r3 + 4); - uint32_t nret = ldl_be_phys(rtas_r3 + 8); - - return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12, - nret, rtas_r3 + 12 + 4*nargs); -} - -static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong size = args[0]; - target_ulong addr = args[1]; - - switch (size) { - case 1: - args[0] = ldub_phys(addr); - return H_SUCCESS; - case 2: - args[0] = lduw_phys(addr); - return H_SUCCESS; - case 4: - args[0] = ldl_phys(addr); - return H_SUCCESS; - case 8: - args[0] = ldq_phys(addr); - return H_SUCCESS; - } - return H_PARAMETER; -} - -static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong size = args[0]; - target_ulong addr = args[1]; - target_ulong val = args[2]; - - switch (size) { - case 1: - stb_phys(addr, val); - return H_SUCCESS; - case 2: - stw_phys(addr, val); - return H_SUCCESS; - case 4: - stl_phys(addr, val); - return H_SUCCESS; - case 8: - stq_phys(addr, val); - return H_SUCCESS; - } - return H_PARAMETER; -} - -static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong dst = args[0]; /* Destination address */ - target_ulong src = args[1]; /* Source address */ - target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */ - target_ulong count = args[3]; /* Element count */ - target_ulong op = args[4]; /* 0 = copy, 1 = invert */ - uint64_t tmp; - unsigned int mask = (1 << esize) - 1; - int step = 1 << esize; - - if (count > 0x80000000) { - return H_PARAMETER; - } - - if ((dst & mask) || (src & mask) || (op > 1)) { - return H_PARAMETER; - } - - if (dst >= src && dst < (src + (count << esize))) { - dst = dst + ((count - 1) << esize); - src = src + ((count - 1) << esize); - step = -step; - } - - while (count--) { - switch (esize) { - case 0: - tmp = ldub_phys(src); - break; - case 1: - tmp = lduw_phys(src); - break; - case 2: - tmp = ldl_phys(src); - break; - case 3: - tmp = ldq_phys(src); - break; - default: - return H_PARAMETER; - } - if (op == 1) { - tmp = ~tmp; - } - switch (esize) { - case 0: - stb_phys(dst, tmp); - break; - case 1: - stw_phys(dst, tmp); - break; - case 2: - stl_phys(dst, tmp); - break; - case 3: - stq_phys(dst, tmp); - break; - } - dst = dst + step; - src = src + step; - } - - return H_SUCCESS; -} - -static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - /* Nothing to do on emulation, KVM will trap this in the kernel */ - return H_SUCCESS; -} - -static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - /* Nothing to do on emulation, KVM will trap this in the kernel */ - return H_SUCCESS; -} - -static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; -static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; - -void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) -{ - spapr_hcall_fn *slot; - - if (opcode <= MAX_HCALL_OPCODE) { - assert((opcode & 0x3) == 0); - - slot = &papr_hypercall_table[opcode / 4]; - } else { - assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)); - - slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; - } - - assert(!(*slot)); - *slot = fn; -} - -target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, - target_ulong *args) -{ - if ((opcode <= MAX_HCALL_OPCODE) - && ((opcode & 0x3) == 0)) { - spapr_hcall_fn fn = papr_hypercall_table[opcode / 4]; - - if (fn) { - return fn(cpu, spapr, opcode, args); - } - } else if ((opcode >= KVMPPC_HCALL_BASE) && - (opcode <= KVMPPC_HCALL_MAX)) { - spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; - - if (fn) { - return fn(cpu, spapr, opcode, args); - } - } - - hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode); - return H_FUNCTION; -} - -static void hypercall_register_types(void) -{ - /* hcall-pft */ - spapr_register_hypercall(H_ENTER, h_enter); - spapr_register_hypercall(H_REMOVE, h_remove); - spapr_register_hypercall(H_PROTECT, h_protect); - - /* hcall-bulk */ - spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); - - /* hcall-dabr */ - spapr_register_hypercall(H_SET_DABR, h_set_dabr); - - /* hcall-splpar */ - spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa); - spapr_register_hypercall(H_CEDE, h_cede); - - /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate - * here between the "CI" and the "CACHE" variants, they will use whatever - * mapping attributes qemu is using. When using KVM, the kernel will - * enforce the attributes more strongly - */ - spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load); - spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store); - spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load); - spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store); - spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi); - spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf); - spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop); - - /* qemu/KVM-PPC specific hcalls */ - spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); -} - -type_init(hypercall_register_types) diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c deleted file mode 100644 index 8d500bf6be..0000000000 --- a/hw/spapr_iommu.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * QEMU sPAPR IOMMU (TCE) code - * - * Copyright (c) 2010 David Gibson, IBM Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -#include "hw/hw.h" -#include "sysemu/kvm.h" -#include "hw/qdev.h" -#include "kvm_ppc.h" -#include "sysemu/dma.h" -#include "exec/address-spaces.h" - -#include "hw/spapr.h" - -#include - -/* #define DEBUG_TCE */ - -enum sPAPRTCEAccess { - SPAPR_TCE_FAULT = 0, - SPAPR_TCE_RO = 1, - SPAPR_TCE_WO = 2, - SPAPR_TCE_RW = 3, -}; - -typedef struct sPAPRTCETable sPAPRTCETable; - -struct sPAPRTCETable { - DMAContext dma; - uint32_t liobn; - uint32_t window_size; - sPAPRTCE *table; - bool bypass; - int fd; - QLIST_ENTRY(sPAPRTCETable) list; -}; - - -QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; - -static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) -{ - sPAPRTCETable *tcet; - - QLIST_FOREACH(tcet, &spapr_tce_tables, list) { - if (tcet->liobn == liobn) { - return tcet; - } - } - - return NULL; -} - -static int spapr_tce_translate(DMAContext *dma, - dma_addr_t addr, - hwaddr *paddr, - hwaddr *len, - DMADirection dir) -{ - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - enum sPAPRTCEAccess access = (dir == DMA_DIRECTION_FROM_DEVICE) - ? SPAPR_TCE_WO : SPAPR_TCE_RO; - uint64_t tce; - -#ifdef DEBUG_TCE - fprintf(stderr, "spapr_tce_translate liobn=0x%" PRIx32 " addr=0x" - DMA_ADDR_FMT "\n", tcet->liobn, addr); -#endif - - if (tcet->bypass) { - *paddr = addr; - *len = (hwaddr)-1; - return 0; - } - - /* Check if we are in bound */ - if (addr >= tcet->window_size) { -#ifdef DEBUG_TCE - fprintf(stderr, "spapr_tce_translate out of bounds\n"); -#endif - return -EFAULT; - } - - tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce; - - /* Check TCE */ - if (!(tce & access)) { - return -EPERM; - } - - /* How much til end of page ? */ - *len = ((~addr) & SPAPR_TCE_PAGE_MASK) + 1; - - /* Translate */ - *paddr = (tce & ~SPAPR_TCE_PAGE_MASK) | - (addr & SPAPR_TCE_PAGE_MASK); - -#ifdef DEBUG_TCE - fprintf(stderr, " -> *paddr=0x" TARGET_FMT_plx ", *len=0x" - TARGET_FMT_plx "\n", *paddr, *len); -#endif - - return 0; -} - -DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size) -{ - sPAPRTCETable *tcet; - - if (spapr_tce_find_by_liobn(liobn)) { - fprintf(stderr, "Attempted to create TCE table with duplicate" - " LIOBN 0x%x\n", liobn); - return NULL; - } - - if (!window_size) { - return NULL; - } - - tcet = g_malloc0(sizeof(*tcet)); - dma_context_init(&tcet->dma, &address_space_memory, spapr_tce_translate, NULL, NULL); - - tcet->liobn = liobn; - tcet->window_size = window_size; - - if (kvm_enabled()) { - tcet->table = kvmppc_create_spapr_tce(liobn, - window_size, - &tcet->fd); - } - - if (!tcet->table) { - size_t table_size = (window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); - tcet->table = g_malloc0(table_size); - } - -#ifdef DEBUG_TCE - fprintf(stderr, "spapr_iommu: New TCE table, liobn=0x%x, context @ %p, " - "table @ %p, fd=%d\n", liobn, &tcet->dma, tcet->table, tcet->fd); -#endif - - QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); - - return &tcet->dma; -} - -void spapr_tce_free(DMAContext *dma) -{ - - if (dma) { - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - - QLIST_REMOVE(tcet, list); - - if (!kvm_enabled() || - (kvmppc_remove_spapr_tce(tcet->table, tcet->fd, - tcet->window_size) != 0)) { - g_free(tcet->table); - } - - g_free(tcet); - } -} - -void spapr_tce_set_bypass(DMAContext *dma, bool bypass) -{ - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - - tcet->bypass = bypass; -} - -void spapr_tce_reset(DMAContext *dma) -{ - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); - - tcet->bypass = false; - memset(tcet->table, 0, table_size); -} - -static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, - target_ulong tce) -{ - sPAPRTCE *tcep; - - if (ioba >= tcet->window_size) { - hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x" - TARGET_FMT_lx "\n", ioba); - return H_PARAMETER; - } - - tcep = tcet->table + (ioba >> SPAPR_TCE_PAGE_SHIFT); - tcep->tce = tce; - - return H_SUCCESS; -} - -static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong liobn = args[0]; - target_ulong ioba = args[1]; - target_ulong tce = args[2]; - sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); - - if (liobn & 0xFFFFFFFF00000000ULL) { - hcall_dprintf("spapr_vio_put_tce on out-of-boundsw LIOBN " - TARGET_FMT_lx "\n", liobn); - return H_PARAMETER; - } - - ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1); - - if (tcet) { - return put_tce_emu(tcet, ioba, tce); - } -#ifdef DEBUG_TCE - fprintf(stderr, "%s on liobn=" TARGET_FMT_lx /*%s*/ - " ioba 0x" TARGET_FMT_lx " TCE 0x" TARGET_FMT_lx "\n", - __func__, liobn, /*dev->qdev.id, */ioba, tce); -#endif - - return H_PARAMETER; -} - -void spapr_iommu_init(void) -{ - QLIST_INIT(&spapr_tce_tables); - - /* hcall-tce */ - spapr_register_hypercall(H_PUT_TCE, h_put_tce); -} - -int spapr_dma_dt(void *fdt, int node_off, const char *propname, - uint32_t liobn, uint64_t window, uint32_t size) -{ - uint32_t dma_prop[5]; - int ret; - - dma_prop[0] = cpu_to_be32(liobn); - dma_prop[1] = cpu_to_be32(window >> 32); - dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF); - dma_prop[3] = 0; /* window size is 32 bits */ - dma_prop[4] = cpu_to_be32(size); - - ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2); - if (ret < 0) { - return ret; - } - - ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2); - if (ret < 0) { - return ret; - } - - ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop)); - if (ret < 0) { - return ret; - } - - return 0; -} - -int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, - DMAContext *iommu) -{ - if (!iommu) { - return 0; - } - - if (iommu->translate == spapr_tce_translate) { - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu); - return spapr_dma_dt(fdt, node_off, propname, - tcet->liobn, 0, tcet->window_size); - } - - return -1; -} diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c deleted file mode 100644 index 5ec787f29d..0000000000 --- a/hw/spapr_rtas.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator - * - * Hypercall based emulated RTAS - * - * Copyright (c) 2010-2011 David Gibson, IBM Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ -#include "cpu.h" -#include "sysemu/sysemu.h" -#include "char/char.h" -#include "hw/qdev.h" -#include "sysemu/device_tree.h" - -#include "hw/spapr.h" -#include "hw/spapr_vio.h" - -#include - -#define TOKEN_BASE 0x2000 -#define TOKEN_MAX 0x100 - -static void rtas_display_character(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - uint8_t c = rtas_ld(args, 0); - VIOsPAPRDevice *sdev = vty_lookup(spapr, 0); - - if (!sdev) { - rtas_st(rets, 0, -1); - } else { - vty_putchars(sdev, &c, sizeof(c)); - rtas_st(rets, 0, 0); - } -} - -static void rtas_get_time_of_day(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - struct tm tm; - - if (nret != 8) { - rtas_st(rets, 0, -3); - return; - } - - qemu_get_timedate(&tm, spapr->rtc_offset); - - rtas_st(rets, 0, 0); /* Success */ - rtas_st(rets, 1, tm.tm_year + 1900); - rtas_st(rets, 2, tm.tm_mon + 1); - rtas_st(rets, 3, tm.tm_mday); - rtas_st(rets, 4, tm.tm_hour); - rtas_st(rets, 5, tm.tm_min); - rtas_st(rets, 6, tm.tm_sec); - rtas_st(rets, 7, 0); /* we don't do nanoseconds */ -} - -static void rtas_set_time_of_day(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - struct tm tm; - - tm.tm_year = rtas_ld(args, 0) - 1900; - tm.tm_mon = rtas_ld(args, 1) - 1; - tm.tm_mday = rtas_ld(args, 2); - tm.tm_hour = rtas_ld(args, 3); - tm.tm_min = rtas_ld(args, 4); - tm.tm_sec = rtas_ld(args, 5); - - /* Just generate a monitor event for the change */ - rtc_change_mon_event(&tm); - spapr->rtc_offset = qemu_timedate_diff(&tm); - - rtas_st(rets, 0, 0); /* Success */ -} - -static void rtas_power_off(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - if (nargs != 2 || nret != 1) { - rtas_st(rets, 0, -3); - return; - } - qemu_system_shutdown_request(); - rtas_st(rets, 0, 0); -} - -static void rtas_system_reboot(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - if (nargs != 0 || nret != 1) { - rtas_st(rets, 0, -3); - return; - } - qemu_system_reset_request(); - rtas_st(rets, 0, 0); -} - -static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - target_ulong id; - CPUPPCState *env; - CPUState *cpu; - - if (nargs != 1 || nret != 2) { - rtas_st(rets, 0, -3); - return; - } - - id = rtas_ld(args, 0); - for (env = first_cpu; env; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - if (cpu->cpu_index != id) { - continue; - } - - if (env->halted) { - rtas_st(rets, 1, 0); - } else { - rtas_st(rets, 1, 2); - } - - rtas_st(rets, 0, 0); - return; - } - - /* Didn't find a matching cpu */ - rtas_st(rets, 0, -3); -} - -static void rtas_start_cpu(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - target_ulong id, start, r3; - CPUState *cpu; - CPUPPCState *env; - - if (nargs != 3 || nret != 1) { - rtas_st(rets, 0, -3); - return; - } - - id = rtas_ld(args, 0); - start = rtas_ld(args, 1); - r3 = rtas_ld(args, 2); - - for (env = first_cpu; env; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - - if (cpu->cpu_index != id) { - continue; - } - - if (!env->halted) { - rtas_st(rets, 0, -1); - return; - } - - /* This will make sure qemu state is up to date with kvm, and - * mark it dirty so our changes get flushed back before the - * new cpu enters */ - kvm_cpu_synchronize_state(env); - - env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); - env->nip = start; - env->gpr[3] = r3; - env->halted = 0; - - qemu_cpu_kick(cpu); - - rtas_st(rets, 0, 0); - return; - } - - /* Didn't find a matching cpu */ - rtas_st(rets, 0, -3); -} - -static struct rtas_call { - const char *name; - spapr_rtas_fn fn; -} rtas_table[TOKEN_MAX]; - -struct rtas_call *rtas_next = rtas_table; - -target_ulong spapr_rtas_call(sPAPREnvironment *spapr, - uint32_t token, uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - if ((token >= TOKEN_BASE) - && ((token - TOKEN_BASE) < TOKEN_MAX)) { - struct rtas_call *call = rtas_table + (token - TOKEN_BASE); - - if (call->fn) { - call->fn(spapr, token, nargs, args, nret, rets); - return H_SUCCESS; - } - } - - /* HACK: Some Linux early debug code uses RTAS display-character, - * but assumes the token value is 0xa (which it is on some real - * machines) without looking it up in the device tree. This - * special case makes this work */ - if (token == 0xa) { - rtas_display_character(spapr, 0xa, nargs, args, nret, rets); - return H_SUCCESS; - } - - hcall_dprintf("Unknown RTAS token 0x%x\n", token); - rtas_st(rets, 0, -3); - return H_PARAMETER; -} - -int spapr_rtas_register(const char *name, spapr_rtas_fn fn) -{ - int i; - - for (i = 0; i < (rtas_next - rtas_table); i++) { - if (strcmp(name, rtas_table[i].name) == 0) { - fprintf(stderr, "RTAS call \"%s\" registered twice\n", name); - exit(1); - } - } - - assert(rtas_next < (rtas_table + TOKEN_MAX)); - - rtas_next->name = name; - rtas_next->fn = fn; - - return (rtas_next++ - rtas_table) + TOKEN_BASE; -} - -int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, - hwaddr rtas_size) -{ - int ret; - int i; - - ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size); - if (ret < 0) { - fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n", - fdt_strerror(ret)); - return ret; - } - - ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base", - rtas_addr); - if (ret < 0) { - fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n", - fdt_strerror(ret)); - return ret; - } - - ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry", - rtas_addr); - if (ret < 0) { - fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n", - fdt_strerror(ret)); - return ret; - } - - ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size", - rtas_size); - if (ret < 0) { - fprintf(stderr, "Couldn't add rtas-size property: %s\n", - fdt_strerror(ret)); - return ret; - } - - for (i = 0; i < TOKEN_MAX; i++) { - struct rtas_call *call = &rtas_table[i]; - - if (!call->name) { - continue; - } - - ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name, - i + TOKEN_BASE); - if (ret < 0) { - fprintf(stderr, "Couldn't add rtas token for %s: %s\n", - call->name, fdt_strerror(ret)); - return ret; - } - - } - return 0; -} - -static void core_rtas_register_types(void) -{ - spapr_rtas_register("display-character", rtas_display_character); - spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); - spapr_rtas_register("set-time-of-day", rtas_set_time_of_day); - spapr_rtas_register("power-off", rtas_power_off); - spapr_rtas_register("system-reboot", rtas_system_reboot); - spapr_rtas_register("query-cpu-stopped-state", - rtas_query_cpu_stopped_state); - spapr_rtas_register("start-cpu", rtas_start_cpu); -} - -type_init(core_rtas_register_types) -- cgit v1.2.3 From 7a2771d1541ec9a0c585e9b853e5f4dc036919ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: sh: move files referencing CPU to hw/sh4/ Signed-off-by: Paolo Bonzini --- hw/sh4/Makefile.objs | 4 +- hw/sh4/sh7750.c | 838 +++++++++++++++++++++++++++++++++++++++++++++++ hw/sh4/sh7750_regnames.c | 97 ++++++ hw/sh7750.c | 838 ----------------------------------------------- hw/sh7750_regnames.c | 97 ------ 5 files changed, 938 insertions(+), 936 deletions(-) create mode 100644 hw/sh4/sh7750.c create mode 100644 hw/sh4/sh7750_regnames.c delete mode 100644 hw/sh7750.c delete mode 100644 hw/sh7750_regnames.c diff --git a/hw/sh4/Makefile.objs b/hw/sh4/Makefile.objs index b2e1f1e044..72b6a1fcb4 100644 --- a/hw/sh4/Makefile.objs +++ b/hw/sh4/Makefile.objs @@ -1,7 +1,9 @@ -obj-y = sh7750.o sh7750_regnames.o tc58128.o +obj-y = tc58128.o obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o obj-y += ide/mmio.o obj-y := $(addprefix ../,$(obj-y)) obj-y += shix.o r2d.o + +obj-y += sh7750.o sh7750_regnames.o diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c new file mode 100644 index 0000000000..6778c94f8e --- /dev/null +++ b/hw/sh4/sh7750.c @@ -0,0 +1,838 @@ +/* + * SH7750 device + * + * Copyright (c) 2007 Magnus Damm + * Copyright (c) 2005 Samuel Tardieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include "hw/hw.h" +#include "hw/sh.h" +#include "sysemu/sysemu.h" +#include "hw/sh7750_regs.h" +#include "hw/sh7750_regnames.h" +#include "hw/sh_intc.h" +#include "cpu.h" +#include "exec/address-spaces.h" + +#define NB_DEVICES 4 + +typedef struct SH7750State { + MemoryRegion iomem; + MemoryRegion iomem_1f0; + MemoryRegion iomem_ff0; + MemoryRegion iomem_1f8; + MemoryRegion iomem_ff8; + MemoryRegion iomem_1fc; + MemoryRegion iomem_ffc; + MemoryRegion mmct_iomem; + /* CPU */ + CPUSH4State *cpu; + /* Peripheral frequency in Hz */ + uint32_t periph_freq; + /* SDRAM controller */ + uint32_t bcr1; + uint16_t bcr2; + uint16_t bcr3; + uint32_t bcr4; + uint16_t rfcr; + /* PCMCIA controller */ + uint16_t pcr; + /* IO ports */ + uint16_t gpioic; + uint32_t pctra; + uint32_t pctrb; + uint16_t portdira; /* Cached */ + uint16_t portpullupa; /* Cached */ + uint16_t portdirb; /* Cached */ + uint16_t portpullupb; /* Cached */ + uint16_t pdtra; + uint16_t pdtrb; + uint16_t periph_pdtra; /* Imposed by the peripherals */ + uint16_t periph_portdira; /* Direction seen from the peripherals */ + uint16_t periph_pdtrb; /* Imposed by the peripherals */ + uint16_t periph_portdirb; /* Direction seen from the peripherals */ + sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ + + /* Cache */ + uint32_t ccr; + + struct intc_desc intc; +} SH7750State; + +static inline int has_bcr3_and_bcr4(SH7750State * s) +{ + return (s->cpu->features & SH_FEATURE_BCR3_AND_BCR4); +} +/********************************************************************** + I/O ports +**********************************************************************/ + +int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device) +{ + int i; + + for (i = 0; i < NB_DEVICES; i++) { + if (s->devices[i] == NULL) { + s->devices[i] = device; + return 0; + } + } + return -1; +} + +static uint16_t portdir(uint32_t v) +{ +#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n)) + return + EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) | + EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) | + EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) | + EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) | + EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) | + EVENPORTMASK(0); +} + +static uint16_t portpullup(uint32_t v) +{ +#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n)) + return + ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) | + ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) | + ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) | + ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) | + ODDPORTMASK(1) | ODDPORTMASK(0); +} + +static uint16_t porta_lines(SH7750State * s) +{ + return (s->portdira & s->pdtra) | /* CPU */ + (s->periph_portdira & s->periph_pdtra) | /* Peripherals */ + (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */ +} + +static uint16_t portb_lines(SH7750State * s) +{ + return (s->portdirb & s->pdtrb) | /* CPU */ + (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */ + (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */ +} + +static void gen_port_interrupts(SH7750State * s) +{ + /* XXXXX interrupts not generated */ +} + +static void porta_changed(SH7750State * s, uint16_t prev) +{ + uint16_t currenta, changes; + int i, r = 0; + +#if 0 + fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n", + prev, porta_lines(s)); + fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra); +#endif + currenta = porta_lines(s); + if (currenta == prev) + return; + changes = currenta ^ prev; + + for (i = 0; i < NB_DEVICES; i++) { + if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) { + r |= s->devices[i]->port_change_cb(currenta, portb_lines(s), + &s->periph_pdtra, + &s->periph_portdira, + &s->periph_pdtrb, + &s->periph_portdirb); + } + } + + if (r) + gen_port_interrupts(s); +} + +static void portb_changed(SH7750State * s, uint16_t prev) +{ + uint16_t currentb, changes; + int i, r = 0; + + currentb = portb_lines(s); + if (currentb == prev) + return; + changes = currentb ^ prev; + + for (i = 0; i < NB_DEVICES; i++) { + if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) { + r |= s->devices[i]->port_change_cb(portb_lines(s), currentb, + &s->periph_pdtra, + &s->periph_portdira, + &s->periph_pdtrb, + &s->periph_portdirb); + } + } + + if (r) + gen_port_interrupts(s); +} + +/********************************************************************** + Memory +**********************************************************************/ + +static void error_access(const char *kind, hwaddr addr) +{ + fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n", + kind, regname(addr), addr); +} + +static void ignore_access(const char *kind, hwaddr addr) +{ + fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n", + kind, regname(addr), addr); +} + +static uint32_t sh7750_mem_readb(void *opaque, hwaddr addr) +{ + switch (addr) { + default: + error_access("byte read", addr); + abort(); + } +} + +static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr) +{ + SH7750State *s = opaque; + + switch (addr) { + case SH7750_BCR2_A7: + return s->bcr2; + case SH7750_BCR3_A7: + if(!has_bcr3_and_bcr4(s)) + error_access("word read", addr); + return s->bcr3; + case SH7750_FRQCR_A7: + return 0; + case SH7750_PCR_A7: + return s->pcr; + case SH7750_RFCR_A7: + fprintf(stderr, + "Read access to refresh count register, incrementing\n"); + return s->rfcr++; + case SH7750_PDTRA_A7: + return porta_lines(s); + case SH7750_PDTRB_A7: + return portb_lines(s); + case SH7750_RTCOR_A7: + case SH7750_RTCNT_A7: + case SH7750_RTCSR_A7: + ignore_access("word read", addr); + return 0; + default: + error_access("word read", addr); + abort(); + } +} + +static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) +{ + SH7750State *s = opaque; + + switch (addr) { + case SH7750_BCR1_A7: + return s->bcr1; + case SH7750_BCR4_A7: + if(!has_bcr3_and_bcr4(s)) + error_access("long read", addr); + return s->bcr4; + case SH7750_WCR1_A7: + case SH7750_WCR2_A7: + case SH7750_WCR3_A7: + case SH7750_MCR_A7: + ignore_access("long read", addr); + return 0; + case SH7750_MMUCR_A7: + return s->cpu->mmucr; + case SH7750_PTEH_A7: + return s->cpu->pteh; + case SH7750_PTEL_A7: + return s->cpu->ptel; + case SH7750_TTB_A7: + return s->cpu->ttb; + case SH7750_TEA_A7: + return s->cpu->tea; + case SH7750_TRA_A7: + return s->cpu->tra; + case SH7750_EXPEVT_A7: + return s->cpu->expevt; + case SH7750_INTEVT_A7: + return s->cpu->intevt; + case SH7750_CCR_A7: + return s->ccr; + case 0x1f000030: /* Processor version */ + return s->cpu->pvr; + case 0x1f000040: /* Cache version */ + return s->cpu->cvr; + case 0x1f000044: /* Processor revision */ + return s->cpu->prr; + default: + error_access("long read", addr); + abort(); + } +} + +#define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \ + && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB)) +static void sh7750_mem_writeb(void *opaque, hwaddr addr, + uint32_t mem_value) +{ + + if (is_in_sdrmx(addr, 2) || is_in_sdrmx(addr, 3)) { + ignore_access("byte write", addr); + return; + } + + error_access("byte write", addr); + abort(); +} + +static void sh7750_mem_writew(void *opaque, hwaddr addr, + uint32_t mem_value) +{ + SH7750State *s = opaque; + uint16_t temp; + + switch (addr) { + /* SDRAM controller */ + case SH7750_BCR2_A7: + s->bcr2 = mem_value; + return; + case SH7750_BCR3_A7: + if(!has_bcr3_and_bcr4(s)) + error_access("word write", addr); + s->bcr3 = mem_value; + return; + case SH7750_PCR_A7: + s->pcr = mem_value; + return; + case SH7750_RTCNT_A7: + case SH7750_RTCOR_A7: + case SH7750_RTCSR_A7: + ignore_access("word write", addr); + return; + /* IO ports */ + case SH7750_PDTRA_A7: + temp = porta_lines(s); + s->pdtra = mem_value; + porta_changed(s, temp); + return; + case SH7750_PDTRB_A7: + temp = portb_lines(s); + s->pdtrb = mem_value; + portb_changed(s, temp); + return; + case SH7750_RFCR_A7: + fprintf(stderr, "Write access to refresh count register\n"); + s->rfcr = mem_value; + return; + case SH7750_GPIOIC_A7: + s->gpioic = mem_value; + if (mem_value != 0) { + fprintf(stderr, "I/O interrupts not implemented\n"); + abort(); + } + return; + default: + error_access("word write", addr); + abort(); + } +} + +static void sh7750_mem_writel(void *opaque, hwaddr addr, + uint32_t mem_value) +{ + SH7750State *s = opaque; + uint16_t temp; + + switch (addr) { + /* SDRAM controller */ + case SH7750_BCR1_A7: + s->bcr1 = mem_value; + return; + case SH7750_BCR4_A7: + if(!has_bcr3_and_bcr4(s)) + error_access("long write", addr); + s->bcr4 = mem_value; + return; + case SH7750_WCR1_A7: + case SH7750_WCR2_A7: + case SH7750_WCR3_A7: + case SH7750_MCR_A7: + ignore_access("long write", addr); + return; + /* IO ports */ + case SH7750_PCTRA_A7: + temp = porta_lines(s); + s->pctra = mem_value; + s->portdira = portdir(mem_value); + s->portpullupa = portpullup(mem_value); + porta_changed(s, temp); + return; + case SH7750_PCTRB_A7: + temp = portb_lines(s); + s->pctrb = mem_value; + s->portdirb = portdir(mem_value); + s->portpullupb = portpullup(mem_value); + portb_changed(s, temp); + return; + case SH7750_MMUCR_A7: + if (mem_value & MMUCR_TI) { + cpu_sh4_invalidate_tlb(s->cpu); + } + s->cpu->mmucr = mem_value & ~MMUCR_TI; + return; + case SH7750_PTEH_A7: + /* If asid changes, clear all registered tlb entries. */ + if ((s->cpu->pteh & 0xff) != (mem_value & 0xff)) + tlb_flush(s->cpu, 1); + s->cpu->pteh = mem_value; + return; + case SH7750_PTEL_A7: + s->cpu->ptel = mem_value; + return; + case SH7750_PTEA_A7: + s->cpu->ptea = mem_value & 0x0000000f; + return; + case SH7750_TTB_A7: + s->cpu->ttb = mem_value; + return; + case SH7750_TEA_A7: + s->cpu->tea = mem_value; + return; + case SH7750_TRA_A7: + s->cpu->tra = mem_value & 0x000007ff; + return; + case SH7750_EXPEVT_A7: + s->cpu->expevt = mem_value & 0x000007ff; + return; + case SH7750_INTEVT_A7: + s->cpu->intevt = mem_value & 0x000007ff; + return; + case SH7750_CCR_A7: + s->ccr = mem_value; + return; + default: + error_access("long write", addr); + abort(); + } +} + +static const MemoryRegionOps sh7750_mem_ops = { + .old_mmio = { + .read = {sh7750_mem_readb, + sh7750_mem_readw, + sh7750_mem_readl }, + .write = {sh7750_mem_writeb, + sh7750_mem_writew, + sh7750_mem_writel }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +/* sh775x interrupt controller tables for sh_intc.c + * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c + */ + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7, + IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E, + IRL0, IRL1, IRL2, IRL3, + HUDI, GPIOI, + DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, + DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, + DMAC_DMAE, + PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3, + TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, + RTC_ATI, RTC_PRI, RTC_CUI, + SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI, + SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI, + WDT, + REF_RCMI, REF_ROVI, + + /* interrupt groups */ + DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, + /* irl bundle */ + IRL, + + NR_SOURCES, +}; + +static struct intc_vect vectors[] = { + INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), + INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500), + INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540), + INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720), + INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), +}; + +static struct intc_group groups[] = { + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), + INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI), + INTC_GROUP(REF, REF_RCMI, REF_ROVI), +}; + +static struct intc_prio_reg prio_registers[] = { + { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, + { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, + { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, + { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, + TMU4, TMU3, + PCIC1, PCIC0_PCISERR } }, +}; + +/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */ + +static struct intc_vect vectors_dma4[] = { + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), + INTC_VECT(DMAC_DMAE, 0x6c0), +}; + +static struct intc_group groups_dma4[] = { + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, + DMAC_DMTE3, DMAC_DMAE), +}; + +/* SH7750R and SH7751R both have 8-channel DMA controllers */ + +static struct intc_vect vectors_dma8[] = { + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), + INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), + INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0), + INTC_VECT(DMAC_DMAE, 0x6c0), +}; + +static struct intc_group groups_dma8[] = { + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, + DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, + DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), +}; + +/* SH7750R, SH7751 and SH7751R all have two extra timer channels */ + +static struct intc_vect vectors_tmu34[] = { + INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80), +}; + +static struct intc_mask_reg mask_registers[] = { + { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, TMU4, TMU3, + PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, + PCIC1_PCIDMA3, PCIC0_PCISERR } }, +}; + +/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */ + +static struct intc_vect vectors_irlm[] = { + INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), + INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), +}; + +/* SH7751 and SH7751R both have PCI */ + +static struct intc_vect vectors_pci[] = { + INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0), + INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0), + INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60), + INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20), +}; + +static struct intc_group groups_pci[] = { + INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), +}; + +static struct intc_vect vectors_irl[] = { + INTC_VECT(IRL_0, 0x200), + INTC_VECT(IRL_1, 0x220), + INTC_VECT(IRL_2, 0x240), + INTC_VECT(IRL_3, 0x260), + INTC_VECT(IRL_4, 0x280), + INTC_VECT(IRL_5, 0x2a0), + INTC_VECT(IRL_6, 0x2c0), + INTC_VECT(IRL_7, 0x2e0), + INTC_VECT(IRL_8, 0x300), + INTC_VECT(IRL_9, 0x320), + INTC_VECT(IRL_A, 0x340), + INTC_VECT(IRL_B, 0x360), + INTC_VECT(IRL_C, 0x380), + INTC_VECT(IRL_D, 0x3a0), + INTC_VECT(IRL_E, 0x3c0), +}; + +static struct intc_group groups_irl[] = { + INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, + IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E), +}; + +/********************************************************************** + Memory mapped cache and TLB +**********************************************************************/ + +#define MM_REGION_MASK 0x07000000 +#define MM_ICACHE_ADDR (0) +#define MM_ICACHE_DATA (1) +#define MM_ITLB_ADDR (2) +#define MM_ITLB_DATA (3) +#define MM_OCACHE_ADDR (4) +#define MM_OCACHE_DATA (5) +#define MM_UTLB_ADDR (6) +#define MM_UTLB_DATA (7) +#define MM_REGION_TYPE(addr) ((addr & MM_REGION_MASK) >> 24) + +static uint64_t invalid_read(void *opaque, hwaddr addr) +{ + abort(); + + return 0; +} + +static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr, + unsigned size) +{ + SH7750State *s = opaque; + uint32_t ret = 0; + + if (size != 4) { + return invalid_read(opaque, addr); + } + + switch (MM_REGION_TYPE(addr)) { + case MM_ICACHE_ADDR: + case MM_ICACHE_DATA: + /* do nothing */ + break; + case MM_ITLB_ADDR: + ret = cpu_sh4_read_mmaped_itlb_addr(s->cpu, addr); + break; + case MM_ITLB_DATA: + ret = cpu_sh4_read_mmaped_itlb_data(s->cpu, addr); + break; + case MM_OCACHE_ADDR: + case MM_OCACHE_DATA: + /* do nothing */ + break; + case MM_UTLB_ADDR: + ret = cpu_sh4_read_mmaped_utlb_addr(s->cpu, addr); + break; + case MM_UTLB_DATA: + ret = cpu_sh4_read_mmaped_utlb_data(s->cpu, addr); + break; + default: + abort(); + } + + return ret; +} + +static void invalid_write(void *opaque, hwaddr addr, + uint64_t mem_value) +{ + abort(); +} + +static void sh7750_mmct_write(void *opaque, hwaddr addr, + uint64_t mem_value, unsigned size) +{ + SH7750State *s = opaque; + + if (size != 4) { + invalid_write(opaque, addr, mem_value); + } + + switch (MM_REGION_TYPE(addr)) { + case MM_ICACHE_ADDR: + case MM_ICACHE_DATA: + /* do nothing */ + break; + case MM_ITLB_ADDR: + cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value); + break; + case MM_ITLB_DATA: + cpu_sh4_write_mmaped_itlb_data(s->cpu, addr, mem_value); + abort(); + break; + case MM_OCACHE_ADDR: + case MM_OCACHE_DATA: + /* do nothing */ + break; + case MM_UTLB_ADDR: + cpu_sh4_write_mmaped_utlb_addr(s->cpu, addr, mem_value); + break; + case MM_UTLB_DATA: + cpu_sh4_write_mmaped_utlb_data(s->cpu, addr, mem_value); + break; + default: + abort(); + break; + } +} + +static const MemoryRegionOps sh7750_mmct_ops = { + .read = sh7750_mmct_read, + .write = sh7750_mmct_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +SH7750State *sh7750_init(CPUSH4State * cpu, MemoryRegion *sysmem) +{ + SH7750State *s; + + s = g_malloc0(sizeof(SH7750State)); + s->cpu = cpu; + s->periph_freq = 60000000; /* 60MHz */ + memory_region_init_io(&s->iomem, &sh7750_mem_ops, s, + "memory", 0x1fc01000); + + memory_region_init_alias(&s->iomem_1f0, "memory-1f0", + &s->iomem, 0x1f000000, 0x1000); + memory_region_add_subregion(sysmem, 0x1f000000, &s->iomem_1f0); + + memory_region_init_alias(&s->iomem_ff0, "memory-ff0", + &s->iomem, 0x1f000000, 0x1000); + memory_region_add_subregion(sysmem, 0xff000000, &s->iomem_ff0); + + memory_region_init_alias(&s->iomem_1f8, "memory-1f8", + &s->iomem, 0x1f800000, 0x1000); + memory_region_add_subregion(sysmem, 0x1f800000, &s->iomem_1f8); + + memory_region_init_alias(&s->iomem_ff8, "memory-ff8", + &s->iomem, 0x1f800000, 0x1000); + memory_region_add_subregion(sysmem, 0xff800000, &s->iomem_ff8); + + memory_region_init_alias(&s->iomem_1fc, "memory-1fc", + &s->iomem, 0x1fc00000, 0x1000); + memory_region_add_subregion(sysmem, 0x1fc00000, &s->iomem_1fc); + + memory_region_init_alias(&s->iomem_ffc, "memory-ffc", + &s->iomem, 0x1fc00000, 0x1000); + memory_region_add_subregion(sysmem, 0xffc00000, &s->iomem_ffc); + + memory_region_init_io(&s->mmct_iomem, &sh7750_mmct_ops, s, + "cache-and-tlb", 0x08000000); + memory_region_add_subregion(sysmem, 0xf0000000, &s->mmct_iomem); + + sh_intc_init(sysmem, &s->intc, NR_SOURCES, + _INTC_ARRAY(mask_registers), + _INTC_ARRAY(prio_registers)); + + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors), + _INTC_ARRAY(groups)); + + cpu->intc_handle = &s->intc; + + sh_serial_init(sysmem, 0x1fe00000, + 0, s->periph_freq, serial_hds[0], + s->intc.irqs[SCI1_ERI], + s->intc.irqs[SCI1_RXI], + s->intc.irqs[SCI1_TXI], + s->intc.irqs[SCI1_TEI], + NULL); + sh_serial_init(sysmem, 0x1fe80000, + SH_SERIAL_FEAT_SCIF, + s->periph_freq, serial_hds[1], + s->intc.irqs[SCIF_ERI], + s->intc.irqs[SCIF_RXI], + s->intc.irqs[SCIF_TXI], + NULL, + s->intc.irqs[SCIF_BRI]); + + tmu012_init(sysmem, 0x1fd80000, + TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, + s->periph_freq, + s->intc.irqs[TMU0], + s->intc.irqs[TMU1], + s->intc.irqs[TMU2_TUNI], + s->intc.irqs[TMU2_TICPI]); + + if (cpu->id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_dma4), + _INTC_ARRAY(groups_dma4)); + } + + if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_dma8), + _INTC_ARRAY(groups_dma8)); + } + + if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_tmu34), + NULL, 0); + tmu012_init(sysmem, 0x1e100000, 0, s->periph_freq, + s->intc.irqs[TMU3], + s->intc.irqs[TMU4], + NULL, NULL); + } + + if (cpu->id & (SH_CPU_SH7751_ALL)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_pci), + _INTC_ARRAY(groups_pci)); + } + + if (cpu->id & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_irlm), + NULL, 0); + } + + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_irl), + _INTC_ARRAY(groups_irl)); + return s; +} + +qemu_irq sh7750_irl(SH7750State *s) +{ + sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */ + return qemu_allocate_irqs(sh_intc_set_irl, sh_intc_source(&s->intc, IRL), + 1)[0]; +} diff --git a/hw/sh4/sh7750_regnames.c b/hw/sh4/sh7750_regnames.c new file mode 100644 index 0000000000..389698d24a --- /dev/null +++ b/hw/sh4/sh7750_regnames.c @@ -0,0 +1,97 @@ +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/sh7750_regs.h" +#include "hw/sh7750_regnames.h" + +#define REGNAME(r) {r, #r}, + +typedef struct { + uint32_t regaddr; + const char *regname; +} regname_t; + +static regname_t regnames[] = { + REGNAME(SH7750_PTEH_A7) + REGNAME(SH7750_PTEL_A7) + REGNAME(SH7750_PTEA_A7) + REGNAME(SH7750_TTB_A7) + REGNAME(SH7750_TEA_A7) + REGNAME(SH7750_MMUCR_A7) + REGNAME(SH7750_CCR_A7) + REGNAME(SH7750_QACR0_A7) + REGNAME(SH7750_QACR1_A7) + REGNAME(SH7750_TRA_A7) + REGNAME(SH7750_EXPEVT_A7) + REGNAME(SH7750_INTEVT_A7) + REGNAME(SH7750_STBCR_A7) + REGNAME(SH7750_STBCR2_A7) + REGNAME(SH7750_FRQCR_A7) + REGNAME(SH7750_WTCNT_A7) + REGNAME(SH7750_WTCSR_A7) + REGNAME(SH7750_R64CNT_A7) + REGNAME(SH7750_RSECCNT_A7) + REGNAME(SH7750_RMINCNT_A7) + REGNAME(SH7750_RHRCNT_A7) + REGNAME(SH7750_RWKCNT_A7) + REGNAME(SH7750_RDAYCNT_A7) + REGNAME(SH7750_RMONCNT_A7) + REGNAME(SH7750_RYRCNT_A7) + REGNAME(SH7750_RSECAR_A7) + REGNAME(SH7750_RMINAR_A7) + REGNAME(SH7750_RHRAR_A7) + REGNAME(SH7750_RWKAR_A7) + REGNAME(SH7750_RDAYAR_A7) + REGNAME(SH7750_RMONAR_A7) + REGNAME(SH7750_RCR1_A7) + REGNAME(SH7750_RCR2_A7) + REGNAME(SH7750_BCR1_A7) + REGNAME(SH7750_BCR2_A7) + REGNAME(SH7750_WCR1_A7) + REGNAME(SH7750_WCR2_A7) + REGNAME(SH7750_WCR3_A7) + REGNAME(SH7750_MCR_A7) + REGNAME(SH7750_PCR_A7) + REGNAME(SH7750_RTCSR_A7) + REGNAME(SH7750_RTCNT_A7) + REGNAME(SH7750_RTCOR_A7) + REGNAME(SH7750_RFCR_A7) + REGNAME(SH7750_SAR0_A7) + REGNAME(SH7750_SAR1_A7) + REGNAME(SH7750_SAR2_A7) + REGNAME(SH7750_SAR3_A7) + REGNAME(SH7750_DAR0_A7) + REGNAME(SH7750_DAR1_A7) + REGNAME(SH7750_DAR2_A7) + REGNAME(SH7750_DAR3_A7) + REGNAME(SH7750_DMATCR0_A7) + REGNAME(SH7750_DMATCR1_A7) + REGNAME(SH7750_DMATCR2_A7) + REGNAME(SH7750_DMATCR3_A7) + REGNAME(SH7750_CHCR0_A7) + REGNAME(SH7750_CHCR1_A7) + REGNAME(SH7750_CHCR2_A7) + REGNAME(SH7750_CHCR3_A7) + REGNAME(SH7750_DMAOR_A7) + REGNAME(SH7750_PCTRA_A7) + REGNAME(SH7750_PDTRA_A7) + REGNAME(SH7750_PCTRB_A7) + REGNAME(SH7750_PDTRB_A7) + REGNAME(SH7750_GPIOIC_A7) + REGNAME(SH7750_ICR_A7) + REGNAME(SH7750_BCR3_A7) + REGNAME(SH7750_BCR4_A7) + REGNAME(SH7750_SDMR2_A7) + REGNAME(SH7750_SDMR3_A7) {(uint32_t) - 1, NULL} +}; + +const char *regname(uint32_t addr) +{ + unsigned int i; + + for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) { + if (regnames[i].regaddr == addr) + return regnames[i].regname; + } + + return ""; +} diff --git a/hw/sh7750.c b/hw/sh7750.c deleted file mode 100644 index 6778c94f8e..0000000000 --- a/hw/sh7750.c +++ /dev/null @@ -1,838 +0,0 @@ -/* - * SH7750 device - * - * Copyright (c) 2007 Magnus Damm - * Copyright (c) 2005 Samuel Tardieu - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include "hw/hw.h" -#include "hw/sh.h" -#include "sysemu/sysemu.h" -#include "hw/sh7750_regs.h" -#include "hw/sh7750_regnames.h" -#include "hw/sh_intc.h" -#include "cpu.h" -#include "exec/address-spaces.h" - -#define NB_DEVICES 4 - -typedef struct SH7750State { - MemoryRegion iomem; - MemoryRegion iomem_1f0; - MemoryRegion iomem_ff0; - MemoryRegion iomem_1f8; - MemoryRegion iomem_ff8; - MemoryRegion iomem_1fc; - MemoryRegion iomem_ffc; - MemoryRegion mmct_iomem; - /* CPU */ - CPUSH4State *cpu; - /* Peripheral frequency in Hz */ - uint32_t periph_freq; - /* SDRAM controller */ - uint32_t bcr1; - uint16_t bcr2; - uint16_t bcr3; - uint32_t bcr4; - uint16_t rfcr; - /* PCMCIA controller */ - uint16_t pcr; - /* IO ports */ - uint16_t gpioic; - uint32_t pctra; - uint32_t pctrb; - uint16_t portdira; /* Cached */ - uint16_t portpullupa; /* Cached */ - uint16_t portdirb; /* Cached */ - uint16_t portpullupb; /* Cached */ - uint16_t pdtra; - uint16_t pdtrb; - uint16_t periph_pdtra; /* Imposed by the peripherals */ - uint16_t periph_portdira; /* Direction seen from the peripherals */ - uint16_t periph_pdtrb; /* Imposed by the peripherals */ - uint16_t periph_portdirb; /* Direction seen from the peripherals */ - sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ - - /* Cache */ - uint32_t ccr; - - struct intc_desc intc; -} SH7750State; - -static inline int has_bcr3_and_bcr4(SH7750State * s) -{ - return (s->cpu->features & SH_FEATURE_BCR3_AND_BCR4); -} -/********************************************************************** - I/O ports -**********************************************************************/ - -int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device) -{ - int i; - - for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] == NULL) { - s->devices[i] = device; - return 0; - } - } - return -1; -} - -static uint16_t portdir(uint32_t v) -{ -#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n)) - return - EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) | - EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) | - EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) | - EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) | - EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) | - EVENPORTMASK(0); -} - -static uint16_t portpullup(uint32_t v) -{ -#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n)) - return - ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) | - ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) | - ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) | - ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) | - ODDPORTMASK(1) | ODDPORTMASK(0); -} - -static uint16_t porta_lines(SH7750State * s) -{ - return (s->portdira & s->pdtra) | /* CPU */ - (s->periph_portdira & s->periph_pdtra) | /* Peripherals */ - (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */ -} - -static uint16_t portb_lines(SH7750State * s) -{ - return (s->portdirb & s->pdtrb) | /* CPU */ - (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */ - (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */ -} - -static void gen_port_interrupts(SH7750State * s) -{ - /* XXXXX interrupts not generated */ -} - -static void porta_changed(SH7750State * s, uint16_t prev) -{ - uint16_t currenta, changes; - int i, r = 0; - -#if 0 - fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n", - prev, porta_lines(s)); - fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra); -#endif - currenta = porta_lines(s); - if (currenta == prev) - return; - changes = currenta ^ prev; - - for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) { - r |= s->devices[i]->port_change_cb(currenta, portb_lines(s), - &s->periph_pdtra, - &s->periph_portdira, - &s->periph_pdtrb, - &s->periph_portdirb); - } - } - - if (r) - gen_port_interrupts(s); -} - -static void portb_changed(SH7750State * s, uint16_t prev) -{ - uint16_t currentb, changes; - int i, r = 0; - - currentb = portb_lines(s); - if (currentb == prev) - return; - changes = currentb ^ prev; - - for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) { - r |= s->devices[i]->port_change_cb(portb_lines(s), currentb, - &s->periph_pdtra, - &s->periph_portdira, - &s->periph_pdtrb, - &s->periph_portdirb); - } - } - - if (r) - gen_port_interrupts(s); -} - -/********************************************************************** - Memory -**********************************************************************/ - -static void error_access(const char *kind, hwaddr addr) -{ - fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n", - kind, regname(addr), addr); -} - -static void ignore_access(const char *kind, hwaddr addr) -{ - fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n", - kind, regname(addr), addr); -} - -static uint32_t sh7750_mem_readb(void *opaque, hwaddr addr) -{ - switch (addr) { - default: - error_access("byte read", addr); - abort(); - } -} - -static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr) -{ - SH7750State *s = opaque; - - switch (addr) { - case SH7750_BCR2_A7: - return s->bcr2; - case SH7750_BCR3_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("word read", addr); - return s->bcr3; - case SH7750_FRQCR_A7: - return 0; - case SH7750_PCR_A7: - return s->pcr; - case SH7750_RFCR_A7: - fprintf(stderr, - "Read access to refresh count register, incrementing\n"); - return s->rfcr++; - case SH7750_PDTRA_A7: - return porta_lines(s); - case SH7750_PDTRB_A7: - return portb_lines(s); - case SH7750_RTCOR_A7: - case SH7750_RTCNT_A7: - case SH7750_RTCSR_A7: - ignore_access("word read", addr); - return 0; - default: - error_access("word read", addr); - abort(); - } -} - -static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) -{ - SH7750State *s = opaque; - - switch (addr) { - case SH7750_BCR1_A7: - return s->bcr1; - case SH7750_BCR4_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("long read", addr); - return s->bcr4; - case SH7750_WCR1_A7: - case SH7750_WCR2_A7: - case SH7750_WCR3_A7: - case SH7750_MCR_A7: - ignore_access("long read", addr); - return 0; - case SH7750_MMUCR_A7: - return s->cpu->mmucr; - case SH7750_PTEH_A7: - return s->cpu->pteh; - case SH7750_PTEL_A7: - return s->cpu->ptel; - case SH7750_TTB_A7: - return s->cpu->ttb; - case SH7750_TEA_A7: - return s->cpu->tea; - case SH7750_TRA_A7: - return s->cpu->tra; - case SH7750_EXPEVT_A7: - return s->cpu->expevt; - case SH7750_INTEVT_A7: - return s->cpu->intevt; - case SH7750_CCR_A7: - return s->ccr; - case 0x1f000030: /* Processor version */ - return s->cpu->pvr; - case 0x1f000040: /* Cache version */ - return s->cpu->cvr; - case 0x1f000044: /* Processor revision */ - return s->cpu->prr; - default: - error_access("long read", addr); - abort(); - } -} - -#define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \ - && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB)) -static void sh7750_mem_writeb(void *opaque, hwaddr addr, - uint32_t mem_value) -{ - - if (is_in_sdrmx(addr, 2) || is_in_sdrmx(addr, 3)) { - ignore_access("byte write", addr); - return; - } - - error_access("byte write", addr); - abort(); -} - -static void sh7750_mem_writew(void *opaque, hwaddr addr, - uint32_t mem_value) -{ - SH7750State *s = opaque; - uint16_t temp; - - switch (addr) { - /* SDRAM controller */ - case SH7750_BCR2_A7: - s->bcr2 = mem_value; - return; - case SH7750_BCR3_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("word write", addr); - s->bcr3 = mem_value; - return; - case SH7750_PCR_A7: - s->pcr = mem_value; - return; - case SH7750_RTCNT_A7: - case SH7750_RTCOR_A7: - case SH7750_RTCSR_A7: - ignore_access("word write", addr); - return; - /* IO ports */ - case SH7750_PDTRA_A7: - temp = porta_lines(s); - s->pdtra = mem_value; - porta_changed(s, temp); - return; - case SH7750_PDTRB_A7: - temp = portb_lines(s); - s->pdtrb = mem_value; - portb_changed(s, temp); - return; - case SH7750_RFCR_A7: - fprintf(stderr, "Write access to refresh count register\n"); - s->rfcr = mem_value; - return; - case SH7750_GPIOIC_A7: - s->gpioic = mem_value; - if (mem_value != 0) { - fprintf(stderr, "I/O interrupts not implemented\n"); - abort(); - } - return; - default: - error_access("word write", addr); - abort(); - } -} - -static void sh7750_mem_writel(void *opaque, hwaddr addr, - uint32_t mem_value) -{ - SH7750State *s = opaque; - uint16_t temp; - - switch (addr) { - /* SDRAM controller */ - case SH7750_BCR1_A7: - s->bcr1 = mem_value; - return; - case SH7750_BCR4_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("long write", addr); - s->bcr4 = mem_value; - return; - case SH7750_WCR1_A7: - case SH7750_WCR2_A7: - case SH7750_WCR3_A7: - case SH7750_MCR_A7: - ignore_access("long write", addr); - return; - /* IO ports */ - case SH7750_PCTRA_A7: - temp = porta_lines(s); - s->pctra = mem_value; - s->portdira = portdir(mem_value); - s->portpullupa = portpullup(mem_value); - porta_changed(s, temp); - return; - case SH7750_PCTRB_A7: - temp = portb_lines(s); - s->pctrb = mem_value; - s->portdirb = portdir(mem_value); - s->portpullupb = portpullup(mem_value); - portb_changed(s, temp); - return; - case SH7750_MMUCR_A7: - if (mem_value & MMUCR_TI) { - cpu_sh4_invalidate_tlb(s->cpu); - } - s->cpu->mmucr = mem_value & ~MMUCR_TI; - return; - case SH7750_PTEH_A7: - /* If asid changes, clear all registered tlb entries. */ - if ((s->cpu->pteh & 0xff) != (mem_value & 0xff)) - tlb_flush(s->cpu, 1); - s->cpu->pteh = mem_value; - return; - case SH7750_PTEL_A7: - s->cpu->ptel = mem_value; - return; - case SH7750_PTEA_A7: - s->cpu->ptea = mem_value & 0x0000000f; - return; - case SH7750_TTB_A7: - s->cpu->ttb = mem_value; - return; - case SH7750_TEA_A7: - s->cpu->tea = mem_value; - return; - case SH7750_TRA_A7: - s->cpu->tra = mem_value & 0x000007ff; - return; - case SH7750_EXPEVT_A7: - s->cpu->expevt = mem_value & 0x000007ff; - return; - case SH7750_INTEVT_A7: - s->cpu->intevt = mem_value & 0x000007ff; - return; - case SH7750_CCR_A7: - s->ccr = mem_value; - return; - default: - error_access("long write", addr); - abort(); - } -} - -static const MemoryRegionOps sh7750_mem_ops = { - .old_mmio = { - .read = {sh7750_mem_readb, - sh7750_mem_readw, - sh7750_mem_readl }, - .write = {sh7750_mem_writeb, - sh7750_mem_writew, - sh7750_mem_writel }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* sh775x interrupt controller tables for sh_intc.c - * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c - */ - -enum { - UNUSED = 0, - - /* interrupt sources */ - IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7, - IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E, - IRL0, IRL1, IRL2, IRL3, - HUDI, GPIOI, - DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, - DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, - DMAC_DMAE, - PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, - PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3, - TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, - RTC_ATI, RTC_PRI, RTC_CUI, - SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI, - SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI, - WDT, - REF_RCMI, REF_ROVI, - - /* interrupt groups */ - DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, - /* irl bundle */ - IRL, - - NR_SOURCES, -}; - -static struct intc_vect vectors[] = { - INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), - INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), - INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), - INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), - INTC_VECT(RTC_CUI, 0x4c0), - INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500), - INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540), - INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720), - INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760), - INTC_VECT(WDT, 0x560), - INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), -}; - -static struct intc_group groups[] = { - INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), - INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), - INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), - INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI), - INTC_GROUP(REF, REF_RCMI, REF_ROVI), -}; - -static struct intc_prio_reg prio_registers[] = { - { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, - { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, - { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, - { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, - { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, - TMU4, TMU3, - PCIC1, PCIC0_PCISERR } }, -}; - -/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */ - -static struct intc_vect vectors_dma4[] = { - INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), - INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), - INTC_VECT(DMAC_DMAE, 0x6c0), -}; - -static struct intc_group groups_dma4[] = { - INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, - DMAC_DMTE3, DMAC_DMAE), -}; - -/* SH7750R and SH7751R both have 8-channel DMA controllers */ - -static struct intc_vect vectors_dma8[] = { - INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), - INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), - INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), - INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0), - INTC_VECT(DMAC_DMAE, 0x6c0), -}; - -static struct intc_group groups_dma8[] = { - INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, - DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, - DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), -}; - -/* SH7750R, SH7751 and SH7751R all have two extra timer channels */ - -static struct intc_vect vectors_tmu34[] = { - INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80), -}; - -static struct intc_mask_reg mask_registers[] = { - { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, TMU4, TMU3, - PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, - PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, - PCIC1_PCIDMA3, PCIC0_PCISERR } }, -}; - -/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */ - -static struct intc_vect vectors_irlm[] = { - INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), - INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), -}; - -/* SH7751 and SH7751R both have PCI */ - -static struct intc_vect vectors_pci[] = { - INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0), - INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0), - INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60), - INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20), -}; - -static struct intc_group groups_pci[] = { - INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, - PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), -}; - -static struct intc_vect vectors_irl[] = { - INTC_VECT(IRL_0, 0x200), - INTC_VECT(IRL_1, 0x220), - INTC_VECT(IRL_2, 0x240), - INTC_VECT(IRL_3, 0x260), - INTC_VECT(IRL_4, 0x280), - INTC_VECT(IRL_5, 0x2a0), - INTC_VECT(IRL_6, 0x2c0), - INTC_VECT(IRL_7, 0x2e0), - INTC_VECT(IRL_8, 0x300), - INTC_VECT(IRL_9, 0x320), - INTC_VECT(IRL_A, 0x340), - INTC_VECT(IRL_B, 0x360), - INTC_VECT(IRL_C, 0x380), - INTC_VECT(IRL_D, 0x3a0), - INTC_VECT(IRL_E, 0x3c0), -}; - -static struct intc_group groups_irl[] = { - INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, - IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E), -}; - -/********************************************************************** - Memory mapped cache and TLB -**********************************************************************/ - -#define MM_REGION_MASK 0x07000000 -#define MM_ICACHE_ADDR (0) -#define MM_ICACHE_DATA (1) -#define MM_ITLB_ADDR (2) -#define MM_ITLB_DATA (3) -#define MM_OCACHE_ADDR (4) -#define MM_OCACHE_DATA (5) -#define MM_UTLB_ADDR (6) -#define MM_UTLB_DATA (7) -#define MM_REGION_TYPE(addr) ((addr & MM_REGION_MASK) >> 24) - -static uint64_t invalid_read(void *opaque, hwaddr addr) -{ - abort(); - - return 0; -} - -static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr, - unsigned size) -{ - SH7750State *s = opaque; - uint32_t ret = 0; - - if (size != 4) { - return invalid_read(opaque, addr); - } - - switch (MM_REGION_TYPE(addr)) { - case MM_ICACHE_ADDR: - case MM_ICACHE_DATA: - /* do nothing */ - break; - case MM_ITLB_ADDR: - ret = cpu_sh4_read_mmaped_itlb_addr(s->cpu, addr); - break; - case MM_ITLB_DATA: - ret = cpu_sh4_read_mmaped_itlb_data(s->cpu, addr); - break; - case MM_OCACHE_ADDR: - case MM_OCACHE_DATA: - /* do nothing */ - break; - case MM_UTLB_ADDR: - ret = cpu_sh4_read_mmaped_utlb_addr(s->cpu, addr); - break; - case MM_UTLB_DATA: - ret = cpu_sh4_read_mmaped_utlb_data(s->cpu, addr); - break; - default: - abort(); - } - - return ret; -} - -static void invalid_write(void *opaque, hwaddr addr, - uint64_t mem_value) -{ - abort(); -} - -static void sh7750_mmct_write(void *opaque, hwaddr addr, - uint64_t mem_value, unsigned size) -{ - SH7750State *s = opaque; - - if (size != 4) { - invalid_write(opaque, addr, mem_value); - } - - switch (MM_REGION_TYPE(addr)) { - case MM_ICACHE_ADDR: - case MM_ICACHE_DATA: - /* do nothing */ - break; - case MM_ITLB_ADDR: - cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value); - break; - case MM_ITLB_DATA: - cpu_sh4_write_mmaped_itlb_data(s->cpu, addr, mem_value); - abort(); - break; - case MM_OCACHE_ADDR: - case MM_OCACHE_DATA: - /* do nothing */ - break; - case MM_UTLB_ADDR: - cpu_sh4_write_mmaped_utlb_addr(s->cpu, addr, mem_value); - break; - case MM_UTLB_DATA: - cpu_sh4_write_mmaped_utlb_data(s->cpu, addr, mem_value); - break; - default: - abort(); - break; - } -} - -static const MemoryRegionOps sh7750_mmct_ops = { - .read = sh7750_mmct_read, - .write = sh7750_mmct_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -SH7750State *sh7750_init(CPUSH4State * cpu, MemoryRegion *sysmem) -{ - SH7750State *s; - - s = g_malloc0(sizeof(SH7750State)); - s->cpu = cpu; - s->periph_freq = 60000000; /* 60MHz */ - memory_region_init_io(&s->iomem, &sh7750_mem_ops, s, - "memory", 0x1fc01000); - - memory_region_init_alias(&s->iomem_1f0, "memory-1f0", - &s->iomem, 0x1f000000, 0x1000); - memory_region_add_subregion(sysmem, 0x1f000000, &s->iomem_1f0); - - memory_region_init_alias(&s->iomem_ff0, "memory-ff0", - &s->iomem, 0x1f000000, 0x1000); - memory_region_add_subregion(sysmem, 0xff000000, &s->iomem_ff0); - - memory_region_init_alias(&s->iomem_1f8, "memory-1f8", - &s->iomem, 0x1f800000, 0x1000); - memory_region_add_subregion(sysmem, 0x1f800000, &s->iomem_1f8); - - memory_region_init_alias(&s->iomem_ff8, "memory-ff8", - &s->iomem, 0x1f800000, 0x1000); - memory_region_add_subregion(sysmem, 0xff800000, &s->iomem_ff8); - - memory_region_init_alias(&s->iomem_1fc, "memory-1fc", - &s->iomem, 0x1fc00000, 0x1000); - memory_region_add_subregion(sysmem, 0x1fc00000, &s->iomem_1fc); - - memory_region_init_alias(&s->iomem_ffc, "memory-ffc", - &s->iomem, 0x1fc00000, 0x1000); - memory_region_add_subregion(sysmem, 0xffc00000, &s->iomem_ffc); - - memory_region_init_io(&s->mmct_iomem, &sh7750_mmct_ops, s, - "cache-and-tlb", 0x08000000); - memory_region_add_subregion(sysmem, 0xf0000000, &s->mmct_iomem); - - sh_intc_init(sysmem, &s->intc, NR_SOURCES, - _INTC_ARRAY(mask_registers), - _INTC_ARRAY(prio_registers)); - - sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors), - _INTC_ARRAY(groups)); - - cpu->intc_handle = &s->intc; - - sh_serial_init(sysmem, 0x1fe00000, - 0, s->periph_freq, serial_hds[0], - s->intc.irqs[SCI1_ERI], - s->intc.irqs[SCI1_RXI], - s->intc.irqs[SCI1_TXI], - s->intc.irqs[SCI1_TEI], - NULL); - sh_serial_init(sysmem, 0x1fe80000, - SH_SERIAL_FEAT_SCIF, - s->periph_freq, serial_hds[1], - s->intc.irqs[SCIF_ERI], - s->intc.irqs[SCIF_RXI], - s->intc.irqs[SCIF_TXI], - NULL, - s->intc.irqs[SCIF_BRI]); - - tmu012_init(sysmem, 0x1fd80000, - TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, - s->periph_freq, - s->intc.irqs[TMU0], - s->intc.irqs[TMU1], - s->intc.irqs[TMU2_TUNI], - s->intc.irqs[TMU2_TICPI]); - - if (cpu->id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { - sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_dma4), - _INTC_ARRAY(groups_dma4)); - } - - if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { - sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_dma8), - _INTC_ARRAY(groups_dma8)); - } - - if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { - sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_tmu34), - NULL, 0); - tmu012_init(sysmem, 0x1e100000, 0, s->periph_freq, - s->intc.irqs[TMU3], - s->intc.irqs[TMU4], - NULL, NULL); - } - - if (cpu->id & (SH_CPU_SH7751_ALL)) { - sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_pci), - _INTC_ARRAY(groups_pci)); - } - - if (cpu->id & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { - sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_irlm), - NULL, 0); - } - - sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_irl), - _INTC_ARRAY(groups_irl)); - return s; -} - -qemu_irq sh7750_irl(SH7750State *s) -{ - sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */ - return qemu_allocate_irqs(sh_intc_set_irl, sh_intc_source(&s->intc, IRL), - 1)[0]; -} diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c deleted file mode 100644 index 389698d24a..0000000000 --- a/hw/sh7750_regnames.c +++ /dev/null @@ -1,97 +0,0 @@ -#include "hw/hw.h" -#include "hw/sh.h" -#include "hw/sh7750_regs.h" -#include "hw/sh7750_regnames.h" - -#define REGNAME(r) {r, #r}, - -typedef struct { - uint32_t regaddr; - const char *regname; -} regname_t; - -static regname_t regnames[] = { - REGNAME(SH7750_PTEH_A7) - REGNAME(SH7750_PTEL_A7) - REGNAME(SH7750_PTEA_A7) - REGNAME(SH7750_TTB_A7) - REGNAME(SH7750_TEA_A7) - REGNAME(SH7750_MMUCR_A7) - REGNAME(SH7750_CCR_A7) - REGNAME(SH7750_QACR0_A7) - REGNAME(SH7750_QACR1_A7) - REGNAME(SH7750_TRA_A7) - REGNAME(SH7750_EXPEVT_A7) - REGNAME(SH7750_INTEVT_A7) - REGNAME(SH7750_STBCR_A7) - REGNAME(SH7750_STBCR2_A7) - REGNAME(SH7750_FRQCR_A7) - REGNAME(SH7750_WTCNT_A7) - REGNAME(SH7750_WTCSR_A7) - REGNAME(SH7750_R64CNT_A7) - REGNAME(SH7750_RSECCNT_A7) - REGNAME(SH7750_RMINCNT_A7) - REGNAME(SH7750_RHRCNT_A7) - REGNAME(SH7750_RWKCNT_A7) - REGNAME(SH7750_RDAYCNT_A7) - REGNAME(SH7750_RMONCNT_A7) - REGNAME(SH7750_RYRCNT_A7) - REGNAME(SH7750_RSECAR_A7) - REGNAME(SH7750_RMINAR_A7) - REGNAME(SH7750_RHRAR_A7) - REGNAME(SH7750_RWKAR_A7) - REGNAME(SH7750_RDAYAR_A7) - REGNAME(SH7750_RMONAR_A7) - REGNAME(SH7750_RCR1_A7) - REGNAME(SH7750_RCR2_A7) - REGNAME(SH7750_BCR1_A7) - REGNAME(SH7750_BCR2_A7) - REGNAME(SH7750_WCR1_A7) - REGNAME(SH7750_WCR2_A7) - REGNAME(SH7750_WCR3_A7) - REGNAME(SH7750_MCR_A7) - REGNAME(SH7750_PCR_A7) - REGNAME(SH7750_RTCSR_A7) - REGNAME(SH7750_RTCNT_A7) - REGNAME(SH7750_RTCOR_A7) - REGNAME(SH7750_RFCR_A7) - REGNAME(SH7750_SAR0_A7) - REGNAME(SH7750_SAR1_A7) - REGNAME(SH7750_SAR2_A7) - REGNAME(SH7750_SAR3_A7) - REGNAME(SH7750_DAR0_A7) - REGNAME(SH7750_DAR1_A7) - REGNAME(SH7750_DAR2_A7) - REGNAME(SH7750_DAR3_A7) - REGNAME(SH7750_DMATCR0_A7) - REGNAME(SH7750_DMATCR1_A7) - REGNAME(SH7750_DMATCR2_A7) - REGNAME(SH7750_DMATCR3_A7) - REGNAME(SH7750_CHCR0_A7) - REGNAME(SH7750_CHCR1_A7) - REGNAME(SH7750_CHCR2_A7) - REGNAME(SH7750_CHCR3_A7) - REGNAME(SH7750_DMAOR_A7) - REGNAME(SH7750_PCTRA_A7) - REGNAME(SH7750_PDTRA_A7) - REGNAME(SH7750_PCTRB_A7) - REGNAME(SH7750_PDTRB_A7) - REGNAME(SH7750_GPIOIC_A7) - REGNAME(SH7750_ICR_A7) - REGNAME(SH7750_BCR3_A7) - REGNAME(SH7750_BCR4_A7) - REGNAME(SH7750_SDMR2_A7) - REGNAME(SH7750_SDMR3_A7) {(uint32_t) - 1, NULL} -}; - -const char *regname(uint32_t addr) -{ - unsigned int i; - - for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) { - if (regnames[i].regaddr == addr) - return regnames[i].regname; - } - - return ""; -} -- cgit v1.2.3