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 device-hotplug.o
common-obj-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
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
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)
--- /dev/null
+/*
+ * 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 <brlapi.h>
+#include <brlapi_constants.h>
+#include <brlapi_keycodes.h>
+#ifdef CONFIG_SDL
+#include <SDL_syswm.h>
+#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);
+}
+
+static 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;
+}
+
+static void register_types(void)
+{
+ register_char_driver("braille", chr_baum_init);
+}
+
+type_init(register_types);
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include "qemu-common.h"
+#include "char/char.h"
+#include "ui/console.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);
+}
+
+static 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;
+}
+
+static void register_types(void)
+{
+ register_char_driver("msmouse", qemu_chr_open_msmouse);
+}
+
+type_init(register_types);
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
"filename", "a valid filename");
} else {
- s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
+ s->fd = qemu_open(s->filename, O_RDONLY | O_NONBLOCK);
if (s->fd == -1) {
error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
if (s->fd != -1) {
- close(s->fd);
+ qemu_close(s->fd);
}
g_free(s->filename);
uint8_t *buf;
int status;
int canceled;
+ int retries;
size_t read_size;
size_t read_offset;
+ int64_t sector_num;
+ int nb_sectors;
#ifdef __linux__
sg_io_hdr_t *ioh;
#endif
#define NOP_INTERVAL 5000
#define MAX_NOP_FAILURES 3
+#define ISCSI_CMD_RETRIES 5
static void
iscsi_bh_cb(void *p)
iscsi_set_events(iscsilun);
}
+static int
+iscsi_aio_writev_acb(IscsiAIOCB *acb);
static void
iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
}
acb->status = 0;
- if (status < 0) {
+ if (status != 0) {
+ if (status == SCSI_STATUS_CHECK_CONDITION
+ && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
+ && acb->retries-- > 0) {
+ if (acb->task != NULL) {
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ }
+ if (iscsi_aio_writev_acb(acb) == 0) {
+ iscsi_set_events(acb->iscsilun);
+ return;
+ }
+ }
error_report("Failed to write16 data to iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
}
-static BlockDriverAIOCB *
-iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb,
- void *opaque)
+static int
+iscsi_aio_writev_acb(IscsiAIOCB *acb)
{
- IscsiLun *iscsilun = bs->opaque;
- struct iscsi_context *iscsi = iscsilun->iscsi;
- IscsiAIOCB *acb;
+ struct iscsi_context *iscsi = acb->iscsilun->iscsi;
size_t size;
uint32_t num_sectors;
uint64_t lba;
#endif
int ret;
- acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
- trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
-
- acb->iscsilun = iscsilun;
- acb->qiov = qiov;
-
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
/* this will allow us to get rid of 'buf' completely */
- size = nb_sectors * BDRV_SECTOR_SIZE;
+ size = acb->nb_sectors * BDRV_SECTOR_SIZE;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
data.size = MIN(size, acb->qiov->size);
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
"command. %s", iscsi_get_error(iscsi));
- qemu_aio_release(acb);
- return NULL;
+ return -1;
}
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_WRITE;
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x8a;
- lba = sector_qemu2lun(sector_num, iscsilun);
+ lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
- num_sectors = size / iscsilun->block_size;
+ num_sectors = size / acb->iscsilun->block_size;
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
acb->task->expxferlen = size;
#if defined(LIBISCSI_FEATURE_IOVECTOR)
- ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
+ ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
NULL,
acb);
#else
- ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
+ ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
&data,
acb);
#endif
if (ret != 0) {
- scsi_free_scsi_task(acb->task);
g_free(acb->buf);
- qemu_aio_release(acb);
- return NULL;
+ return -1;
}
#if defined(LIBISCSI_FEATURE_IOVECTOR)
scsi_task_set_iov_out(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov);
#endif
- iscsi_set_events(iscsilun);
+ return 0;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ IscsiAIOCB *acb;
+ acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
+ trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
+
+ acb->iscsilun = iscsilun;
+ acb->qiov = qiov;
+ acb->nb_sectors = nb_sectors;
+ acb->sector_num = sector_num;
+ acb->retries = ISCSI_CMD_RETRIES;
+
+ if (iscsi_aio_writev_acb(acb) != 0) {
+ if (acb->task) {
+ scsi_free_scsi_task(acb->task);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
+ iscsi_set_events(iscsilun);
return &acb->common;
}
+static int
+iscsi_aio_readv_acb(IscsiAIOCB *acb);
+
static void
iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
acb->status = 0;
if (status != 0) {
+ if (status == SCSI_STATUS_CHECK_CONDITION
+ && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
+ && acb->retries-- > 0) {
+ if (acb->task != NULL) {
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ }
+ if (iscsi_aio_readv_acb(acb) == 0) {
+ iscsi_set_events(acb->iscsilun);
+ return;
+ }
+ }
error_report("Failed to read16 data from iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
iscsi_schedule_bh(acb);
}
-static BlockDriverAIOCB *
-iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb,
- void *opaque)
+static int
+iscsi_aio_readv_acb(IscsiAIOCB *acb)
{
- IscsiLun *iscsilun = bs->opaque;
- struct iscsi_context *iscsi = iscsilun->iscsi;
- IscsiAIOCB *acb;
- size_t qemu_read_size;
+ struct iscsi_context *iscsi = acb->iscsilun->iscsi;
+ uint64_t lba;
+ uint32_t num_sectors;
+ int ret;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
int i;
#endif
- int ret;
- uint64_t lba;
- uint32_t num_sectors;
-
- qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
-
- acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
- trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
-
- acb->iscsilun = iscsilun;
- acb->qiov = qiov;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
- acb->read_size = qemu_read_size;
acb->buf = NULL;
/* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
* data.
*/
acb->read_offset = 0;
- if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
- uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
+ if (acb->iscsilun->block_size > BDRV_SECTOR_SIZE) {
+ uint64_t bdrv_offset = BDRV_SECTOR_SIZE * acb->sector_num;
- acb->read_offset = bdrv_offset % iscsilun->block_size;
+ acb->read_offset = bdrv_offset % acb->iscsilun->block_size;
}
- num_sectors = (qemu_read_size + iscsilun->block_size
+ num_sectors = (acb->read_size + acb->iscsilun->block_size
+ acb->read_offset - 1)
- / iscsilun->block_size;
+ / acb->iscsilun->block_size;
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi READ16 "
"command. %s", iscsi_get_error(iscsi));
- qemu_aio_release(acb);
- return NULL;
+ return -1;
}
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_READ;
- lba = sector_qemu2lun(sector_num, iscsilun);
- acb->task->expxferlen = qemu_read_size;
+ lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
+ acb->task->expxferlen = acb->read_size;
- switch (iscsilun->type) {
+ switch (acb->iscsilun->type) {
case TYPE_DISK:
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x88;
break;
}
- ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
+ ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
iscsi_aio_read16_cb,
NULL,
acb);
if (ret != 0) {
- scsi_free_scsi_task(acb->task);
- qemu_aio_release(acb);
- return NULL;
+ return -1;
}
#if defined(LIBISCSI_FEATURE_IOVECTOR)
acb->qiov->iov[i].iov_base);
}
#endif
+ return 0;
+}
- iscsi_set_events(iscsilun);
+static BlockDriverAIOCB *
+iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ IscsiAIOCB *acb;
+ acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
+ trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
+
+ acb->nb_sectors = nb_sectors;
+ acb->sector_num = sector_num;
+ acb->iscsilun = iscsilun;
+ acb->qiov = qiov;
+ acb->read_size = BDRV_SECTOR_SIZE * (size_t)acb->nb_sectors;
+ acb->retries = ISCSI_CMD_RETRIES;
+
+ if (iscsi_aio_readv_acb(acb) != 0) {
+ if (acb->task) {
+ scsi_free_scsi_task(acb->task);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
+ iscsi_set_events(iscsilun);
return &acb->common;
}
+static int
+iscsi_aio_flush_acb(IscsiAIOCB *acb);
static void
iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
}
acb->status = 0;
- if (status < 0) {
+ if (status != 0) {
+ if (status == SCSI_STATUS_CHECK_CONDITION
+ && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
+ && acb->retries-- > 0) {
+ if (acb->task != NULL) {
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ }
+ if (iscsi_aio_flush_acb(acb) == 0) {
+ iscsi_set_events(acb->iscsilun);
+ return;
+ }
+ }
error_report("Failed to sync10 data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
iscsi_schedule_bh(acb);
}
-static BlockDriverAIOCB *
-iscsi_aio_flush(BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque)
+static int
+iscsi_aio_flush_acb(IscsiAIOCB *acb)
{
- IscsiLun *iscsilun = bs->opaque;
- struct iscsi_context *iscsi = iscsilun->iscsi;
- IscsiAIOCB *acb;
-
- acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
+ struct iscsi_context *iscsi = acb->iscsilun->iscsi;
- acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
- acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
+ acb->task = iscsi_synchronizecache10_task(iscsi, acb->iscsilun->lun,
0, 0, 0, 0,
iscsi_synccache10_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send synchronizecache10 command. %s",
iscsi_get_error(iscsi));
+ return -1;
+ }
+
+ return 0;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ IscsiLun *iscsilun = bs->opaque;
+
+ IscsiAIOCB *acb;
+
+ acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
+
+ acb->iscsilun = iscsilun;
+ acb->retries = ISCSI_CMD_RETRIES;
+
+ if (iscsi_aio_flush_acb(acb) != 0) {
qemu_aio_release(acb);
return NULL;
}
return &acb->common;
}
+static int iscsi_aio_discard_acb(IscsiAIOCB *acb);
+
static void
iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
}
acb->status = 0;
- if (status < 0) {
+ if (status != 0) {
+ if (status == SCSI_STATUS_CHECK_CONDITION
+ && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
+ && acb->retries-- > 0) {
+ if (acb->task != NULL) {
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ }
+ if (iscsi_aio_discard_acb(acb) == 0) {
+ iscsi_set_events(acb->iscsilun);
+ return;
+ }
+ }
error_report("Failed to unmap data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
iscsi_schedule_bh(acb);
}
-static BlockDriverAIOCB *
-iscsi_aio_discard(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- IscsiLun *iscsilun = bs->opaque;
- struct iscsi_context *iscsi = iscsilun->iscsi;
- IscsiAIOCB *acb;
+static int iscsi_aio_discard_acb(IscsiAIOCB *acb) {
+ struct iscsi_context *iscsi = acb->iscsilun->iscsi;
struct unmap_list list[1];
- acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
-
- acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
- list[0].lba = sector_qemu2lun(sector_num, iscsilun);
- list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
+ list[0].lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
+ list[0].num = acb->nb_sectors * BDRV_SECTOR_SIZE / acb->iscsilun->block_size;
- acb->task = iscsi_unmap_task(iscsi, iscsilun->lun,
+ acb->task = iscsi_unmap_task(iscsi, acb->iscsilun->lun,
0, 0, &list[0], 1,
iscsi_unmap_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send unmap command. %s",
iscsi_get_error(iscsi));
+ return -1;
+ }
+
+ return 0;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_discard(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ IscsiAIOCB *acb;
+
+ acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
+
+ acb->iscsilun = iscsilun;
+ acb->nb_sectors = nb_sectors;
+ acb->sector_num = sector_num;
+ acb->retries = ISCSI_CMD_RETRIES;
+
+ if (iscsi_aio_discard_acb(acb) != 0) {
+ if (acb->task) {
+ scsi_free_scsi_task(acb->task);
+ }
qemu_aio_release(acb);
return NULL;
}
}
#endif
+static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
+{
+ struct scsi_task *task = NULL;
+ struct scsi_readcapacity10 *rc10 = NULL;
+ struct scsi_readcapacity16 *rc16 = NULL;
+ int ret = 0;
+ int retries = ISCSI_CMD_RETRIES;
+
+try_again:
+ switch (iscsilun->type) {
+ case TYPE_DISK:
+ task = iscsi_readcapacity16_sync(iscsilun->iscsi, iscsilun->lun);
+ if (task == NULL || task->status != SCSI_STATUS_GOOD) {
+ if (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION
+ && task->sense.key == SCSI_SENSE_UNIT_ATTENTION
+ && retries-- > 0) {
+ scsi_free_scsi_task(task);
+ goto try_again;
+ }
+ error_report("iSCSI: failed to send readcapacity16 command.");
+ ret = -EINVAL;
+ goto out;
+ }
+ rc16 = scsi_datain_unmarshall(task);
+ if (rc16 == NULL) {
+ error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
+ ret = -EINVAL;
+ goto out;
+ }
+ iscsilun->block_size = rc16->block_length;
+ iscsilun->num_blocks = rc16->returned_lba + 1;
+ break;
+ case TYPE_ROM:
+ task = iscsi_readcapacity10_sync(iscsilun->iscsi, iscsilun->lun, 0, 0);
+ if (task == NULL || task->status != SCSI_STATUS_GOOD) {
+ error_report("iSCSI: failed to send readcapacity10 command.");
+ ret = -EINVAL;
+ goto out;
+ }
+ rc10 = scsi_datain_unmarshall(task);
+ if (rc10 == NULL) {
+ error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
+ ret = -EINVAL;
+ goto out;
+ }
+ iscsilun->block_size = rc10->block_size;
+ if (rc10->lba == 0) {
+ /* blank disk loaded */
+ iscsilun->num_blocks = 0;
+ } else {
+ iscsilun->num_blocks = rc10->lba + 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+out:
+ if (task) {
+ scsi_free_scsi_task(task);
+ }
+
+ return ret;
+}
+
/*
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
struct iscsi_url *iscsi_url = NULL;
struct scsi_task *task = NULL;
struct scsi_inquiry_standard *inq = NULL;
- struct scsi_readcapacity10 *rc10 = NULL;
- struct scsi_readcapacity16 *rc16 = NULL;
char *initiator_name = NULL;
int ret;
iscsilun->type = inq->periperal_device_type;
- scsi_free_scsi_task(task);
-
- switch (iscsilun->type) {
- case TYPE_DISK:
- task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
- if (task == NULL || task->status != SCSI_STATUS_GOOD) {
- error_report("iSCSI: failed to send readcapacity16 command.");
- ret = -EINVAL;
- goto out;
- }
- rc16 = scsi_datain_unmarshall(task);
- if (rc16 == NULL) {
- error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
- ret = -EINVAL;
- goto out;
- }
- iscsilun->block_size = rc16->block_length;
- iscsilun->num_blocks = rc16->returned_lba + 1;
- break;
- case TYPE_ROM:
- task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
- if (task == NULL || task->status != SCSI_STATUS_GOOD) {
- error_report("iSCSI: failed to send readcapacity10 command.");
- ret = -EINVAL;
- goto out;
- }
- rc10 = scsi_datain_unmarshall(task);
- if (rc10 == NULL) {
- error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
- ret = -EINVAL;
- goto out;
- }
- iscsilun->block_size = rc10->block_size;
- if (rc10->lba == 0) {
- /* blank disk loaded */
- iscsilun->num_blocks = 0;
- } else {
- iscsilun->num_blocks = rc10->lba + 1;
- }
- break;
- default:
- break;
+ if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
+ goto out;
}
-
bs->total_sectors = iscsilun->num_blocks *
iscsilun->block_size / BDRV_SECTOR_SIZE ;
bs->sg = 1;
}
- ret = 0;
-
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
/* Set up a timer for sending out iSCSI NOPs */
iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event, iscsilun);
memset(iscsilun, 0, sizeof(IscsiLun));
}
+static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ int ret = 0;
+
+ if (iscsilun->type != TYPE_DISK) {
+ return -ENOTSUP;
+ }
+
+ if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
+ return ret;
+ }
+
+ if (offset > iscsi_getlength(bs)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int iscsi_has_zero_init(BlockDriverState *bs)
{
return 0;
.create_options = iscsi_create_options,
.bdrv_getlength = iscsi_getlength,
+ .bdrv_truncate = iscsi_truncate,
.bdrv_aio_readv = iscsi_aio_readv,
.bdrv_aio_writev = iscsi_aio_writev,
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"
#include <iscsi/iscsi.h>
int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; }
EOF
- if compile_prog "" "-liscsi" ; then
+ if $pkg_config --atleast-version=1.7.0 libiscsi --modversion >/dev/null 2>&1; then
+ libiscsi="yes"
+ libiscsi_cflags=$($pkg_config --cflags libiscsi 2>/dev/null)
+ libiscsi_libs=$($pkg_config --libs libiscsi 2>/dev/null)
+ CFLAGS="$CFLAGS $libiscsi_cflags"
+ LIBS="$LIBS $libiscsi_libs"
+ elif compile_prog "" "-liscsi" ; then
libiscsi="yes"
LIBS="$LIBS -liscsi"
else
spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
if $pkg_config --atleast-version=0.12.0 spice-server >/dev/null 2>&1 && \
- $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1 && \
+ $pkg_config --atleast-version=0.12.3 spice-protocol > /dev/null 2>&1 && \
compile_prog "$spice_cflags" "$spice_libs" ; then
spice="yes"
libs_softmmu="$libs_softmmu $spice_libs"
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"
TARGET_ARCH=microblaze
bflt="yes"
target_nptl="yes"
- target_libs_softmmu="$fdt_libs"
;;
mips|mipsel)
TARGET_ARCH=mips
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
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
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
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
FILES="$FILES pc-bios/spapr-rtas/Makefile"
FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
+FILES="$FILES pc-bios/qemu-icon.bmp"
for bios_file in \
$source_path/pc-bios/*.bin \
$source_path/pc-bios/*.aml \
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
+CONFIG_E500=$(CONFIG_FDT)
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
+CONFIG_PSERIES=$(CONFIG_FDT)
+CONFIG_E500=$(CONFIG_FDT)
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
+CONFIG_E500=$(CONFIG_FDT)
--- /dev/null
+/*
+ * 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);
+ }
+}
+++ /dev/null
-/*
- * Virtio 9p
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * 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
#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"
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)
--- /dev/null
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * 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
#include <sys/un.h>
#include "hw/virtio.h"
#include "virtio-9p.h"
+#include "qemu/error-report.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-proxy.h"
#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"
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) {
}
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);
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
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 += qdev-monitor.o
+common-obj-y += ps2.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
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
ifeq ($(CONFIG_PCI), y)
obj-$(CONFIG_LINUX) += vfio_pci.o
endif
-$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
endif
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "sysemu/kvm.h"
/* A15MP private memory region. */
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
typedef struct A9MPPrivState {
SysBusDevice busdev;
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
/* A9MP private memory region. */
* 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 {
* 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 {
* 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
#ifndef HW_ACPI_ICH9_H
#define HW_ACPI_ICH9_H
-#include "acpi.h"
+#include "hw/acpi.h"
typedef struct ICH9LPCPMRegs {
/*
* 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
* 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 */
#if !defined(__ADB_H__)
#define __ADB_H__
-#include "qdev.h"
+#include "hw/qdev.h"
#define MAX_ADB_DEVICES 16
* 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
void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
#define SHIFT 2
#else
-#include "fmopl.h"
+#include "hw/fmopl.h"
#define SHIFT 1
#endif
* GNU GPL, version 2 or (at your option) any later version.
*/
-#include "ssi.h"
+#include "hw/ssi.h"
#include "ui/console.h"
typedef struct {
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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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,
+ },
+};
+++ /dev/null
-/*
- * 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.h"
-#include "elf.h"
-#include "loader.h"
-#include "boards.h"
-#include "alpha_sys.h"
-#include "sysemu/sysemu.h"
-#include "mc146818rtc.h"
-#include "ide.h"
-#include "i8254.h"
-#include "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);
+++ /dev/null
-/*
- * QEMU Alpha PCI support functions.
- *
- * Some of this isn't very Alpha specific at all.
- *
- * ??? Sparse memory access not implemented.
- */
-
-#include "config.h"
-#include "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,
- },
-};
#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],
#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"
+++ /dev/null
-/*
- * Arnewsh 5206 ColdFire system emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-
-#include "hw.h"
-#include "mcf.h"
-#include "boards.h"
-#include "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);
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"
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#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
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
-#include "apic.h"
-#include "apic_internal.h"
+#include "hw/apic.h"
+#include "hw/apic_internal.h"
#include "trace.h"
#include "sysemu/kvm.h"
#define QEMU_APIC_INTERNAL_H
#include "exec/memory.h"
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "qemu/timer.h"
/* APIC Local Vector Table */
* 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
#include <stdint.h>
#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);
*
*/
-#include "hw.h"
-#include "isa.h"
+#include "hw/hw.h"
+#include "hw/isa.h"
#include "ui/console.h"
#include "qemu/timer.h"
-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 += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
-obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
+obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.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.o stellaris_enet.o
-obj-y += highbank.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 += gumstix.o
-obj-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
-obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
+obj-y += zaurus.o ide/microdrive.o tc6393xb.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 += 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-$(CONFIG_FDT) += ../device_tree.o
obj-$(CONFIG_KVM) += kvm/arm_gic.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
+
+obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
+obj-y += omap1.o omap2.o
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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 <wfi> */
+ 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);
+ }
+}
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * Samsung exynos4210 SoC emulation
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ * Maksim Kozlov <m.kozlov@samsung.com>
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ * Igor Mitsyanko <i.mitsyanko@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 <wfi> */
+ 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;
+}
--- /dev/null
+/*
+ * Samsung exynos4 SoC based boards emulation
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ * Maksim Kozlov <m.kozlov@samsung.com>
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ * Igor Mitsyanko <i.mitsyanko@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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);
--- /dev/null
+/*
+ * Gumstix Platforms
+ *
+ * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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);
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 <wfi> */
+ 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);
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * PXA270-based Intel Mainstone platforms.
+ *
+ * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
+ * <akuster@mvista.com>
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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);
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * Nokia N-series internet tablets.
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
--- /dev/null
+/*
+ * TI OMAP processors emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#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;
+}
--- /dev/null
+/*
+ * TI OMAP processors emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <i>value</i>. */
+ 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 <i>ch</i>. */
+ } 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;
+}
--- /dev/null
+/* omap_sx1.c Support for the Siemens SX1 smartphone emulation.
+ *
+ * Copyright (C) 2008
+ * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ * Copyright (C) 2007 Vladimir Ananiev <vovan888@gmail.com>
+ *
+ * based on PalmOne's (TM) PDAs support (palm.c)
+ */
+
+/*
+ * PalmOne's (TM) PDAs.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#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);
--- /dev/null
+/*
+ * PalmOne's (TM) PDAs.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#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);
--- /dev/null
+/*
+ * 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"
+#include "sysemu/kvm.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);
+ }
+}
+
+static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
+{
+#ifdef CONFIG_KVM
+ ARMCPU *cpu = opaque;
+ CPUState *cs = CPU(cpu);
+ int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
+
+ switch (irq) {
+ case ARM_PIC_CPU_IRQ:
+ kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
+ break;
+ case ARM_PIC_CPU_FIQ:
+ kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
+ break;
+ default:
+ hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
+ }
+ kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
+ kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
+#endif
+}
+
+qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
+{
+ if (kvm_enabled()) {
+ return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
+ }
+ return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
+}
--- /dev/null
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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)
--- /dev/null
+/*
+ * Intel XScale PXA255/270 GPIO controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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)
--- /dev/null
+/*
+ * Intel XScale PXA Programmable Interrupt Controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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)
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * PXA270-based Clamshell PDA platforms.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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)
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/* 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 <balrog@zabor.org>
+ * 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)
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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);
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
--- /dev/null
+/*
+ * PXA270-based Zipit Z2 device
+ *
+ * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * 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);
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "qemu/timer.h"
/* MPCore private memory region. */
+++ /dev/null
-/*
- * ARM kernel loader.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "config.h"
-#include "hw.h"
-#include "arm-misc.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "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 <wfi> */
- 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);
- }
-}
* armv7m_nvic device.
*/
-#include "sysbus.h"
-#include "arm_gic_internal.h"
+#include "hw/sysbus.h"
+#include "hw/arm_gic_internal.h"
//#define DEBUG_GIC
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "arm_gic_internal.h"
+#include "hw/arm_gic_internal.h"
static void gic_save(QEMUFile *f, void *opaque)
{
#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
*
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
/* L2C-310 r3p2 */
#define CACHE_ID 0x410000c8
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "qemu/timer.h"
/* This device implements the per-cpu private timer and watchdog block
+++ /dev/null
-/*
- * Generic ARM Programmable Interrupt Controller support.
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL
- */
-
-#include "hw.h"
-#include "arm-misc.h"
-#include "sysemu/kvm.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);
- }
-}
-
-static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
-{
-#ifdef CONFIG_KVM
- ARMCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
-
- switch (irq) {
- case ARM_PIC_CPU_IRQ:
- kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
- break;
- case ARM_PIC_CPU_FIQ:
- kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
- break;
- default:
- hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
- }
- kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
- kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
-#endif
-}
-
-qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
-{
- if (kvm_enabled()) {
- return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
- }
- return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
-}
* 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
* 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. */
+++ /dev/null
-/*
- * ARMV7M System emulation.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "sysbus.h"
-#include "arm-misc.h"
-#include "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)
* 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;
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "net/net.h"
-#include "flash.h"
-#include "boards.h"
-#include "etraxfs.h"
-#include "loader.h"
-#include "elf.h"
-#include "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);
+++ /dev/null
-/*
- * 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 <brlapi.h>
-#include <brlapi_constants.h>
-#include <brlapi_keycodes.h>
-#ifdef CONFIG_SDL
-#include <SDL_syswm.h>
-#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);
-}
-
-static 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;
-}
-
-static void register_types(void)
-{
- register_char_driver("braille", chr_baum_init);
-}
-
-type_init(register_types);
* 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
#ifndef BITBANG_I2C_H
#define BITBANG_I2C_H
-#include "i2c.h"
+#include "hw/i2c.h"
typedef struct bitbang_i2c_interface bitbang_i2c_interface;
#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);
}
#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)
{
#define HW_BOARDS_H
#include "sysemu/blockdev.h"
-#include "qdev.h"
+#include "hw/qdev.h"
#define DEFAULT_MACHINE_OPTIONS \
.boot_order = "cad"
#include <assert.h>
-#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"
#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;
#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);
#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,
#include "qemu-common.h"
#include "qemu/timer.h"
-#include "bt.h"
+#include "hw/bt.h"
#define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */
*/
#include "qemu-common.h"
-#include "bt.h"
+#include "hw/bt.h"
struct bt_l2cap_sdp_state_s {
struct bt_l2cap_conn_params_s *channel;
#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)
#include <zlib.h> /* For crc32 */
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "net/net.h"
#include "net/checksum.h"
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "qemu/timer.h"
#ifdef CADENCE_TTC_ERR_DEBUG
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "char/char.h"
#include "qemu/timer.h"
*/
#include "qemu-common.h"
-#include "irq.h"
-#include "devices.h"
+#include "hw/irq.h"
+#include "hw/devices.h"
#include "sysemu/sysemu.h"
//#define DEBUG
#ifndef CCID_H
#define CCID_H
-#include "qdev.h"
+#include "hw/qdev.h"
typedef struct CCIDCardState CCIDCardState;
typedef struct CCIDCardInfo CCIDCardInfo;
here. */
#include "qemu-common.h"
-#include "scsi.h"
+#include "hw/scsi.h"
static void lba_to_msf(uint8_t *buf, int lba)
{
* 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:
#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,
}
#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)
{
}
#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
+++ /dev/null
-/*
- * 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.h"
-#include "sysbus.h"
-#include "boards.h"
-#include "devices.h"
-#include "strongarm.h"
-#include "arm-misc.h"
-#include "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)
+++ /dev/null
-/*
- * 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.h"
-#include "loader.h"
-#include "elf.h"
-#include "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);
-}
-# 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
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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "hw.h"
-#include "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);
-}
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "trace.h"
/*
* 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"
/*
* 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"
*
*/
-#include "hw/dataplane/ioq.h"
+#include "ioq.h"
void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs)
{
#include "trace.h"
#include "qemu/iov.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"
#include "block/aio.h"
*/
#include "trace.h"
-#include "hw/dataplane/vring.h"
+#include "vring.h"
+#include "qemu/error-report.h"
/* Map the guest's vring to host memory */
bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
#include <linux/virtio_ring.h>
#include "qemu-common.h"
-#include "hw/dataplane/hostmem.h"
+#include "hostmem.h"
#include "hw/virtio.h"
typedef struct {
* 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) \
* (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) \
* 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
+++ /dev/null
-/*
- * 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);
- }
-}
* 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 */
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "trace.h"
typedef struct {
* 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.
+++ /dev/null
-/*
- * 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.h"
-#include "boards.h"
-#include "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);
*/
-#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
* 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.
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "trace.h"
/* There are 3 versions of this chip used in SMP sun4m systems:
*/
#include <stddef.h> /* 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"
* - 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
* 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
/* #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:
* 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"
* 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"
* THE SOFTWARE.
*/
-#include "sysbus.h"
-#include "esp.h"
+#include "hw/sysbus.h"
+#include "hw/esp.h"
#include "trace.h"
#include "qemu/log.h"
#ifndef QEMU_HW_ESP_H
#define QEMU_HW_ESP_H
-#include "scsi.h"
+#include "hw/scsi.h"
/* esp.c */
#define ESP_MAX_DEVS 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);
*/
#include <stdio.h>
#include <sys/time.h>
-#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)
*/
#include <stdio.h>
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "net/net.h"
-#include "etraxfs.h"
+#include "hw/etraxfs.h"
#define D(x)
* THE SOFTWARE.
*/
-#include "sysbus.h"
-#include "hw.h"
+#include "hw/sysbus.h"
+#include "hw/hw.h"
//#include "pc.h"
//#include "etraxfs.h"
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "char/char.h"
#include "qemu/log.h"
* 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)
+++ /dev/null
-/*
- * Samsung exynos4210 SoC emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- * Maksim Kozlov <m.kozlov@samsung.com>
- * Evgeny Voevodin <e.voevodin@samsung.com>
- * Igor Mitsyanko <i.mitsyanko@samsung.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "boards.h"
-#include "sysemu/sysemu.h"
-#include "sysbus.h"
-#include "arm-misc.h"
-#include "loader.h"
-#include "exynos4210.h"
-#include "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 <wfi> */
- 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;
-}
* IRQs are passed to GIC through Combiner.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
-#include "exynos4210.h"
+#include "hw/exynos4210.h"
//#define DEBUG_COMBINER
#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"
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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,
*/
#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
* 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
* uses PMU INFORM5 register as a holding pen.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#ifndef DEBUG_PMU
#define DEBUG_PMU 0
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
* 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
*
*/
-#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
+++ /dev/null
-/*
- * Samsung exynos4 SoC based boards emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- * Maksim Kozlov <m.kozlov@samsung.com>
- * Evgeny Voevodin <e.voevodin@samsung.com>
- * Igor Mitsyanko <i.mitsyanko@samsung.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "sysemu/sysemu.h"
-#include "sysbus.h"
-#include "net/net.h"
-#include "arm-misc.h"
-#include "exec/address-spaces.h"
-#include "exynos4210.h"
-#include "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);
* 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"
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#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()
- }
-};
+++ /dev/null
-#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 */
#include <stdarg.h>
#include <math.h>
//#include "driver.h" /* use M.A.M.E. */
-#include "fmopl.h"
+#include "hw/fmopl.h"
#ifndef PI
#define PI 3.14159265358979323846
- 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. */
* 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"
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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 */
* 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
#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
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "char/char.h"
#include "trace.h"
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "qemu/timer.h"
-#include "ptimer.h"
+#include "hw/ptimer.h"
#include "trace.h"
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "cpu.h"
-#include "grlib.h"
+#include "hw/grlib.h"
#include "trace.h"
* 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
+++ /dev/null
-/*
- * Gumstix Platforms
- *
- * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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.h"
-#include "pxa.h"
-#include "net/net.h"
-#include "flash.h"
-#include "devices.h"
-#include "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);
* 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
* 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)))
* 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)))
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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"
/* -------------------------------------------------------------------------- */
* 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
* 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
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "sysbus.h"
-#include "arm-misc.h"
-#include "devices.h"
-#include "loader.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "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 <wfi> */
- 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);
* 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
#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"
* This code is licensed under the LGPL.
*/
-#include "i2c.h"
+#include "hw/i2c.h"
struct i2c_bus
{
#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
-obj-y += mc146818rtc.o pc.o
-obj-y += apic_common.o apic.o kvmvapic.o
+obj-y += mc146818rtc.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 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
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
+
+obj-y += kvmvapic.o
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 <glib.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 "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 <xen/hvm/hvm_info_table.h>
+#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", \
+ }, {\
+ .driver = "e1000",\
+ .property = "autonegotiation",\
+ .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);
--- /dev/null
+/*
+ * Q35 chipset based pc system emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2009, 2010
+ * Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * 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);
--- /dev/null
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@hp.com>
+ *
+ * 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;
+}
--- /dev/null
+#include <signal.h>
+#include "hw/xen_backend.h"
+#include "hw/xen_domainbuild.h"
+#include "qemu/timer.h"
+#include "qemu/log.h"
+
+#include <xenguest.h>
+
+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;
+}
--- /dev/null
+/*
+ * 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);
* THE SOFTWARE.
*/
-#include "isa.h"
+#include "hw/isa.h"
//#define DEBUG_I82374
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
* 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
#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
* 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)
#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 */
* 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
* 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)
{
#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;
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
-#include "pci/pci.h"
-#include "ich9.h"
+#include "hw/pci/pci.h"
+#include "hw/ich9.h"
/*****************************************************************************/
#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);
#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
* 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
* 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 */
* 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
*
*/
-#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
+++ /dev/null
-/*
- * ARM Integrator CP System emulation.
- *
- * Copyright (c) 2005-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL
- */
-
-#include "sysbus.h"
-#include "devices.h"
-#include "boards.h"
-#include "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)
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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"
/* --------------------------------------------------------------------- */
#ifndef HW_INTEL_HDA_H
#define HW_INTEL_HDA_H
-#include "qdev.h"
+#include "hw/qdev.h"
/* --------------------------------------------------------------------- */
/* hda bus */
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#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)
{
#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
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
#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,
* later version.
*/
-#include "ipack.h"
+#include "hw/ipack.h"
IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot)
{
#ifndef QEMU_IPACK_H
#define QEMU_IPACK_H
-#include "qdev.h"
+#include "hw/qdev.h"
typedef struct IPackBus IPackBus;
* later version.
*/
-#include "ipack.h"
+#include "hw/ipack.h"
#include "qemu/bitops.h"
#include "char/char.h"
* THE SOFTWARE.
*/
#include "qemu-common.h"
-#include "irq.h"
+#include "hw/irq.h"
struct IRQState {
qemu_irq_handler handler;
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#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;
#include "exec/ioport.h"
#include "exec/memory.h"
-#include "qdev.h"
+#include "hw/qdev.h"
#define ISA_NUM_IRQS 16
* 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,
* 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"
#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,
+++ /dev/null
-/*
- * 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 "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);
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "exec/address-spaces.h"
-#include "hw.h"
-#include "arm-misc.h"
-#include "devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "serial.h"
-#include "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)
* 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 <zlib.h>
* 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 {
+++ /dev/null
-/*
- * 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.h"
-#include "qemu/timer.h"
-#include "ptimer.h"
-#include "char/char.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "loader.h"
-#include "elf.h"
-#include "trace.h"
-#include "exec/address-spaces.h"
-
-#include "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);
-# LM32 boards
-obj-y += lm32_boards.o
-obj-y += milkymist.o
-
# LM32 peripherals
obj-y += lm32_pic.o
obj-y += lm32_juart.o
obj-y += framebuffer.o
obj-y := $(addprefix ../,$(obj-y))
+
+# LM32 boards
+obj-y += lm32_boards.o
+obj-y += milkymist.o
--- /dev/null
+/*
+ * QEMU models for LatticeMico32 uclinux and evr32 boards.
+ *
+ * Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
--- /dev/null
+/*
+ * QEMU model for the Milkymist board.
+ *
+ * Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+++ /dev/null
-/*
- * QEMU models for LatticeMico32 uclinux and evr32 boards.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "sysbus.h"
-#include "hw.h"
-#include "flash.h"
-#include "devices.h"
-#include "boards.h"
-#include "loader.h"
-#include "sysemu/blockdev.h"
-#include "elf.h"
-#include "lm32_hwsetup.h"
-#include "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);
#define QEMU_HW_LM32_HWSETUP_H
#include "qemu-common.h"
-#include "loader.h"
+#include "hw/loader.h"
typedef struct {
void *data;
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#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,
#include <assert.h>
-#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;
* 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"
* 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)
*/
-#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"
* 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
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "hw.h"
-#include "i2c.h"
+#include "hw/hw.h"
+#include "hw/i2c.h"
#include "qemu/timer.h"
#include "ui/console.h"
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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"
#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
#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),
* 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"
#include <assert.h>
-#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
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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 { \
* 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
-obj-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
-obj-y += dummy_m68k.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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
* 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 */
* 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
* 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)
+++ /dev/null
-/*
- * PXA270-based Intel Mainstone platforms.
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- * <akuster@mvista.com>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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.h"
-#include "pxa.h"
-#include "arm-misc.h"
-#include "net/net.h"
-#include "devices.h"
-#include "boards.h"
-#include "flash.h"
-#include "sysemu/blockdev.h"
-#include "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);
* 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
* GNU GPL, version 2 or (at your option) any later version.
*/
-#include "ssi.h"
+#include "hw/ssi.h"
typedef struct {
SSISlave ssidev;
* This file is licensed under GNU GPL.
*/
-#include "i2c.h"
+#include "hw/i2c.h"
typedef struct {
I2CSlave i2c;
* 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
#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);
+++ /dev/null
-/*
- * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw.h"
-#include "mcf.h"
-#include "qemu/timer.h"
-#include "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;
-}
+++ /dev/null
-/*
- * Motorola ColdFire MCF5208 SoC emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw.h"
-#include "mcf.h"
-#include "qemu/timer.h"
-#include "ptimer.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-#include "boards.h"
-#include "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);
*
* 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 <zlib.h>
#include "exec/address-spaces.h"
+++ /dev/null
-/*
- * ColdFire Interrupt Controller emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw.h"
-#include "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);
-}
*
* 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"
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#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 */
-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-$(CONFIG_FDT) += ../device_tree.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
--- /dev/null
+/*
+ * Microblaze kernel loader
+ *
+ * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * Model of Petalogix linux reference design targeting Xilinx Spartan ml605
+ * board.
+ *
+ * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
+ * 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);
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
+++ /dev/null
-/*
- * Microblaze kernel loader
- *
- * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
- * 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 "loader.h"
-#include "elf.h"
-
-#include "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);
- }
-
-}
#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,
+++ /dev/null
-/*
- * 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.h"
-#include "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);
-}
* 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"
* 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"
#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,
return dev;
}
-static inline DeviceState *milkymist_minimac_create(hwaddr base,
- qemu_irq rx_irq, qemu_irq tx_irq)
-{
- DeviceState *dev;
-
- qemu_check_nic_model(&nd_table[0], "minimac");
- dev = qdev_create(NULL, "milkymist-minimac");
- qdev_set_nic_properties(dev, &nd_table[0]);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq);
-
- return dev;
-}
-
static inline DeviceState *milkymist_minimac2_create(hwaddr base,
hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
{
* 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),
*
*/
-#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 <zlib.h>
*
*/
-#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"
* 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 {
* 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 {
*
*/
-#include "hw.h"
-#include "sysbus.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
#include "trace.h"
#include "qemu/error-report.h"
* 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"
* 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,
+++ /dev/null
-/*
- * QEMU model for the Milkymist board.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "sysbus.h"
-#include "hw.h"
-#include "flash.h"
-#include "sysemu/sysemu.h"
-#include "devices.h"
-#include "boards.h"
-#include "loader.h"
-#include "elf.h"
-#include "sysemu/blockdev.h"
-#include "milkymist-hw.h"
-#include "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);
-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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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 <outch+0x8> */
+ 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);
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+++ /dev/null
-/*
- * 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.h"
-#include "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;
-}
+++ /dev/null
-/*
- * 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.h"
-#include "pc.h"
-#include "serial.h"
-#include "fdc.h"
-#include "net/net.h"
-#include "boards.h"
-#include "smbus.h"
-#include "block/block.h"
-#include "flash.h"
-#include "mips.h"
-#include "mips_cpudevs.h"
-#include "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 "elf.h"
-#include "vt82c686.h"
-#include "mc146818rtc.h"
-#include "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);
+++ /dev/null
-/*
- * 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.h"
-#include "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);
-}
+++ /dev/null
-/*
- * 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.h"
-#include "mips.h"
-#include "mips_cpudevs.h"
-#include "pc.h"
-#include "serial.h"
-#include "isa.h"
-#include "fdc.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/arch_init.h"
-#include "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 "sysemu/blockdev.h"
-#include "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);
+++ /dev/null
-/*
- * 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.h"
-#include "pc.h"
-#include "serial.h"
-#include "fdc.h"
-#include "net/net.h"
-#include "boards.h"
-#include "smbus.h"
-#include "block/block.h"
-#include "flash.h"
-#include "mips.h"
-#include "mips_cpudevs.h"
-#include "pci/pci.h"
-#include "char/char.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/arch_init.h"
-#include "boards.h"
-#include "qemu/log.h"
-#include "mips-bios.h"
-#include "ide.h"
-#include "loader.h"
-#include "elf.h"
-#include "mc146818rtc.h"
-#include "i8254.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-#include "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 <outch+0x8> */
- 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);
+++ /dev/null
-/*
- * 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.h"
-#include "mips.h"
-#include "mips_cpudevs.h"
-#include "serial.h"
-#include "isa.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "mips-bios.h"
-#include "loader.h"
-#include "elf.h"
-#include "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);
+++ /dev/null
-/*
- * 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.h"
-#include "mips.h"
-#include "mips_cpudevs.h"
-#include "pc.h"
-#include "serial.h"
-#include "isa.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "flash.h"
-#include "qemu/log.h"
-#include "mips-bios.h"
-#include "ide.h"
-#include "loader.h"
-#include "elf.h"
-#include "mc146818rtc.h"
-#include "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);
+++ /dev/null
-/*
- * 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.h"
-#include "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);
-}
-#include "hw.h"
+#include "hw/hw.h"
#include "net/net.h"
#include "trace.h"
-#include "sysbus.h"
+#include "hw/sysbus.h"
/* MIPSnet register offsets */
+++ /dev/null
-/*
- * QEMU PowerPC MPC8544 global util pseudo-device
- *
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <alex@csgraf.de>
- *
- * 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.h"
-#include "sysemu/sysemu.h"
-#include "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)
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include "qemu-common.h"
-#include "char/char.h"
-#include "ui/console.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);
-}
-
-static 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;
-}
-
-static void register_types(void)
-{
- register_char_driver("msmouse", qemu_chr_open_msmouse);
-}
-
-type_init(register_types);
* 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
+++ /dev/null
-/*
- * 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.h"
-#include "fw_cfg.h"
-#include "multiboot.h"
-#include "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 */
-}
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "arm-misc.h"
-#include "devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "serial.h"
-#include "qemu/timer.h"
-#include "ptimer.h"
-#include "block/block.h"
-#include "flash.h"
-#include "ui/console.h"
-#include "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)
#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
* 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 {
* 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 */
+++ /dev/null
-/*
- * Nokia N-series internet tablets.
- *
- * Copyright (C) 2007 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "sysemu/sysemu.h"
-#include "omap.h"
-#include "arm-misc.h"
-#include "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 "sysemu/blockdev.h"
-#include "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);
+++ /dev/null
-/*
- * TI OMAP processors emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-#include "hw.h"
-#include "arm-misc.h"
-#include "omap.h"
-#include "sysemu/sysemu.h"
-#include "soc_dma.h"
-#include "sysemu/blockdev.h"
-#include "qemu/range.h"
-#include "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;
-}
+++ /dev/null
-/*
- * TI OMAP processors emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "sysemu/blockdev.h"
-#include "hw.h"
-#include "arm-misc.h"
-#include "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 "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 <i>value</i>. */
- 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 <i>ch</i>. */
- } 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;
-}
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "hw.h"
-#include "omap.h"
+#include "hw/hw.h"
+#include "hw/omap.h"
struct clk {
const char *name;
*/
#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 */
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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;
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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;
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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"
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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 {
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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 {
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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 {
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "hw.h"
-#include "omap.h"
+#include "hw/hw.h"
+#include "hw/omap.h"
struct omap_l4_s {
MemoryRegion *address_space;
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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 {
#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,
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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;
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "hw.h"
-#include "omap.h"
+#include "hw/hw.h"
+#include "hw/omap.h"
/* SDRAM Controller Subsystem */
struct omap_sdrc_s {
* 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 {
+++ /dev/null
-/* omap_sx1.c Support for the Siemens SX1 smartphone emulation.
- *
- * Copyright (C) 2008
- * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- * Copyright (C) 2007 Vladimir Ananiev <vovan888@gmail.com>
- *
- * based on PalmOne's (TM) PDAs support (palm.c)
- */
-
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-#include "hw.h"
-#include "ui/console.h"
-#include "omap.h"
-#include "boards.h"
-#include "arm-misc.h"
-#include "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);
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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;
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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,
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#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 */
*/
#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 */
* 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"
* 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
-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
--- /dev/null
+/*
+ * QEMU OpenRISC timer support
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Zhizhou Zhang <etouzh@gmail.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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;
+}
--- /dev/null
+/*
+ * OpenRISC simulator for use as an IIS.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Feng Gao <gf91597@gmail.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
--- /dev/null
+/*
+ * OpenRISC Programmable Interrupt Controller support.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Feng Gao <gf91597@gmail.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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];
+ }
+}
+++ /dev/null
-/*
- * OpenRISC Programmable Interrupt Controller support.
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * Feng Gao <gf91597@gmail.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "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];
- }
-}
+++ /dev/null
-/*
- * OpenRISC simulator for use as an IIS.
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * Feng Gao <gf91597@gmail.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "hw.h"
-#include "boards.h"
-#include "elf.h"
-#include "serial.h"
-#include "net/net.h"
-#include "loader.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "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);
+++ /dev/null
-/*
- * QEMU OpenRISC timer support
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * Zhizhou Zhang <etouzh@gmail.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "cpu.h"
-#include "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;
-}
+++ /dev/null
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-#include "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 "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);
* 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)
* 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
#if defined(CONFIG_POSIX)
#include <sys/mman.h>
#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
+++ /dev/null
-/*
- * 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.h"
-#include "pc.h"
-#include "serial.h"
-#include "apic.h"
-#include "fdc.h"
-#include "ide.h"
-#include "pci/pci.h"
-#include "monitor/monitor.h"
-#include "fw_cfg.h"
-#include "hpet_emul.h"
-#include "smbios.h"
-#include "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 "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
-#include "kvm_i386.h"
-#include "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);
- }
-}
#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). */
* THE SOFTWARE.
*/
-#include "pc87312.h"
+#include "hw/pc87312.h"
+#include "qemu/error-report.h"
#include "sysemu/blockdev.h"
#include "sysemu/sysemu.h"
#include "char/char.h"
#ifndef QEMU_PC87312_H
#define QEMU_PC87312_H
-#include "isa.h"
+#include "hw/isa.h"
#define TYPE_PC87312 "pc87312"
+++ /dev/null
-/*
- * 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 <glib.h>
-
-#include "hw.h"
-#include "pc.h"
-#include "apic.h"
-#include "pci/pci.h"
-#include "pci/pci_ids.h"
-#include "usb.h"
-#include "net/net.h"
-#include "boards.h"
-#include "ide.h"
-#include "sysemu/kvm.h"
-#include "kvm/clock.h"
-#include "sysemu/sysemu.h"
-#include "sysbus.h"
-#include "sysemu/arch_init.h"
-#include "sysemu/blockdev.h"
-#include "smbus.h"
-#include "xen.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "cpu.h"
-#ifdef CONFIG_XEN
-# include <xen/hvm/hvm_info_table.h>
-#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", \
- }, {\
- .driver = "e1000",\
- .property = "autonegotiation",\
- .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);
+++ /dev/null
-/*
- * Q35 chipset based pc system emulator
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2009, 2010
- * Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * 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.h"
-#include "sysemu/arch_init.h"
-#include "smbus.h"
-#include "boards.h"
-#include "mc146818rtc.h"
-#include "xen.h"
-#include "sysemu/kvm.h"
-#include "kvm/clock.h"
-#include "q35.h"
-#include "exec/address-spaces.h"
-#include "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);
*/
#include "sysemu/blockdev.h"
-#include "sysbus.h"
-#include "hw.h"
-#include "pc.h"
+#include "qemu/error-report.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"
MemoryRegion conf_mem;
MemoryRegion data_mem;
MemoryRegion mmcfg;
- MemoryRegion *address_space;
uint32_t config_reg;
PCIBus *bus;
};
+#include "qemu-common.h"
#include <strings.h>
#include <stdint.h>
#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"
#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)
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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;
* 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 */
* 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
* 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
* 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
#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)
{
+++ /dev/null
-/*
- * Model of Petalogix linux reference design targeting Xilinx Spartan ml605
- * board.
- *
- * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
- * 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 "sysbus.h"
-#include "hw.h"
-#include "net/net.h"
-#include "flash.h"
-#include "sysemu/sysemu.h"
-#include "devices.h"
-#include "boards.h"
-#include "xilinx.h"
-#include "sysemu/blockdev.h"
-#include "serial.h"
-#include "exec/address-spaces.h"
-#include "ssi.h"
-
-#include "microblaze_boot.h"
-#include "microblaze_pic_cpu.h"
-
-#include "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);
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "hw.h"
-#include "net/net.h"
-#include "flash.h"
-#include "sysemu/sysemu.h"
-#include "devices.h"
-#include "boards.h"
-#include "xilinx.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-
-#include "microblaze_boot.h"
-#include "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);
* 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 { \
* 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
* 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;
* 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"
/*
dev = qdev_create(NULL, "i440FX-pcihost");
s = PCI_HOST_BRIDGE(dev);
- s->address_space = address_space_mem;
b = pci_bus_new(dev, NULL, pci_address_space,
address_space_io, 0);
s->bus = b;
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "char/char.h"
typedef struct {
* 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
* 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"
*
*/
-#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
* 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;
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
//#define DEBUG_PL061 1
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#define PL080_MAX_CHANNELS 8
#define PL080_CONF_E 0x1
* 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
};
#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)
{
#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] =
*/
#include "sysemu/blockdev.h"
-#include "sysbus.h"
-#include "sd.h"
+#include "hw/sysbus.h"
+#include "hw/sd.h"
//#define DEBUG_PL181 1
* 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
* License along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*/
-#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? */
+++ /dev/null
-/*
- * 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.h"
-#include "ppc.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "nvram.h"
-#include "qemu/log.h"
-#include "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;
-}
-# 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) += 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
+obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o
+obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o
+obj-$(CONFIG_PSERIES) += 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
-# PowerPC E500 boards
-obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o
-# PowerPC 440 Xilinx ML507 reference board.
-obj-y += virtex_ml507.o
+obj-y += ppc4xx_pci.o
# PowerPC OpenPIC
obj-y += openpic.o
-obj-$(CONFIG_FDT) += ../device_tree.o
# Xilinx PPC peripherals
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 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
obj-y += prep.o
# OldWorld PowerMac
# 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
+obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
+# PowerPC 440 Xilinx ML507 reference board.
+obj-y += virtex_ml507.o
#ifndef E500_CCSR_H
#define E500_CCSR_H
-#include "../sysbus.h"
+#include "hw/sysbus.h"
typedef struct PPCE500CCSRState {
/*< private >*/
#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"
--- /dev/null
+/*
+ * QEMU PowerPC MPC8544 global util pseudo-device
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <alex@csgraf.de>
+ *
+ * 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)
#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"
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * QEMU PowerPC 440 Bamboo board emulation
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors:
+ * Jerone Young <jyoung5@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * QEMU PowerPC e500v2 ePAPR spinning code
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <agraf@suse.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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)
dev = qdev_create(NULL, "raven-pcihost");
pcihost = PCI_HOST_BRIDGE(dev);
- pcihost->address_space = get_system_memory();
object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
qdev_init_nofail(dev);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
--- /dev/null
+/*
+ * 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 <libfdt.h>
+
+/* 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_string(fdt, "compatible", "qemu,pseries")));
+
+ _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);
--- /dev/null
+/*
+ * 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 <libfdt.h>
+
+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<null> */
+} 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);
+}
--- /dev/null
+#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_read(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];
+ uint8_t *hpte;
+ int i, ridx, n_entries = 1;
+
+ if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ return H_PARAMETER;
+ }
+
+ if (flags & H_READ_4) {
+ /* Clear the two low order bits */
+ pte_index &= ~(3ULL);
+ n_entries = 4;
+ }
+
+ hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+
+ for (i = 0, ridx = 0; i < n_entries; i++) {
+ args[ridx++] = ldq_p(hpte);
+ args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+ hpte += HASH_PTE_SIZE_64;
+ }
+
+ 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);
+ spapr_register_hypercall(H_READ, h_read);
+
+ /* 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)
--- /dev/null
+/*
+ * QEMU sPAPR IOMMU (TCE) code
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#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 <libfdt.h>
+
+/* #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;
+}
--- /dev/null
+/*
+ * 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 <libfdt.h>
+
+#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)
--- /dev/null
+/*
+ * QEMU sPAPR VIO code
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
+ * Based on the s390 virtio bus code:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <libfdt.h>
+#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 */
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
#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;
+++ /dev/null
-/*
- * 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.h"
-#include "ppc.h"
-#include "ppc405.h"
-#include "nvram.h"
-#include "flash.h"
-#include "sysemu/sysemu.h"
-#include "block/block.h"
-#include "boards.h"
-#include "qemu/log.h"
-#include "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);
+++ /dev/null
-/*
- * 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.h"
-#include "ppc.h"
-#include "ppc405.h"
-#include "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;
-}
+++ /dev/null
-/*
- * QEMU PowerPC 440 Bamboo board emulation
- *
- * Copyright 2007 IBM Corporation.
- * Authors:
- * Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * Hollis Blanchard <hollisb@us.ibm.com>
- *
- * 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.h"
-#include "pci/pci.h"
-#include "boards.h"
-#include "sysemu/kvm.h"
-#include "kvm_ppc.h"
-#include "sysemu/device_tree.h"
-#include "loader.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-#include "serial.h"
-#include "ppc.h"
-#include "ppc405.h"
-#include "sysemu/sysemu.h"
-#include "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);
#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,
+++ /dev/null
-/*
- * 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.h"
-#include "ppc.h"
-#include "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;
-}
/* 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
+++ /dev/null
-/*
- * 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.h"
-#include "ppc.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "nvram.h"
-#include "qemu/log.h"
-#include "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);
-}
* (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__)
+++ /dev/null
-/*
- * QEMU PowerPC e500v2 ePAPR spinning code
- *
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <agraf@suse.de>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- * 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.h"
-#include "sysemu/sysemu.h"
-#include "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)
* 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"
* 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"
*
* 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
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "boards.h"
-#include "loader.h"
-#include "pc.h"
-
-#undef DEBUG_PUV3
-#include "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)
* 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)
* 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;
* 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;
* 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 {
* 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;
+++ /dev/null
-/*
- * Intel XScale PXA255/270 processor support.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "sysbus.h"
-#include "pxa.h"
-#include "sysemu/sysemu.h"
-#include "serial.h"
-#include "i2c.h"
-#include "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)
* 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
+++ /dev/null
-/*
- * Intel XScale PXA255/270 GPIO controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw.h"
-#include "sysbus.h"
-#include "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)
* 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"
/*
* 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;
};
#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)
* 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;
* 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 {
+++ /dev/null
-/*
- * Intel XScale PXA Programmable Interrupt Controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw.h"
-#include "pxa.h"
-#include "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)
* 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
* 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
#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) \
-#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"
/* --- target physical address --- */
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#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 : "<null>");
- 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;
-}
+++ /dev/null
-#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
*/
#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"
#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"
#ifndef QEMU_QDEV_PROPERTIES_H
#define QEMU_QDEV_PROPERTIES_H
-#include "qdev-core.h"
+#include "hw/qdev-core.h"
/*** qdev-properties.c ***/
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"
#include "qapi/visitor.h"
int qdev_hotplug = 0;
#define QDEV_H
#include "hw/hw.h"
-#include "qdev-core.h"
-#include "qdev-properties.h"
-#include "qdev-monitor.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
#endif
*/
#include "qemu/timer.h"
-#include "qxl.h"
+#include "hw/qxl.h"
static const char *qxl_type[] = {
[ QXL_CMD_NOP ] = "nop",
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "qxl.h"
+#include "hw/qxl.h"
static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
{
#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
#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"
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "hw.h"
-#include "sh.h"
-#include "devices.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "pci/pci.h"
-#include "net/net.h"
-#include "sh7750_regs.h"
-#include "ide.h"
-#include "loader.h"
-#include "usb.h"
-#include "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);
* THE SOFTWARE.
*/
-#include "hw.h"
-#include "mips.h"
+#include "hw/hw.h"
+#include "hw/mips.h"
#include "qemu/timer.h"
/********************************************************/
+++ /dev/null
-/*
- * ARM RealView Baseboard System emulation.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * 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 "net/net.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "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);
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
typedef struct {
SysBusDevice busdev;
/* For crc32 */
#include <zlib.h>
-#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"
#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;
#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"
#include "sysemu/kvm.h"
#include "exec/memory.h"
-#include "sclp.h"
+#include "hw/s390x/sclp.h"
static inline S390SCLPDevice *get_event_facility(void)
{
#include <hw/qdev.h>
#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 {
*/
#include <hw/qdev.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 SignalQuiesce {
EventBufferHeader ebh;
* 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"
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
//#define DEBUG_IRQ
-#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"
will start the next chunk or complete the command. */
void scsi_req_continue(SCSIRequest *req)
{
+ if (req->io_canceled) {
+ trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
+ return;
+ }
trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
if (req->cmd.mode == SCSI_XFER_TO_DEV) {
req->ops->write_data(req);
#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"
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ if (r->req.io_canceled) {
+ goto done;
+ }
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ if (r->req.io_canceled) {
+ goto done;
+ }
+
if (scsi_is_cmd_fua(&r->req.cmd)) {
bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
}
scsi_req_complete(&r->req, GOOD);
+
+done:
if (!r->req.io_canceled) {
scsi_req_unref(&r->req);
}
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ if (r->req.io_canceled) {
+ goto done;
+ }
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ if (r->req.io_canceled) {
+ goto done;
+ }
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
+ if (r->req.io_canceled) {
+ goto done;
+ }
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
}
}
- if (r->req.io_canceled) {
- return;
- }
-
/* The request is used as the AIO opaque value, so add a ref. */
scsi_req_ref(&r->req);
r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
+ if (r->req.io_canceled) {
+ goto done;
+ }
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
uint32_t nb_sectors;
r->req.aiocb = NULL;
+ if (r->req.io_canceled) {
+ goto done;
+ }
+
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
}
- if (data->count > 0 && !r->req.io_canceled) {
+ if (data->count > 0) {
sector_num = ldq_be_p(&data->inbuf[0]);
nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
if (!check_lba_range(s, sector_num, nb_sectors)) {
return;
}
+ scsi_req_complete(&r->req, GOOD);
+
done:
- if (data->count == 0) {
- scsi_req_complete(&r->req, GOOD);
- }
if (!r->req.io_canceled) {
scsi_req_unref(&r->req);
}
#include "qemu-common.h"
#include "qemu/error-report.h"
-#include "scsi.h"
+#include "hw/scsi.h"
#include "sysemu/blockdev.h"
#ifdef __linux__
#include <sys/stat.h>
#include <unistd.h>
#include <scsi/sg.h>
-#include "scsi-defs.h"
+#include "hw/scsi-defs.h"
#define SCSI_SENSE_BUF_SIZE 96
#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"
* 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
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
#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
* THE SOFTWARE.
*/
-#include "serial.h"
-#include "isa.h"
+#include "hw/serial.h"
+#include "hw/isa.h"
typedef struct ISASerialState {
ISADevice dev;
/* 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
* THE SOFTWARE.
*/
-#include "serial.h"
+#include "hw/serial.h"
#include "char/char.h"
#include "qemu/timer.h"
#include "exec/address-spaces.h"
#ifndef HW_SERIAL_H
#define HW_SERIAL_H 1
-#include "hw.h"
+#include "hw/hw.h"
#include "sysemu/sysemu.h"
#include "exec/memory.h"
* 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"
#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)
-obj-y = shix.o r2d.o 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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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 <stdio.h>
+#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];
+}
--- /dev/null
+#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 "<unknown reg>";
+}
--- /dev/null
+/*
+ * 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);
+++ /dev/null
-/*
- * 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 <stdio.h>
-#include "hw.h"
-#include "sh.h"
-#include "sysemu/sysemu.h"
-#include "sh7750_regs.h"
-#include "sh7750_regnames.h"
-#include "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];
-}
+++ /dev/null
-#include "hw.h"
-#include "sh.h"
-#include "sh7750_regs.h"
-#include "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 "<unknown reg>";
-}
* 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
#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;
* 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"
* 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"
* 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
+++ /dev/null
-/*
- * 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.h"
-#include "sh.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "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);
* 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
*/
#include "sysemu/sysemu.h"
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "trace.h"
/*
* 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"
/*
*/
#include <stdio.h>
-#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"
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,
+++ /dev/null
-/*
- * SMBIOS Support
- *
- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- *
- * Authors:
- * Alex Williamson <alex.williamson@hp.com>
- *
- * 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 "smbios.h"
-#include "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;
-}
/* 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
* THE SOFTWARE.
*/
-#include "i2c.h"
+#include "hw/i2c.h"
#define TYPE_SMBUS_DEVICE "smbus-device"
#define SMBUS_DEVICE(obj) \
* 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
* 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) \
* 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 <zlib.h>
*/
#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)
{
+++ /dev/null
-/*
- * 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.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 "pci/pci.h"
-
-#include "exec/address-spaces.h"
-#include "hw/usb.h"
-#include "qemu/config-file.h"
-
-#include <libfdt.h>
-
-/* 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_string(fdt, "compatible", "qemu,pseries")));
-
- _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);
+++ /dev/null
-/*
- * 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 <libfdt.h>
-
-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<null> */
-} 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);
-}
+++ /dev/null
-#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_read(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];
- uint8_t *hpte;
- int i, ridx, n_entries = 1;
-
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
- return H_PARAMETER;
- }
-
- if (flags & H_READ_4) {
- /* Clear the two low order bits */
- pte_index &= ~(3ULL);
- n_entries = 4;
- }
-
- hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
-
- for (i = 0, ridx = 0; i < n_entries; i++) {
- args[ridx++] = ldq_p(hpte);
- args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
- hpte += HASH_PTE_SIZE_64;
- }
-
- 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);
- spapr_register_hypercall(H_READ, h_read);
-
- /* 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)
+++ /dev/null
-/*
- * QEMU sPAPR IOMMU (TCE) code
- *
- * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-#include "hw.h"
-#include "sysemu/kvm.h"
-#include "qdev.h"
-#include "kvm_ppc.h"
-#include "sysemu/dma.h"
-#include "exec/address-spaces.h"
-
-#include "hw/spapr.h"
-
-#include <libfdt.h>
-
-/* #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;
-}
* THE SOFTWARE.
*
*/
-#include "hw.h"
+#include "hw/hw.h"
#include "net/net.h"
#include "hw/qdev.h"
#include "hw/spapr.h"
* 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"
+++ /dev/null
-/*
- * 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 <libfdt.h>
-
-#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)
+++ /dev/null
-/*
- * QEMU sPAPR VIO code
- *
- * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
- * Based on the s390 virtio bus code:
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "hw.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "monitor/monitor.h"
-#include "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 <libfdt.h>
-#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 */
* - 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"
-#include "qdev.h"
+#include "hw/qdev.h"
#include "char/char.h"
#include "hw/spapr.h"
#include "hw/spapr_vio.h"
-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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
* 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"
/*
-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
--- /dev/null
+/*
+ * 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);
+++ /dev/null
-/*
- * PXA270-based Clamshell PDA platforms.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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.h"
-#include "pxa.h"
-#include "arm-misc.h"
-#include "sysemu/sysemu.h"
-#include "pcmcia.h"
-#include "i2c.h"
-#include "ssi.h"
-#include "flash.h"
-#include "qemu/timer.h"
-#include "devices.h"
-#include "sharpsl.h"
-#include "ui/console.h"
-#include "block/block.h"
-#include "audio/audio.h"
-#include "boards.h"
-#include "sysemu/blockdev.h"
-#include "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)
/* 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
/* 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
*/
#include "sysemu/blockdev.h"
-#include "ssi.h"
-#include "sd.h"
+#include "hw/ssi.h"
+#include "hw/sd.h"
//#define DEBUG_SSI_SD 1
* GNU GPL, version 2 or (at your option) any later version.
*/
-#include "ssi.h"
+#include "hw/ssi.h"
struct SSIBus {
BusState qbus;
#ifndef QEMU_SSI_H
#define QEMU_SSI_H
-#include "qdev.h"
+#include "hw/qdev.h"
typedef struct SSISlave SSISlave;
+++ /dev/null
-/*
- * Luminary Micro Stellaris peripherals
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "sysbus.h"
-#include "ssi.h"
-#include "arm-misc.h"
-#include "devices.h"
-#include "qemu/timer.h"
-#include "i2c.h"
-#include "net/net.h"
-#include "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)
*
* This code is licensed under the GPL.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "net/net.h"
#include <zlib.h>
*
* 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 {
-#include "stream.h"
+#include "hw/stream.h"
void
stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
* 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
* 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
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "qemu/timer.h"
-#include "sun4m.h"
-#include "nvram.h"
-#include "sparc32_dma.h"
-#include "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 "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);
void sun4m_irq_info(Monitor *mon, const QDict *qdict);
/* sparc32_dma.c */
-#include "sparc32_dma.h"
+#include "hw/sparc32_dma.h"
#endif
* THE SOFTWARE.
*/
-#include "sun4m.h"
-#include "sysbus.h"
+#include "hw/sun4m.h"
+#include "hw/sysbus.h"
#include "trace.h"
/*
+++ /dev/null
-/*
- * 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.h"
-#include "pci/pci.h"
-#include "apb_pci.h"
-#include "pc.h"
-#include "serial.h"
-#include "nvram.h"
-#include "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 "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);
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "monitor/monitor.h"
#include "exec/address-spaces.h"
/* Devices attached directly to the main system bus. */
-#include "qdev.h"
+#include "hw/qdev.h"
#include "exec/memory.h"
#define QDEV_MAX_MMIO 32
-#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
* 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"
}
#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)
{
#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
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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)
#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)
+++ /dev/null
-/* 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 <balrog@zabor.org>
- * 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.h"
-#include "pxa.h"
-#include "arm-misc.h"
-#include "devices.h"
-#include "sharpsl.h"
-#include "pcmcia.h"
-#include "block/block.h"
-#include "boards.h"
-#include "i2c.h"
-#include "ssi.h"
-#include "sysemu/blockdev.h"
-#include "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)
* later version.
*/
-#include "ipack.h"
-#include "pci/pci.h"
+#include "hw/ipack.h"
+#include "hw/pci/pci.h"
#include "qemu/bitops.h"
#include <stdio.h>
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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)))
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
*/
#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;
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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"
# PKUnity-v3 SoC and board information
obj-${CONFIG_PUV3} += puv3.o
-
-obj-y := $(addprefix ../,$(obj-y))
--- /dev/null
+/*
+ * 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)
* 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
* THE SOFTWARE.
*/
-#include "qdev.h"
+#include "hw/qdev.h"
#include "qemu/queue.h"
/* Constants related to the USB / PCI interaction */
#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"
*
*/
-#include "sysbus.h"
-#include "bitbang_i2c.h"
+#include "hw/sysbus.h"
+#include "hw/bitbang_i2c.h"
typedef struct {
SysBusDevice busdev;
* 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 {
+++ /dev/null
-/*
- * ARM Versatile Platform/Application Baseboard System emulation.
- *
- * Copyright (c) 2005-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "sysbus.h"
-#include "arm-misc.h"
-#include "devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "pci/pci.h"
-#include "i2c.h"
-#include "boards.h"
-#include "sysemu/blockdev.h"
-#include "exec/address-spaces.h"
-#include "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)
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- *
- * 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 "arm-misc.h"
-#include "primecell.h"
-#include "devices.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "exec/address-spaces.h"
-#include "sysemu/blockdev.h"
-#include "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);
#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"
* 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"
* 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;
* 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)
* 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
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)
{
*/
#include <sys/ioctl.h>
-#include "vhost.h"
+#include "hw/vhost.h"
#include "hw/hw.h"
#include "qemu/range.h"
#include <linux/vhost.h>
#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"
#include <stdio.h>
-#include "vhost.h"
+#include "hw/vhost.h"
struct vhost_net {
struct vhost_dev dev;
+++ /dev/null
-/*
- * 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 "sysbus.h"
-#include "hw.h"
-#include "serial.h"
-#include "flash.h"
-#include "sysemu/sysemu.h"
-#include "devices.h"
-#include "boards.h"
-#include "sysemu/device_tree.h"
-#include "loader.h"
-#include "elf.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-
-#include "ppc.h"
-#include "ppc4xx.h"
-#include "ppc405.h"
-
-#include "sysemu/blockdev.h"
-#include "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);
#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"
#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 */
#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 <scsi/sg.h>
#endif
#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 */
*
*/
-#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 */
#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) \
#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;
*/
#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
#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
#include <inttypes.h>
-#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 */
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);
.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.
*/
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)
#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 "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;
VirtIOBlkConf blk;
NICConf nic;
uint32_t host_features;
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_VIRTFS
V9fsConf fsconf;
#endif
virtio_serial_conf serial;
};
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. */
*/
#include "qemu/iov.h"
-#include "qdev.h"
-#include "virtio.h"
-#include "virtio-rng.h"
+#include "hw/qdev.h"
+#include "qapi/qmp/qerror.h"
+#include "hw/virtio.h"
+#include "hw/virtio-rng.h"
#include "qemu/rng.h"
typedef struct VirtIORNG {
*
*/
-#include "virtio-scsi.h"
+#include "hw/virtio-scsi.h"
+#include "qemu/error-report.h"
#include <hw/scsi.h>
#include <hw/scsi-defs.h>
#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
#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 {
#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 == */
#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. */
#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_LINUX
-#include "9p.h"
+#ifdef CONFIG_VIRTFS
+#include "hw/9pfs/virtio-9p-device.h"
#endif
/* from Linux's linux/virtio_config.h */
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
* 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
* 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
* 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 */
* 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"
-typedef uint32_t pci_addr_t;
-#include "pci/pci_host.h"
//#define DEBUG_VT82C686B
#ifdef DEBUG_VT82C686B
#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*/
#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*/
* 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
*/
#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))
#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,
*/
#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)
#include <sys/mman.h>
#include <sys/signal.h>
-#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 <xen/grant_table.h>
#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"
#endif
#include <xen/io/xenbus.h>
-#include "hw.h"
-#include "xen.h"
+#include "hw/hw.h"
+#include "hw/xen.h"
#include "qemu/queue.h"
/*
#include <stdarg.h>
#include <sys/mman.h>
-#include "hw.h"
+#include "hw/hw.h"
#include "char/char.h"
-#include "xen_backend.h"
+#include "hw/xen_backend.h"
#include <xen/io/console.h>
-#include "xen_backend.h"
+#include "hw/xen_backend.h"
#include "sysemu/blockdev.h"
/* ------------------------------------------------------------- */
#include <sys/mman.h>
#include <sys/uio.h>
-#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"
/* ------------------------------------------------------------- */
+++ /dev/null
-#include <signal.h>
-#include "xen_backend.h"
-#include "xen_domainbuild.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-
-#include <xenguest.h>
-
-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;
-}
#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);
+++ /dev/null
-/*
- * 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.h"
-#include "pc.h"
-#include "boards.h"
-#include "xen_backend.h"
-#include "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);
#include <sys/mman.h>
#include <sys/wait.h>
-#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 <xen/io/netif.h>
#include <assert.h>
-#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"
#include <sys/ioctl.h>
-#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"
#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);
*/
#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)))
#include <sys/mman.h>
-#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
#include <string.h>
#include <time.h>
-#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 <xen/event_channel.h>
#include <xen/io/fbif.h>
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "char/char.h"
#include "qemu/log.h"
#include "net/net.h"
+++ /dev/null
-/*
- * 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.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;
-}
#define HW_XILINX_H 1
-#include "stream.h"
#include "qemu-common.h"
+#include "qapi/qmp/qerror.h"
+#include "hw/stream.h"
#include "net/net.h"
static inline DeviceState *
* 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)
* 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)
* THE SOFTWARE.
*/
-#include "sysbus.h"
-#include "hw.h"
+#include "hw/sysbus.h"
+#include "hw/hw.h"
#include "net/net.h"
#define D(x)
* THE SOFTWARE.
*/
-#include "sysbus.h"
-#include "hw.h"
+#include "hw/sysbus.h"
+#include "hw/hw.h"
#define D(x)
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
-#include "fifo.h"
+#include "qemu/fifo8.h"
-#include "ssi.h"
+#include "hw/ssi.h"
#ifdef XILINX_SPI_ERR_DEBUG
#define DB_PRINT(...) do { \
* 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 "fifo.h"
-#include "ssi.h"
+#include "qemu/fifo8.h"
+#include "hw/ssi.h"
#include "qemu/bitops.h"
#ifdef XILINX_SPIPS_ERR_DEBUG
* THE SOFTWARE.
*/
-#include "sysbus.h"
-#include "ptimer.h"
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
#include "qemu/log.h"
#define D(x)
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "char/char.h"
#define DUART(x)
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "sysbus.h"
-#include "arm-misc.h"
-#include "net/net.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "boards.h"
-#include "flash.h"
-#include "sysemu/blockdev.h"
-#include "loader.h"
-#include "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);
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
#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,
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
#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,
-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))
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+++ /dev/null
-/*
- * 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 "boards.h"
-#include "loader.h"
-#include "elf.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "serial.h"
-#include "net/net.h"
-#include "sysbus.h"
-#include "flash.h"
-#include "sysemu/blockdev.h"
-#include "char/char.h"
-#include "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);
+++ /dev/null
-/*
- * 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.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;
- }
-}
+++ /dev/null
-/*
- * 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 "boards.h"
-#include "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);
+++ /dev/null
-/*
- * PXA270-based Zipit Z2 device
- *
- * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * 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.h"
-#include "pxa.h"
-#include "arm-misc.h"
-#include "devices.h"
-#include "i2c.h"
-#include "ssi.h"
-#include "boards.h"
-#include "sysemu/sysemu.h"
-#include "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);
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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"
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#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
#ifndef QEMU_VMSTATE_H
#define QEMU_VMSTATE_H 1
+#include <migration/qemu-file.h>
+
typedef void SaveStateHandler(QEMUFile *f, void *opaque);
typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
--- /dev/null
+#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
--- /dev/null
+#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 */
*/
#include <dirent.h>
#include "hw/hw.h"
-#include "hw/qdev.h"
+#include "monitor/qdev.h"
#include "hw/usb.h"
#include "hw/pcmcia.h"
#include "hw/pc.h"
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 : "<null>");
+ 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;
+}
}
#endif /* !_WIN32 */
-#ifndef _WIN32
-
typedef struct IOWatchPoll
{
GSource *src;
return tag;
}
+#ifndef _WIN32
static GIOChannel *io_channel_from_fd(int fd)
{
GIOChannel *chan;
return chan;
}
+#endif
static GIOChannel *io_channel_from_socket(int fd)
{
return len1 - len;
}
+#ifndef _WIN32
+
typedef struct FDCharDriver {
CharDriverState *chr;
GIOChannel *fd_in, *fd_out;
Example
@example
-qemu-system-x86_84 --drive file=gluster://192.0.2.1/testvol/a.img
+qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img
@end example
See also @url{http://www.gluster.org}.
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
--- /dev/null
+#include <monitor/monitor.h>
+#include <sysemu/sysemu.h>
+#include <sysemu/blockdev.h>
+
+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;
+}
qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd);
qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
qtest_add_func("/rtc/set-year/1980", set_year_1980);
- qtest_add_func("/rtc/register_b_set_flag", register_b_set_flag);
- qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
+ qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag);
+ qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers);
ret = g_test_run();
if (s) {
scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
+scsi_req_continue_canceled(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64
scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
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
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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()
+ }
+};
int socket_set_cork(int fd, int v)
{
#if defined(SOL_TCP) && defined(TCP_CORK)
- return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
+ return qemu_setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
#else
return 0;
#endif
int socket_set_nodelay(int fd)
{
int v = 1;
- return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
+ return qemu_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
}
int qemu_madvise(void *addr, size_t len, int advice)
#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"
#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"