diff options
Diffstat (limited to 'hw/ppc')
-rw-r--r-- | hw/ppc/Makefile.objs | 3 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 4 | ||||
-rw-r--r-- | hw/ppc/pnv_core.c | 1 | ||||
-rw-r--r-- | hw/ppc/ppc440.h | 1 | ||||
-rw-r--r-- | hw/ppc/ppc440_uc.c | 222 | ||||
-rw-r--r-- | hw/ppc/sam460ex.c | 32 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 16 | ||||
-rw-r--r-- | hw/ppc/spapr_caps.c | 13 |
8 files changed, 281 insertions, 11 deletions
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 86d82a6ec3..bcab6323b7 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -14,7 +14,8 @@ obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o # PowerPC 4xx boards obj-y += ppc4xx_devs.o ppc405_uc.o obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o -obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o +obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o +obj-$(CONFIG_SAM460EX) += sam460ex.o # PReP obj-$(CONFIG_PREP) += prep.o obj-$(CONFIG_PREP) += prep_systemio.o diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 84355b2672..d11980166f 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -406,11 +406,11 @@ static void ppc_core99_init(MachineState *machine) adb_bus = qdev_get_child_bus(dev, "adb.0"); dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); - qdev_prop_set_bit(dev, "disable-direct-reg3-writes", has_pmu); + qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true); qdev_init_nofail(dev); dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); - qdev_prop_set_bit(dev, "disable-direct-reg3-writes", has_pmu); + qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true); qdev_init_nofail(dev); } diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index a9f129fc2c..9750464bf4 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -150,6 +150,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) if (!chip) { error_propagate(errp, local_err); error_prepend(errp, "required link 'chip' not found: "); + return; } pc->threads = g_new(PowerPCCPU *, cc->nr_threads); diff --git a/hw/ppc/ppc440.h b/hw/ppc/ppc440.h index ad27db12e4..7cef936125 100644 --- a/hw/ppc/ppc440.h +++ b/hw/ppc/ppc440.h @@ -21,6 +21,7 @@ void ppc440_sdram_init(CPUPPCState *env, int nbanks, hwaddr *ram_bases, hwaddr *ram_sizes, int do_init); void ppc4xx_ahb_init(CPUPPCState *env); +void ppc4xx_dma_init(CPUPPCState *env, int dcr_base); void ppc460ex_pcie_init(CPUPPCState *env); #endif /* PPC440_H */ diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 1ab2235f20..0bbaa6844a 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -13,6 +13,7 @@ #include "qemu-common.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/hw.h" #include "exec/address-spaces.h" @@ -803,6 +804,227 @@ void ppc4xx_ahb_init(CPUPPCState *env) } /*****************************************************************************/ +/* DMA controller */ + +#define DMA0_CR_CE (1 << 31) +#define DMA0_CR_PW (1 << 26 | 1 << 25) +#define DMA0_CR_DAI (1 << 24) +#define DMA0_CR_SAI (1 << 23) +#define DMA0_CR_DEC (1 << 2) + +enum { + DMA0_CR = 0x00, + DMA0_CT, + DMA0_SAH, + DMA0_SAL, + DMA0_DAH, + DMA0_DAL, + DMA0_SGH, + DMA0_SGL, + + DMA0_SR = 0x20, + DMA0_SGC = 0x23, + DMA0_SLP = 0x25, + DMA0_POL = 0x26, +}; + +typedef struct { + uint32_t cr; + uint32_t ct; + uint64_t sa; + uint64_t da; + uint64_t sg; +} PPC4xxDmaChnl; + +typedef struct { + int base; + PPC4xxDmaChnl ch[4]; + uint32_t sr; +} PPC4xxDmaState; + +static uint32_t dcr_read_dma(void *opaque, int dcrn) +{ + PPC4xxDmaState *dma = opaque; + uint32_t val = 0; + int addr = dcrn - dma->base; + int chnl = addr / 8; + + switch (addr) { + case 0x00 ... 0x1f: + switch (addr % 8) { + case DMA0_CR: + val = dma->ch[chnl].cr; + break; + case DMA0_CT: + val = dma->ch[chnl].ct; + break; + case DMA0_SAH: + val = dma->ch[chnl].sa >> 32; + break; + case DMA0_SAL: + val = dma->ch[chnl].sa; + break; + case DMA0_DAH: + val = dma->ch[chnl].da >> 32; + break; + case DMA0_DAL: + val = dma->ch[chnl].da; + break; + case DMA0_SGH: + val = dma->ch[chnl].sg >> 32; + break; + case DMA0_SGL: + val = dma->ch[chnl].sg; + break; + } + break; + case DMA0_SR: + val = dma->sr; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n", + __func__, dcrn, chnl, addr); + } + + return val; +} + +static void dcr_write_dma(void *opaque, int dcrn, uint32_t val) +{ + PPC4xxDmaState *dma = opaque; + int addr = dcrn - dma->base; + int chnl = addr / 8; + + switch (addr) { + case 0x00 ... 0x1f: + switch (addr % 8) { + case DMA0_CR: + dma->ch[chnl].cr = val; + if (val & DMA0_CR_CE) { + int count = dma->ch[chnl].ct & 0xffff; + + if (count) { + int width, i, sidx, didx; + uint8_t *rptr, *wptr; + hwaddr rlen, wlen; + + sidx = didx = 0; + width = 1 << ((val & DMA0_CR_PW) >> 25); + rptr = cpu_physical_memory_map(dma->ch[chnl].sa, &rlen, 0); + wptr = cpu_physical_memory_map(dma->ch[chnl].da, &wlen, 1); + if (rptr && wptr) { + if (!(val & DMA0_CR_DEC) && + val & DMA0_CR_SAI && val & DMA0_CR_DAI) { + /* optimise common case */ + memmove(wptr, rptr, count * width); + sidx = didx = count * width; + } else { + /* do it the slow way */ + for (sidx = didx = i = 0; i < count; i++) { + uint64_t v = ldn_le_p(rptr + sidx, width); + stn_le_p(wptr + didx, width, v); + if (val & DMA0_CR_SAI) { + sidx += width; + } + if (val & DMA0_CR_DAI) { + didx += width; + } + } + } + } + if (wptr) { + cpu_physical_memory_unmap(wptr, wlen, 1, didx); + } + if (wptr) { + cpu_physical_memory_unmap(rptr, rlen, 0, sidx); + } + } + } + break; + case DMA0_CT: + dma->ch[chnl].ct = val; + break; + case DMA0_SAH: + dma->ch[chnl].sa &= 0xffffffffULL; + dma->ch[chnl].sa |= (uint64_t)val << 32; + break; + case DMA0_SAL: + dma->ch[chnl].sa &= 0xffffffff00000000ULL; + dma->ch[chnl].sa |= val; + break; + case DMA0_DAH: + dma->ch[chnl].da &= 0xffffffffULL; + dma->ch[chnl].da |= (uint64_t)val << 32; + break; + case DMA0_DAL: + dma->ch[chnl].da &= 0xffffffff00000000ULL; + dma->ch[chnl].da |= val; + break; + case DMA0_SGH: + dma->ch[chnl].sg &= 0xffffffffULL; + dma->ch[chnl].sg |= (uint64_t)val << 32; + break; + case DMA0_SGL: + dma->ch[chnl].sg &= 0xffffffff00000000ULL; + dma->ch[chnl].sg |= val; + break; + } + break; + case DMA0_SR: + dma->sr &= ~val; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n", + __func__, dcrn, chnl, addr); + } +} + +static void ppc4xx_dma_reset(void *opaque) +{ + PPC4xxDmaState *dma = opaque; + int dma_base = dma->base; + + memset(dma, 0, sizeof(*dma)); + dma->base = dma_base; +} + +void ppc4xx_dma_init(CPUPPCState *env, int dcr_base) +{ + PPC4xxDmaState *dma; + int i; + + dma = g_malloc0(sizeof(*dma)); + dma->base = dcr_base; + qemu_register_reset(&ppc4xx_dma_reset, dma); + for (i = 0; i < 4; i++) { + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CR, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CT, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAH, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAL, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAH, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAL, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGH, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGL, + dma, &dcr_read_dma, &dcr_write_dma); + } + ppc_dcr_register(env, dcr_base + DMA0_SR, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + DMA0_SGC, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + DMA0_SLP, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + DMA0_POL, + dma, &dcr_read_dma, &dcr_write_dma); +} + +/*****************************************************************************/ /* PCI Express controller */ /* FIXME: This is not complete and does not work, only implemented partially * to allow firmware and guests to find an empty bus. Cards should use PCI. diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index c7c799b843..7eed2ec601 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -37,6 +37,8 @@ #include "hw/i2c/smbus.h" #include "hw/usb/hcd-ehci.h" +#include <libfdt.h> + #define BINARY_DEVICE_TREE_FILE "canyonlands.dtb" #define UBOOT_FILENAME "u-boot-sam460-20100605.bin" /* to extract the official U-Boot bin from the updater: */ @@ -67,6 +69,10 @@ */ #define CPU_FREQ 1150000000 +#define PLB_FREQ 230000000 +#define OPB_FREQ 115000000 +#define EBC_FREQ 115000000 +#define UART_FREQ 11059200 #define SDRAM_NR_BANKS 4 /* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */ @@ -255,6 +261,7 @@ static int sam460ex_load_device_tree(hwaddr addr, void *fdt; uint32_t tb_freq = CPU_FREQ; uint32_t clock_freq = CPU_FREQ; + int offset; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -308,6 +315,27 @@ static int sam460ex_load_device_tree(hwaddr addr, qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency", tb_freq); + /* Remove cpm node if it exists (it is not emulated) */ + offset = fdt_path_offset(fdt, "/cpm"); + if (offset >= 0) { + fdt_nop_node(fdt, offset); + } + + /* set serial port clocks */ + offset = fdt_node_offset_by_compatible(fdt, -1, "ns16550"); + while (offset >= 0) { + fdt_setprop_cell(fdt, offset, "clock-frequency", UART_FREQ); + offset = fdt_node_offset_by_compatible(fdt, offset, "ns16550"); + } + + /* some more clocks */ + qemu_fdt_setprop_cell(fdt, "/plb", "clock-frequency", + PLB_FREQ); + qemu_fdt_setprop_cell(fdt, "/plb/opb", "clock-frequency", + OPB_FREQ); + qemu_fdt_setprop_cell(fdt, "/plb/opb/ebc", "clock-frequency", + EBC_FREQ); + rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); g_free(fdt); ret = fdt_size; @@ -457,6 +485,7 @@ static void sam460ex_init(MachineState *machine) object_property_set_bool(OBJECT(dev), true, "realized", NULL); smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size); g_free(smbus_eeprom_buf); + i2c_create_slave(i2c[0]->bus, "m41t80", 0x68); dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]); i2c[1] = PPC4xx_I2C(dev); @@ -476,6 +505,9 @@ static void sam460ex_init(MachineState *machine) /* MAL */ ppc4xx_mal_init(env, 4, 16, &uic[2][3]); + /* DMA */ + ppc4xx_dma_init(env, 0x200); + /* 256K of L2 cache as memory */ ppc4xx_l2sram_init(env); /* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */ diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1602472165..3f5e1d3ec2 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -137,7 +137,7 @@ static ICSState *spapr_ics_create(sPAPRMachineState *spapr, goto error; } - return ICS_SIMPLE(obj); + return ICS_BASE(obj); error: error_propagate(errp, local_err); @@ -3962,6 +3962,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->no_parallel = 1; mc->default_boot_order = ""; mc->default_ram_size = 512 * MiB; + mc->default_display = "std"; mc->kvm_type = spapr_kvm_type; machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE); mc->pci_allow_0_address = true; @@ -4095,17 +4096,16 @@ static void spapr_machine_2_12_instance_options(MachineState *machine) static void spapr_machine_2_12_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); - uint8_t mps; spapr_machine_3_0_class_options(mc); SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_12); - if (kvmppc_hpt_needs_host_contiguous_pages()) { - mps = ctz64(qemu_getrampagesize()); - } else { - mps = 34; /* allow everything up to 16GiB, i.e. everything */ - } - smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = mps; + /* We depend on kvm_enabled() to choose a default value for the + * hpt-max-page-size capability. Of course we can't do it here + * because this is too early and the HW accelerator isn't initialzed + * yet. Postpone this to machine init (see default_caps_with_cpu()). + */ + smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0; } DEFINE_SPAPR_MACHINE(2_12, "2.12", false); diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 62663ebdf5..aa605cea91 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -465,6 +465,19 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; } + /* This is for pseries-2.12 and older */ + if (smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] == 0) { + uint8_t mps; + + if (kvmppc_hpt_needs_host_contiguous_pages()) { + mps = ctz64(qemu_getrampagesize()); + } else { + mps = 34; /* allow everything up to 16GiB, i.e. everything */ + } + + caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = mps; + } + return caps; } |