15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * System (CPU) Bus device support code 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2009 CodeSourcery 55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This library is free software; you can redistribute it and/or 75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * modify it under the terms of the GNU Lesser General Public 85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * License as published by the Free Software Foundation; either 95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * version 2 of the License, or (at your option) any later version. 105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This library is distributed in the hope that it will be useful, 125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Lesser General Public License for more details. 155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * You should have received a copy of the GNU Lesser General Public 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * License along with this library; if not, write to the Free Software 185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA 195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sysbus.h" 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sysemu.h" 235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "monitor.h" 245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(n >= 0 && n < dev->num_irq); 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->irqs[n] = 0; 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (dev->irqp[n]) { 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *dev->irqp[n] = irq; 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr) 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(n >= 0 && n < dev->num_mmio); 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (dev->mmio[n].addr == addr) { 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ??? region already mapped here. */ 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (dev->mmio[n].addr != (target_phys_addr_t)-1) { 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Unregister previous mapping. */ 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size, 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner IO_MEM_UNASSIGNED); 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].addr = addr; 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (dev->mmio[n].cb) { 495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].cb(dev, addr); 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cpu_register_physical_memory(addr, dev->mmio[n].size, 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].iofunc); 535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Request an IRQ source. The actual IRQ object may be populated later. */ 585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_init_irq(SysBusDevice *dev, qemu_irq *p) 595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int n; 615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(dev->num_irq < QDEV_MAX_IRQ); 635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner n = dev->num_irq++; 645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->irqp[n] = p; 655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Pass IRQs from a target device. */ 685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target) 695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(dev->num_irq == 0); 725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->num_irq = target->num_irq; 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < dev->num_irq; i++) { 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->irqp[i] = target->irqp[i]; 755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc) 795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int n; 815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(dev->num_mmio < QDEV_MAX_MMIO); 835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner n = dev->num_mmio++; 845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].addr = -1; 855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].size = size; 865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].iofunc = iofunc; 875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size, 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner mmio_mapfunc cb) 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int n; 935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(dev->num_mmio < QDEV_MAX_MMIO); 955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner n = dev->num_mmio++; 965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].addr = -1; 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].size = size; 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev->mmio[n].cb = cb; 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void sysbus_device_init(DeviceState *dev, DeviceInfo *base) 1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev); 1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->init(sysbus_from_qdev(dev)); 1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_register_withprop(SysBusDeviceInfo *info) 1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.init = sysbus_device_init; 1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.bus_type = BUS_TYPE_SYSTEM; 1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(info->qdev.size >= sizeof(SysBusDevice)); 1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_register(&info->qdev); 1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_register_dev(const char *name, size_t size, sysbus_initfn init) 1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SysBusDeviceInfo *info; 1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info = qemu_mallocz(sizeof(*info)); 1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.name = qemu_strdup(name); 1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.size = size; 1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->init = init; 1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sysbus_register_withprop(info); 1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerDeviceState *sysbus_create_varargs(const char *name, 1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner target_phys_addr_t addr, ...) 1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DeviceState *dev; 1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SysBusDevice *s; 1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner va_list va; 1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_irq irq; 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int n; 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev = qdev_create(NULL, name); 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s = sysbus_from_qdev(dev); 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_init(dev); 1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (addr != (target_phys_addr_t)-1) { 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sysbus_mmio_map(s, 0, addr); 1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner va_start(va, addr); 1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner n = 0; 1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (1) { 1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner irq = va_arg(va, qemu_irq); 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!irq) { 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sysbus_connect_irq(s, n, irq); 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner n++; 1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return dev; 1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SysBusDevice *s = sysbus_from_qdev(dev); 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < s->num_mmio; i++) { 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner indent, "", s->mmio[i].addr, s->mmio[i].size); 1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 166