From patchwork Fri Jul 17 06:02:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669019 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5149F13B6 for ; Fri, 17 Jul 2020 06:04:15 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1754C2070A for ; Fri, 17 Jul 2020 06:04:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="FQPlVAkL" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1754C2070A Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:34538 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJTi-00050K-CM for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:04:14 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59966) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3ID8RXwsKCuEKVNLQQHPRHQJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--hskinnemoen.bounces.google.com>) id 1jwJSn-0003Gu-5Y for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:17 -0400 Received: from mail-qt1-x849.google.com ([2607:f8b0:4864:20::849]:36687) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3ID8RXwsKCuEKVNLQQHPRHQJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--hskinnemoen.bounces.google.com>) id 1jwJSl-0005CV-1K for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:16 -0400 Received: by mail-qt1-x849.google.com with SMTP id i5so5568963qtw.3 for ; Thu, 16 Jul 2020 23:03:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=jUCvYQNlXFy8r9SiooY+XwLf5P/ugf5WTHNCr6H/Now=; b=FQPlVAkLgnJ5jWtbrm6fTSvy8qGN1ryb6GI5NEni0Xu47yQt7qAyVtz7WH7mprrbBO ikoxlPWcahRSI+TwETiCWwoJT3sD5ZmK9q/UNxxnkbGAU2iebOK4LErAZcIPNiZ4ason O7vcpuw/MzxlGQoXO80kzmQZyt0vl3YFha6UabYy5o5z7E14WlT1zfIoVXhJy76iBjP5 tu9FYV40Ydcv4/Jw/3a+eB6Z3kd0RRAWwlNdhHgnvwIegLhc6kgFsLHuUAzkmB+tRpOI v4W3zCDeLkcLvmLOuAPJv6xMB22g5VvfMYJcOfXPrld6yQmU8TIc4FeblBl6PTlDFH0T STyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=jUCvYQNlXFy8r9SiooY+XwLf5P/ugf5WTHNCr6H/Now=; b=LaT/sTMayKFgesI//WT/wc/kcyxvE5UtK9tBBcG0+iaYF+tzDlny/+NCQ8BciXpWX3 xiwpEv5Q9Wd0aIKsJuObfxsPS3g+fK4rB1hF4WMdwiT888GvMThb5EheEIzgnCx7/6eA VWry7bUhESn1AdK/UVXTtW9cm5YhkEK6kD8u4NaFtvkE7dzxyVpQR0frTACezZUNAwop /YZkWrRWcsEG05iQVWXKCwnOMBYrh6aWh6VGEZW7v/7av110AeNJJKF7/Ws3eAJkCd0m HW3KuthnSlK5N5OkNs9/hrLSVwJx2Y+NidnigAfmk92K92Zrdl4nQsn4dkr+fSDkuIRp tOCg== X-Gm-Message-State: AOAM530xSxfcxH+tJ+U0AP6sQFzRt2ueqlly2MQAR5ytXBGJD388qT3h 44dlvLca1j7zAf47VIp1zM+we4MX4EBxhIb96npahaHOQW/kpcBQyVg4RnJBR6VkEh0ecSMnA9e chOt3UKxiKrLvpPo/rfwGz8OxEfAfq7xjkfJH/hirwBXtsL2Cth9Up8bbesgTYmPOd6KLzwf35w == X-Google-Smtp-Source: ABdhPJwCVf4Asdx/lr/KrbQfr/G02ETrMOw0vtF/bJpnk6dx6ZliRK4daSWDLsVijahN2Ytx/R56DxlD9Eyd29biHQ== X-Received: by 2002:a0c:a221:: with SMTP id f30mr7473652qva.115.1594965792225; Thu, 16 Jul 2020 23:03:12 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:46 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-2-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 01/13] hw/misc: Add NPCM7xx System Global Control Registers device model From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , Joel Stanley , " =?utf-8?q?C=C3=A9dric_Le_Goater?= " , " =?utf-8?q?Philippe?= =?utf-8?q?_Mathieu-Daud=C3=A9?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::849; envelope-from=3ID8RXwsKCuEKVNLQQHPRHQJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--hskinnemoen.bounces.google.com; helo=mail-qt1-x849.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Implement a device model for the System Global Control Registers in the NPCM730 and NPCM750 BMC SoCs. This is primarily used to enable SMP boot (the boot ROM spins reading the SCRPAD register) and DDR memory initialization; other registers are best effort for now. The reset values of the MDLR and PWRON registers are determined by the SoC variant (730 vs 750) and board straps respectively. Reviewed-by: Joel Stanley Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Havard Skinnemoen --- include/hw/misc/npcm7xx_gcr.h | 76 ++++++++++++ hw/misc/npcm7xx_gcr.c | 227 ++++++++++++++++++++++++++++++++++ MAINTAINERS | 8 ++ hw/arm/Kconfig | 3 + hw/misc/Makefile.objs | 1 + hw/misc/trace-events | 4 + 6 files changed, 319 insertions(+) create mode 100644 include/hw/misc/npcm7xx_gcr.h create mode 100644 hw/misc/npcm7xx_gcr.c diff --git a/include/hw/misc/npcm7xx_gcr.h b/include/hw/misc/npcm7xx_gcr.h new file mode 100644 index 0000000000..4884676be2 --- /dev/null +++ b/include/hw/misc/npcm7xx_gcr.h @@ -0,0 +1,76 @@ +/* + * Nuvoton NPCM7xx System Global Control Registers. + * + * Copyright 2020 Google LLC + * + * 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. + */ +#ifndef NPCM7XX_GCR_H +#define NPCM7XX_GCR_H + +#include "exec/memory.h" +#include "hw/sysbus.h" + +enum NPCM7xxGCRRegisters { + NPCM7XX_GCR_PDID, + NPCM7XX_GCR_PWRON, + NPCM7XX_GCR_MFSEL1 = 0x0c / sizeof(uint32_t), + NPCM7XX_GCR_MFSEL2, + NPCM7XX_GCR_MISCPE, + NPCM7XX_GCR_SPSWC = 0x038 / sizeof(uint32_t), + NPCM7XX_GCR_INTCR, + NPCM7XX_GCR_INTSR, + NPCM7XX_GCR_HIFCR = 0x050 / sizeof(uint32_t), + NPCM7XX_GCR_INTCR2 = 0x060 / sizeof(uint32_t), + NPCM7XX_GCR_MFSEL3, + NPCM7XX_GCR_SRCNT, + NPCM7XX_GCR_RESSR, + NPCM7XX_GCR_RLOCKR1, + NPCM7XX_GCR_FLOCKR1, + NPCM7XX_GCR_DSCNT, + NPCM7XX_GCR_MDLR, + NPCM7XX_GCR_SCRPAD3, + NPCM7XX_GCR_SCRPAD2, + NPCM7XX_GCR_DAVCLVLR = 0x098 / sizeof(uint32_t), + NPCM7XX_GCR_INTCR3, + NPCM7XX_GCR_VSINTR = 0x0ac / sizeof(uint32_t), + NPCM7XX_GCR_MFSEL4, + NPCM7XX_GCR_CPBPNTR = 0x0c4 / sizeof(uint32_t), + NPCM7XX_GCR_CPCTL = 0x0d0 / sizeof(uint32_t), + NPCM7XX_GCR_CP2BST, + NPCM7XX_GCR_B2CPNT, + NPCM7XX_GCR_CPPCTL, + NPCM7XX_GCR_I2CSEGSEL, + NPCM7XX_GCR_I2CSEGCTL, + NPCM7XX_GCR_VSRCR, + NPCM7XX_GCR_MLOCKR, + NPCM7XX_GCR_SCRPAD = 0x013c / sizeof(uint32_t), + NPCM7XX_GCR_USB1PHYCTL, + NPCM7XX_GCR_USB2PHYCTL, + NPCM7XX_GCR_NR_REGS, +}; + +typedef struct NPCM7xxGCRState { + SysBusDevice parent; + + MemoryRegion iomem; + + uint32_t regs[NPCM7XX_GCR_NR_REGS]; + + uint32_t reset_pwron; + uint32_t reset_mdlr; + uint32_t reset_intcr3; +} NPCM7xxGCRState; + +#define TYPE_NPCM7XX_GCR "npcm7xx-gcr" +#define NPCM7XX_GCR(obj) OBJECT_CHECK(NPCM7xxGCRState, (obj), TYPE_NPCM7XX_GCR) + +#endif /* NPCM7XX_GCR_H */ diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c new file mode 100644 index 0000000000..dc08d2ebcc --- /dev/null +++ b/hw/misc/npcm7xx_gcr.c @@ -0,0 +1,227 @@ +/* + * Nuvoton NPCM7xx System Global Control Registers. + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/misc/npcm7xx_gcr.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" + +#include "trace.h" + +#define NPCM7XX_GCR_MIN_DRAM_SIZE (128 * MiB) +#define NPCM7XX_GCR_MAX_DRAM_SIZE (2 * GiB) + +static const uint32_t cold_reset_values[NPCM7XX_GCR_NR_REGS] = { + [NPCM7XX_GCR_PDID] = 0x04a92750, /* Poleg A1 */ + [NPCM7XX_GCR_MISCPE] = 0x0000ffff, + [NPCM7XX_GCR_SPSWC] = 0x00000003, + [NPCM7XX_GCR_INTCR] = 0x0000035e, + [NPCM7XX_GCR_HIFCR] = 0x0000004e, + [NPCM7XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */ + [NPCM7XX_GCR_RESSR] = 0x80000000, + [NPCM7XX_GCR_DSCNT] = 0x000000c0, + [NPCM7XX_GCR_DAVCLVLR] = 0x5a00f3cf, + [NPCM7XX_GCR_SCRPAD] = 0x00000008, + [NPCM7XX_GCR_USB1PHYCTL] = 0x034730e4, + [NPCM7XX_GCR_USB2PHYCTL] = 0x034730e4, +}; + +static uint64_t npcm7xx_gcr_read(void *opaque, hwaddr offset, unsigned size) +{ + uint32_t reg = offset / sizeof(uint32_t); + NPCM7xxGCRState *s = opaque; + + if (reg >= NPCM7XX_GCR_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: offset 0x%04" HWADDR_PRIx " out of range\n", + __func__, offset); + return 0; + } + + trace_npcm7xx_gcr_read(offset, s->regs[reg]); + + return s->regs[reg]; +} + +static void npcm7xx_gcr_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ + uint32_t reg = offset / sizeof(uint32_t); + NPCM7xxGCRState *s = opaque; + uint32_t value = v; + + trace_npcm7xx_gcr_write(offset, value); + + if (reg >= NPCM7XX_GCR_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: offset 0x%04" HWADDR_PRIx " out of range\n", + __func__, offset); + return; + } + + switch (reg) { + case NPCM7XX_GCR_PDID: + case NPCM7XX_GCR_PWRON: + case NPCM7XX_GCR_INTSR: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n", + __func__, offset); + return; + + case NPCM7XX_GCR_RESSR: + case NPCM7XX_GCR_CP2BST: + /* Write 1 to clear */ + value = s->regs[reg] & ~value; + break; + + case NPCM7XX_GCR_RLOCKR1: + case NPCM7XX_GCR_MDLR: + /* Write 1 to set */ + value |= s->regs[reg]; + break; + }; + + s->regs[reg] = value; +} + +static const struct MemoryRegionOps npcm7xx_gcr_ops = { + .read = npcm7xx_gcr_read, + .write = npcm7xx_gcr_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type) +{ + NPCM7xxGCRState *s = NPCM7XX_GCR(obj); + + QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values)); + + switch (type) { + case RESET_TYPE_COLD: + memcpy(s->regs, cold_reset_values, sizeof(s->regs)); + s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron; + s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr; + s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3; + break; + } +} + +static void npcm7xx_gcr_realize(DeviceState *dev, Error **errp) +{ + ERRP_GUARD(); + NPCM7xxGCRState *s = NPCM7XX_GCR(dev); + uint64_t dram_size; + Object *obj; + + obj = object_property_get_link(OBJECT(dev), "dram-mr", errp); + if (!obj) { + error_prepend(errp, "%s: required dram-mr link not found: ", __func__); + return; + } + dram_size = memory_region_size(MEMORY_REGION(obj)); + if (!is_power_of_2(dram_size) || + dram_size < NPCM7XX_GCR_MIN_DRAM_SIZE || + dram_size > NPCM7XX_GCR_MAX_DRAM_SIZE) { + error_setg(errp, "%s: unsupported DRAM size %" PRIu64, + __func__, dram_size); + error_append_hint(errp, + "DRAM size must be a power of two between %" PRIu64 + " and %" PRIu64 " MiB, inclusive.\n", + NPCM7XX_GCR_MIN_DRAM_SIZE / MiB, + NPCM7XX_GCR_MAX_DRAM_SIZE / MiB); + return; + } + + /* Power-on reset value */ + s->reset_intcr3 = 0x00001002; + + /* + * The GMMAP (Graphics Memory Map) field is used by u-boot to detect the + * DRAM size, and is normally initialized by the boot block as part of DRAM + * training. However, since we don't have a complete emulation of the + * memory controller and try to make it look like it has already been + * initialized, the boot block will skip this initialization, and we need + * to make sure this field is set correctly up front. + * + * WARNING: some versions of u-boot only looks at bits 8 and 9, so 2 GiB of + * DRAM will be interpreted as 128 MiB. + * + * https://github.com/Nuvoton-Israel/u-boot/blob/2aef993bd2aafeb5408dbaad0f3ce099ee40c4aa/board/nuvoton/poleg/poleg.c#L244 + */ + s->reset_intcr3 |= ctz64(dram_size / NPCM7XX_GCR_MIN_DRAM_SIZE) << 8; +} + +static void npcm7xx_gcr_init(Object *obj) +{ + NPCM7xxGCRState *s = NPCM7XX_GCR(obj); + + memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s, + TYPE_NPCM7XX_GCR, 4 * KiB); + sysbus_init_mmio(&s->parent, &s->iomem); +} + +static const VMStateDescription vmstate_npcm7xx_gcr = { + .name = "npcm7xx-gcr", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, NPCM7xxGCRState, NPCM7XX_GCR_NR_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + +static Property npcm7xx_gcr_properties[] = { + DEFINE_PROP_UINT32("disabled-modules", NPCM7xxGCRState, reset_mdlr, 0), + DEFINE_PROP_UINT32("power-on-straps", NPCM7xxGCRState, reset_pwron, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "NPCM7xx System Global Control Registers"; + dc->realize = npcm7xx_gcr_realize; + dc->vmsd = &vmstate_npcm7xx_gcr; + rc->phases.enter = npcm7xx_gcr_enter_reset; + + device_class_set_props(dc, npcm7xx_gcr_properties); +} + +static const TypeInfo npcm7xx_gcr_info = { + .name = TYPE_NPCM7XX_GCR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCM7xxGCRState), + .instance_init = npcm7xx_gcr_init, + .class_init = npcm7xx_gcr_class_init, +}; + +static void npcm7xx_gcr_register_type(void) +{ + type_register_static(&npcm7xx_gcr_info); +} +type_init(npcm7xx_gcr_register_type); diff --git a/MAINTAINERS b/MAINTAINERS index 030faf0249..9b468eb6b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -747,6 +747,14 @@ S: Odd Fixes F: hw/arm/musicpal.c F: docs/system/arm/musicpal.rst +Nuvoton NPCM7xx +M: Havard Skinnemoen +M: Tyrone Ting +L: qemu-arm@nongnu.org +S: Supported +F: hw/*/npcm7xx* +F: include/hw/*/npcm7xx* + nSeries M: Andrzej Zaborowski M: Peter Maydell diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 4a224a6351..192a8dec3b 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -354,6 +354,9 @@ config XLNX_VERSAL select VIRTIO_MMIO select UNIMP +config NPCM7XX + bool + config FSL_IMX25 bool select IMX diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 6be3d255ab..e00b839f03 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -51,6 +51,7 @@ common-obj-$(CONFIG_IMX) += imx_rngc.o common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_gcr.o common-obj-$(CONFIG_OMAP) += omap_clk.o common-obj-$(CONFIG_OMAP) += omap_gpmc.o common-obj-$(CONFIG_OMAP) += omap_l4.o diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 066752aa90..dbf90db8ed 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -111,6 +111,10 @@ mos6522_set_sr_int(void) "set sr_int" mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" +# npcm7xx_gcr.c +npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 +npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 + # stm32f4xx_syscfg stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d" stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d" From patchwork Fri Jul 17 06:02:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669025 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 33CF713B6 for ; Fri, 17 Jul 2020 06:06:29 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EAA7A2070A for ; Fri, 17 Jul 2020 06:06:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="LJNtfeAi" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EAA7A2070A Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:42712 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJVs-0008RD-4U for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:06:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60004) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3Ij8RXwsKCuMMXPNSSJRTJSLTTLQJ.HTRVJRZ-IJaJQSTSLSZ.TWL@flex--hskinnemoen.bounces.google.com>) id 1jwJSo-0003KE-Sr for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:18 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:43597) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3Ij8RXwsKCuMMXPNSSJRTJSLTTLQJ.HTRVJRZ-IJaJQSTSLSZ.TWL@flex--hskinnemoen.bounces.google.com>) id 1jwJSm-0005Dt-OR for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:18 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id x184so10152151ybx.10 for ; Thu, 16 Jul 2020 23:03:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=Q2iAvXL1jLs7q/iNFlIw4+s2o/tK8vDj+qwa76R5kuI=; b=LJNtfeAib9Kl74U7GvYKGQFZbAHA4L1VwGIl/Y1x1tlgKHHDF65o1QZg0Z4aZLKIk1 v0cwNPKq1dw5vC4R+Qs2qCEQvvlTtIiNlY1O8PLQfSjSNJI5KXeMwv6kTPr6Rry0QCLB jJCDabruALBqoojHz0z25pC+49F6t/XGAuNO1KwoPrvHjmq14XGUCCfmeU3M8sA12i3L FsUiaXsIXTK4OYJbdj++gMMFDpZD/H9yXrHPKm8x9UpCEd/YwuNtr4sDOp2cYdY4vv0r Va0aK61xKFg0+8vJTj/K+wSmbWdbB/JgcwCEJzWnCH2j5r4hsNlnGd7PvFoM8Y5YeEnz EfFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=Q2iAvXL1jLs7q/iNFlIw4+s2o/tK8vDj+qwa76R5kuI=; b=gupOA0c8U3wZQTv6FLL8bPx95zlOv0yIbrDOvU0CVudA7a1Y/aOKGOLzbqF6S8ZUYQ KHcKpWIW42uhv31OoR8PFOrLI/5qmQtBWfdrQ+czhFiMJiGQ7S2jCh42o+Ok+dP5+gwV A4KlSIPCo5Lii2pdnFI7hpj2/fjTfhRFID421jGtZa2xpdTb/+eutHRdef+LzFXDq07o C6mgZKglO4uJ7GcHs8r9mwzL7u0iF9lKzra1WzqXfxi8QHPxxDmlX6KeiOeMy22WCG+s 8i/AjR6Mj1EGJH7uvsmUHl9Z5aqoJbmiQP85hJYMg7jiLctpeAzwfsvqBzdViTGTi7sh Tjxg== X-Gm-Message-State: AOAM530ZewaMTqQnl/iBmfRRYk2axnhkpXS8XDsbHJHiuNLh/r5FHFvG JLjXltcw/jvSSQvmNRhtidBATg3+BAYODwQWHw47v+RdDzuRVKjYahyl4++IziF350PWRU7C4B9 GcaCBiYN502TMXCWKZyckSJ1/DOyOeckPSp4VTzej3Csg9lj/6kp/Zxn2bu882NjN95T5O7FF0w == X-Google-Smtp-Source: ABdhPJy8Eij22jrHSzzqRYrhuDVE6pYKTrzWcwwdA2kngvI682yG/qx8iRr05TsLf6L+LoSJjBGC3l+YV0AsJvVrWQ== X-Received: by 2002:a25:cc4e:: with SMTP id l75mr11177298ybf.377.1594965794879; Thu, 16 Jul 2020 23:03:14 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:47 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-3-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 02/13] hw/misc: Add NPCM7xx Clock Controller device model From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , Joel Stanley , " =?utf-8?q?C=C3=A9dric_Le_Goater?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3Ij8RXwsKCuMMXPNSSJRTJSLTTLQJ.HTRVJRZ-IJaJQSTSLSZ.TWL@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Enough functionality to boot the Linux kernel has been implemented. This includes: - Correct power-on reset values so the various clock rates can be accurately calculated. - Clock enables stick around when written. In addition, a best effort attempt to implement SECCNT and CNTR25M was made even though I don't think the kernel needs them. Reviewed-by: Tyrone Ting Reviewed-by: Joel Stanley Reviewed-by: Cédric Le Goater Signed-off-by: Havard Skinnemoen --- include/hw/misc/npcm7xx_clk.h | 72 +++++++++++ hw/misc/npcm7xx_clk.c | 234 ++++++++++++++++++++++++++++++++++ hw/misc/Makefile.objs | 1 + hw/misc/trace-events | 4 + 4 files changed, 311 insertions(+) create mode 100644 include/hw/misc/npcm7xx_clk.h create mode 100644 hw/misc/npcm7xx_clk.c diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h new file mode 100644 index 0000000000..40ed64ff15 --- /dev/null +++ b/include/hw/misc/npcm7xx_clk.h @@ -0,0 +1,72 @@ +/* + * Nuvoton NPCM7xx Clock Control Registers. + * + * Copyright 2020 Google LLC + * + * 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. + */ +#ifndef NPCM7XX_CLK_H +#define NPCM7XX_CLK_H + +#include "exec/memory.h" +#include "hw/sysbus.h" + +/* + * The reference clock frequency for the timer modules, and the SECCNT and + * CNTR25M registers in this module, is always 25 MHz. + */ +#define NPCM7XX_TIMER_REF_HZ (25000000) + +enum NPCM7xxCLKRegisters { + NPCM7XX_CLK_CLKEN1, + NPCM7XX_CLK_CLKSEL, + NPCM7XX_CLK_CLKDIV1, + NPCM7XX_CLK_PLLCON0, + NPCM7XX_CLK_PLLCON1, + NPCM7XX_CLK_SWRSTR, + NPCM7XX_CLK_IPSRST1 = 0x20 / sizeof(uint32_t), + NPCM7XX_CLK_IPSRST2, + NPCM7XX_CLK_CLKEN2, + NPCM7XX_CLK_CLKDIV2, + NPCM7XX_CLK_CLKEN3, + NPCM7XX_CLK_IPSRST3, + NPCM7XX_CLK_WD0RCR, + NPCM7XX_CLK_WD1RCR, + NPCM7XX_CLK_WD2RCR, + NPCM7XX_CLK_SWRSTC1, + NPCM7XX_CLK_SWRSTC2, + NPCM7XX_CLK_SWRSTC3, + NPCM7XX_CLK_SWRSTC4, + NPCM7XX_CLK_PLLCON2, + NPCM7XX_CLK_CLKDIV3, + NPCM7XX_CLK_CORSTC, + NPCM7XX_CLK_PLLCONG, + NPCM7XX_CLK_AHBCKFI, + NPCM7XX_CLK_SECCNT, + NPCM7XX_CLK_CNTR25M, + NPCM7XX_CLK_NR_REGS, +}; + +typedef struct NPCM7xxCLKState { + SysBusDevice parent; + + MemoryRegion iomem; + + uint32_t regs[NPCM7XX_CLK_NR_REGS]; + + /* Time reference for SECCNT and CNTR25M, initialized by power on reset */ + int64_t ref_ns; +} NPCM7xxCLKState; + +#define TYPE_NPCM7XX_CLK "npcm7xx-clk" +#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK) + +#endif /* NPCM7XX_CLK_H */ diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c new file mode 100644 index 0000000000..55beecc06f --- /dev/null +++ b/hw/misc/npcm7xx_clk.c @@ -0,0 +1,234 @@ +/* + * Nuvoton NPCM7xx Clock Control Registers. + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/misc/npcm7xx_clk.h" +#include "migration/vmstate.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qemu/units.h" +#include "trace.h" + +#define PLLCON_LOKI BIT(31) +#define PLLCON_LOKS BIT(30) +#define PLLCON_PWDEN BIT(12) + +/* + * These reset values were taken from version 0.91 of the NPCM750R data sheet. + * + * All are loaded on power-up reset. CLKENx and SWRSTR should also be loaded on + * core domain reset, but this reset type is not yet supported by QEMU. + */ +static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = { + [NPCM7XX_CLK_CLKEN1] = 0xffffffff, + [NPCM7XX_CLK_CLKSEL] = 0x004aaaaa, + [NPCM7XX_CLK_CLKDIV1] = 0x5413f855, + [NPCM7XX_CLK_PLLCON0] = 0x00222101 | PLLCON_LOKI, + [NPCM7XX_CLK_PLLCON1] = 0x00202101 | PLLCON_LOKI, + [NPCM7XX_CLK_IPSRST1] = 0x00001000, + [NPCM7XX_CLK_IPSRST2] = 0x80000000, + [NPCM7XX_CLK_CLKEN2] = 0xffffffff, + [NPCM7XX_CLK_CLKDIV2] = 0xaa4f8f9f, + [NPCM7XX_CLK_CLKEN3] = 0xffffffff, + [NPCM7XX_CLK_IPSRST3] = 0x03000000, + [NPCM7XX_CLK_WD0RCR] = 0xffffffff, + [NPCM7XX_CLK_WD1RCR] = 0xffffffff, + [NPCM7XX_CLK_WD2RCR] = 0xffffffff, + [NPCM7XX_CLK_SWRSTC1] = 0x00000003, + [NPCM7XX_CLK_PLLCON2] = 0x00c02105 | PLLCON_LOKI, + [NPCM7XX_CLK_CORSTC] = 0x04000003, + [NPCM7XX_CLK_PLLCONG] = 0x01228606 | PLLCON_LOKI, + [NPCM7XX_CLK_AHBCKFI] = 0x000000c8, +}; + +static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size) +{ + uint32_t reg = offset / sizeof(uint32_t); + NPCM7xxCLKState *s = opaque; + int64_t now_ns; + uint32_t value = 0; + + if (reg >= NPCM7XX_CLK_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: offset 0x%04" HWADDR_PRIx " out of range\n", + __func__, offset); + return 0; + } + + switch (reg) { + case NPCM7XX_CLK_SWRSTR: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: register @ 0x%04" HWADDR_PRIx " is write-only\n", + __func__, offset); + break; + + case NPCM7XX_CLK_SECCNT: + now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + value = (now_ns - s->ref_ns) / NANOSECONDS_PER_SECOND; + break; + + case NPCM7XX_CLK_CNTR25M: + now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + /* + * This register counts 25 MHz cycles, updating every 640 ns. It rolls + * over to zero every second. + * + * The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000. + */ + value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ; + break; + + default: + value = s->regs[reg]; + break; + }; + + trace_npcm7xx_clk_read(offset, value); + + return value; +} + +static void npcm7xx_clk_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ + uint32_t reg = offset / sizeof(uint32_t); + NPCM7xxCLKState *s = opaque; + uint32_t value = v; + + trace_npcm7xx_clk_write(offset, value); + + if (reg >= NPCM7XX_CLK_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: offset 0x%04" HWADDR_PRIx " out of range\n", + __func__, offset); + return; + } + + switch (reg) { + case NPCM7XX_CLK_SWRSTR: + qemu_log_mask(LOG_UNIMP, "%s: SW reset not implemented: 0x%02x\n", + __func__, value); + value = 0; + break; + + case NPCM7XX_CLK_PLLCON0: + case NPCM7XX_CLK_PLLCON1: + case NPCM7XX_CLK_PLLCON2: + case NPCM7XX_CLK_PLLCONG: + if (value & PLLCON_PWDEN) { + /* Power down -- clear lock and indicate loss of lock */ + value &= ~PLLCON_LOKI; + value |= PLLCON_LOKS; + } else { + /* Normal mode -- assume always locked */ + value |= PLLCON_LOKI; + /* Keep LOKS unchanged unless cleared by writing 1 */ + if (value & PLLCON_LOKS) { + value &= ~PLLCON_LOKS; + } else { + value |= (value & PLLCON_LOKS); + } + } + break; + + case NPCM7XX_CLK_CNTR25M: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n", + __func__, offset); + return; + } + + s->regs[reg] = value; +} + +static const struct MemoryRegionOps npcm7xx_clk_ops = { + .read = npcm7xx_clk_read, + .write = npcm7xx_clk_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void npcm7xx_clk_enter_reset(Object *obj, ResetType type) +{ + NPCM7xxCLKState *s = NPCM7XX_CLK(obj); + + QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values)); + + switch (type) { + case RESET_TYPE_COLD: + memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values)); + s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + return; + } + + /* + * A small number of registers need to be reset on a core domain reset, + * but no such reset type exists yet. + */ + qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.", + __func__, type); +} + +static void npcm7xx_clk_init(Object *obj) +{ + NPCM7xxCLKState *s = NPCM7XX_CLK(obj); + + memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s, + TYPE_NPCM7XX_CLK, 4 * KiB); + sysbus_init_mmio(&s->parent, &s->iomem); +} + +static const VMStateDescription vmstate_npcm7xx_clk = { + .name = "npcm7xx-clk", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS), + VMSTATE_INT64(ref_ns, NPCM7xxCLKState), + VMSTATE_END_OF_LIST(), + }, +}; + +static void npcm7xx_clk_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "NPCM7xx Clock Control Registers"; + dc->vmsd = &vmstate_npcm7xx_clk; + rc->phases.enter = npcm7xx_clk_enter_reset; +} + +static const TypeInfo npcm7xx_clk_info = { + .name = TYPE_NPCM7XX_CLK, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCM7xxCLKState), + .instance_init = npcm7xx_clk_init, + .class_init = npcm7xx_clk_class_init, +}; + +static void npcm7xx_clk_register_type(void) +{ + type_register_static(&npcm7xx_clk_info); +} +type_init(npcm7xx_clk_register_type); diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e00b839f03..9a73c1f77f 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -51,6 +51,7 @@ common-obj-$(CONFIG_IMX) += imx_rngc.o common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_clk.o common-obj-$(CONFIG_NPCM7XX) += npcm7xx_gcr.o common-obj-$(CONFIG_OMAP) += omap_clk.o common-obj-$(CONFIG_OMAP) += omap_gpmc.o diff --git a/hw/misc/trace-events b/hw/misc/trace-events index dbf90db8ed..a010699b4f 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -111,6 +111,10 @@ mos6522_set_sr_int(void) "set sr_int" mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" +# npcm7xx_clk.c +npcm7xx_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 +npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 + # npcm7xx_gcr.c npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 From patchwork Fri Jul 17 06:02:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669027 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5AD80138C for ; Fri, 17 Jul 2020 06:06:52 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2109B22B51 for ; Fri, 17 Jul 2020 06:06:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="kAcMuXrp" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2109B22B51 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:44012 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJWF-0000Y0-Am for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:06:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60028) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3JD8RXwsKCuUOZRPUULTVLUNVVNSL.JVTXLTb-KLcLSUVUNUb.VYN@flex--hskinnemoen.bounces.google.com>) id 1jwJSr-0003PS-4o for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:21 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:53281) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3JD8RXwsKCuUOZRPUULTVLUNVVNSL.JVTXLTb-KLcLSUVUNUb.VYN@flex--hskinnemoen.bounces.google.com>) id 1jwJSo-0005EM-F7 for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:20 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id d27so10092010ybe.20 for ; Thu, 16 Jul 2020 23:03:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=H0eIDQzJJdz5R8/ksmV97usqmY+YDzuGYi8npQpmCBE=; b=kAcMuXrpm9kjH74HMbo72enPjU1yBADXnupxrit9iBsAfzgFiyS5RgoVXqhbd09Bzh tO1hnZfPnRHzNhUdiE0DEEJUmDQcwDjckHry6uDmDdG4PEhHgtMVoy13D6wKItkVCCKB +kHOr8HtQXrMOq+VLAeHjRUtJwKq8icow8PHp4l35klBWHiO1xvUIBPSh3H0UCXUftgM Ko/vJDyWMGurNgW5/eHRKQrgBLpnUq4qAN0W70Ks227/JNE/BDBBCxNVWLCzW44RAj/c DRAdMU6M2a94GNFaRCcxFLT+siANqnf1WmYr20h/6TV+ZKudK1XFG7JAcSUUhzqV+Dp8 HadA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=H0eIDQzJJdz5R8/ksmV97usqmY+YDzuGYi8npQpmCBE=; b=njyLYrpxT7GhFmA7N0yKT1m3rF9br1Zz3ZroXlmEckDX5jhbSAbrnNis5RH/D4niZ6 k5qMd8RgwUp0jdW0X4yASpQtX8wjvkWpWIjeHOTQv7MqkuSFG9yVOf5fx3/WqM1XT96X trQW31m454r1SQJnQ+TOeSAiVJL9dGAGTkWUD8WmJsIazxF8mAt+MMF6VpvxVUgBaTJm maMqrrFJJeEJK3TUsK72FHjw65k+i931vYPa+bW+W9ncHlXGJ2l4wT8idv2VDYbV9bqU rImofg6v+t2AFnXhKs7JzPiZVUSQwFUk9V5uUhDE7bD/5e6qnBPD459GFMk0wBSLHSd7 siAw== X-Gm-Message-State: AOAM531TSOHRS0f7ypfR1JyThD33bEXCj5NbNpNXC18+Zwdg9+H42VN6 DoJOaEPW8FCS1NI4+Y4YiYxwD5aJUMW4qXpkNVqdhYlW48M7MKRz4vmztPBlytiUEq7RZn/xJt+ jqHc8faOwD8hlnSfSxIqyjLIUtDb1MbgYwRlz0k2UVUlLaKtdEntDg9wqN7n1AbyKKnCWEzWOhQ == X-Google-Smtp-Source: ABdhPJyLSMdwg7I2sbtd4bJie9Nc7FDNgWVYSRbmPv2BEcsbkX28HcXqaNIVA8FOyavGg6TkKOd3i2e/TD7PZCvxPg== X-Received: by 2002:a25:9c44:: with SMTP id x4mr11616569ybo.510.1594965796970; Thu, 16 Jul 2020 23:03:16 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:48 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-4-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 03/13] hw/timer: Add NPCM7xx Timer device model From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , Joel Stanley Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3JD8RXwsKCuUOZRPUULTVLUNVVNSL.JVTXLTb-KLcLSUVUNUb.VYN@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" The NPCM730 and NPCM750 SoCs have three timer modules each holding five timers and some shared registers (e.g. interrupt status). Each timer runs at 25 MHz divided by a prescaler, and counts down from a configurable initial value to zero. When zero is reached, the interrupt flag for the timer is set, and the timer is disabled (one-shot mode) or reloaded from its initial value (periodic mode). This implementation is sufficient to boot a Linux kernel configured for NPCM750. Note that the kernel does not seem to actually turn on the interrupts. Reviewed-by: Tyrone Ting Reviewed-by: Joel Stanley Signed-off-by: Havard Skinnemoen Reviewed-by: Philippe Mathieu-Daudé --- include/hw/timer/npcm7xx_timer.h | 96 ++++++ hw/timer/npcm7xx_timer.c | 489 +++++++++++++++++++++++++++++++ hw/timer/Makefile.objs | 1 + hw/timer/trace-events | 5 + 4 files changed, 591 insertions(+) create mode 100644 include/hw/timer/npcm7xx_timer.h create mode 100644 hw/timer/npcm7xx_timer.c diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h new file mode 100644 index 0000000000..94900a7877 --- /dev/null +++ b/include/hw/timer/npcm7xx_timer.h @@ -0,0 +1,96 @@ +/* + * Nuvoton NPCM7xx Timer Controller + * + * Copyright 2020 Google LLC + * + * 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. + */ +#ifndef NPCM7XX_TIMER_H +#define NPCM7XX_TIMER_H + +#include "exec/memory.h" +#include "hw/sysbus.h" +#include "qemu/timer.h" + +/* Each Timer Module (TIM) instance holds five 25 MHz timers. */ +#define NPCM7XX_TIMERS_PER_CTRL (5) + +/** + * enum NPCM7xxTimerRegisters - 32-bit register indices. + */ +enum NPCM7xxTimerRegisters { + NPCM7XX_TIMER_TCSR0, + NPCM7XX_TIMER_TCSR1, + NPCM7XX_TIMER_TICR0, + NPCM7XX_TIMER_TICR1, + NPCM7XX_TIMER_TDR0, + NPCM7XX_TIMER_TDR1, + NPCM7XX_TIMER_TISR, + NPCM7XX_TIMER_WTCR, + NPCM7XX_TIMER_TCSR2, + NPCM7XX_TIMER_TCSR3, + NPCM7XX_TIMER_TICR2, + NPCM7XX_TIMER_TICR3, + NPCM7XX_TIMER_TDR2, + NPCM7XX_TIMER_TDR3, + NPCM7XX_TIMER_TCSR4 = 0x0040 / sizeof(uint32_t), + NPCM7XX_TIMER_TICR4 = 0x0048 / sizeof(uint32_t), + NPCM7XX_TIMER_TDR4 = 0x0050 / sizeof(uint32_t), + NPCM7XX_TIMER_NR_REGS, +}; + +typedef struct NPCM7xxTimerCtrlState NPCM7xxTimerCtrlState; + +/** + * struct NPCM7xxTimer - Individual timer state. + * @irq: GIC interrupt line to fire on expiration (if enabled). + * @qtimer: QEMU timer that notifies us on expiration. + * @expires_ns: Absolute virtual expiration time. + * @remaining_ns: Remaining time until expiration if timer is paused. + * @tcsr: The Timer Control and Status Register. + * @ticr: The Timer Initial Count Register. + */ +typedef struct NPCM7xxTimer { + NPCM7xxTimerCtrlState *ctrl; + + qemu_irq irq; + QEMUTimer qtimer; + int64_t expires_ns; + int64_t remaining_ns; + + uint32_t tcsr; + uint32_t ticr; +} NPCM7xxTimer; + +/** + * struct NPCM7xxTimerCtrlState - Timer Module device state. + * @parent: System bus device. + * @iomem: Memory region through which registers are accessed. + * @tisr: The Timer Interrupt Status Register. + * @wtcr: The Watchdog Timer Control Register. + * @timer: The five individual timers managed by this module. + */ +struct NPCM7xxTimerCtrlState { + SysBusDevice parent; + + MemoryRegion iomem; + + uint32_t tisr; + uint32_t wtcr; + + NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL]; +}; + +#define TYPE_NPCM7XX_TIMER "npcm7xx-timer" +#define NPCM7XX_TIMER(obj) \ + OBJECT_CHECK(NPCM7xxTimerCtrlState, (obj), TYPE_NPCM7XX_TIMER) + +#endif /* NPCM7XX_TIMER_H */ diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c new file mode 100644 index 0000000000..9f9a7048f2 --- /dev/null +++ b/hw/timer/npcm7xx_timer.c @@ -0,0 +1,489 @@ +/* + * Nuvoton NPCM7xx Timer Controller + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/irq.h" +#include "hw/misc/npcm7xx_clk.h" +#include "hw/timer/npcm7xx_timer.h" +#include "migration/vmstate.h" +#include "qemu/bitops.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qemu/units.h" +#include "trace.h" + +/* Register field definitions. */ +#define NPCM7XX_TCSR_CEN BIT(30) +#define NPCM7XX_TCSR_IE BIT(29) +#define NPCM7XX_TCSR_PERIODIC BIT(27) +#define NPCM7XX_TCSR_CRST BIT(26) +#define NPCM7XX_TCSR_CACT BIT(25) +#define NPCM7XX_TCSR_RSVD 0x21ffff00 +#define NPCM7XX_TCSR_PRESCALE_START 0 +#define NPCM7XX_TCSR_PRESCALE_LEN 8 + +/* + * Returns the index of timer in the tc->timer array. This can be used to + * locate the registers that belong to this timer. + */ +static int npcm7xx_timer_index(NPCM7xxTimerCtrlState *tc, NPCM7xxTimer *timer) +{ + int index = timer - tc->timer; + + g_assert(index >= 0 && index < NPCM7XX_TIMERS_PER_CTRL); + + return index; +} + +/* Return the value by which to divide the reference clock rate. */ +static uint32_t npcm7xx_timer_prescaler(const NPCM7xxTimer *t) +{ + return extract32(t->tcsr, NPCM7XX_TCSR_PRESCALE_START, + NPCM7XX_TCSR_PRESCALE_LEN) + 1; +} + +/* Convert a timer cycle count to a time interval in nanoseconds. */ +static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count) +{ + int64_t ns = count; + + ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ; + ns *= npcm7xx_timer_prescaler(t); + + return ns; +} + +/* Convert a time interval in nanoseconds to a timer cycle count. */ +static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns) +{ + int64_t count; + + count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ); + count /= npcm7xx_timer_prescaler(t); + + return count; +} + +/* + * Raise the interrupt line if there's a pending interrupt and interrupts are + * enabled for this timer. If not, lower it. + */ +static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t) +{ + NPCM7xxTimerCtrlState *tc = t->ctrl; + int index = npcm7xx_timer_index(tc, t); + + if ((t->tcsr & NPCM7XX_TCSR_IE) && (tc->tisr & BIT(index))) { + qemu_irq_raise(t->irq); + trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, 1); + } else { + qemu_irq_lower(t->irq); + trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, 0); + } +} + +/* Start or resume the timer. */ +static void npcm7xx_timer_start(NPCM7xxTimer *t) +{ + int64_t now; + + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + t->expires_ns = now + t->remaining_ns; + timer_mod(&t->qtimer, t->expires_ns); +} + +/* + * Called when the counter reaches zero. Sets the interrupt flag, and either + * restarts or disables the timer. + */ +static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t) +{ + NPCM7xxTimerCtrlState *tc = t->ctrl; + int index = npcm7xx_timer_index(tc, t); + + tc->tisr |= BIT(index); + + if (t->tcsr & NPCM7XX_TCSR_PERIODIC) { + t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr); + if (t->tcsr & NPCM7XX_TCSR_CEN) { + npcm7xx_timer_start(t); + } + } else { + t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT); + } + + npcm7xx_timer_check_interrupt(t); +} + +/* Stop counting. Record the time remaining so we can continue later. */ +static void npcm7xx_timer_pause(NPCM7xxTimer *t) +{ + int64_t now; + + timer_del(&t->qtimer); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + t->remaining_ns = t->expires_ns - now; + g_assert(t->remaining_ns > 0); +} + +/* + * Restart the timer from its initial value. If the timer was enabled and stays + * enabled, adjust the QEMU timer according to the new count. If the timer is + * transitioning from disabled to enabled, the caller is expected to start the + * timer later. + */ +static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr) +{ + t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr); + + if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) { + npcm7xx_timer_start(t); + } +} + +/* Register read and write handlers */ + +static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr) +{ + uint32_t old_tcsr = t->tcsr; + + if (new_tcsr & NPCM7XX_TCSR_RSVD) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: reserved bits in 0x%08x ignored\n", + __func__, new_tcsr); + new_tcsr &= ~NPCM7XX_TCSR_RSVD; + } + if (new_tcsr & NPCM7XX_TCSR_CACT) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only bits in 0x%08x ignored\n", + __func__, new_tcsr); + new_tcsr &= ~NPCM7XX_TCSR_CACT; + } + + t->tcsr = (t->tcsr & NPCM7XX_TCSR_CACT) | new_tcsr; + + if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_IE) { + npcm7xx_timer_check_interrupt(t); + } + if (new_tcsr & NPCM7XX_TCSR_CRST) { + npcm7xx_timer_restart(t, old_tcsr); + t->tcsr &= ~NPCM7XX_TCSR_CRST; + } + if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) { + if (new_tcsr & NPCM7XX_TCSR_CEN) { + npcm7xx_timer_start(t); + } else { + npcm7xx_timer_pause(t); + } + } +} + +static void npcm7xx_timer_write_ticr(NPCM7xxTimer *t, uint32_t new_ticr) +{ + t->ticr = new_ticr; + + npcm7xx_timer_restart(t, t->tcsr); +} + +static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t) +{ + if (t->tcsr & NPCM7XX_TCSR_CEN) { + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + return npcm7xx_timer_ns_to_count(t, t->expires_ns - now); + } + + return npcm7xx_timer_ns_to_count(t, t->remaining_ns); +} + +static hwaddr npcm7xx_tcsr_index(hwaddr reg) +{ + switch (reg) { + case NPCM7XX_TIMER_TCSR0: + return 0; + case NPCM7XX_TIMER_TCSR1: + return 1; + case NPCM7XX_TIMER_TCSR2: + return 2; + case NPCM7XX_TIMER_TCSR3: + return 3; + case NPCM7XX_TIMER_TCSR4: + return 4; + default: + g_assert_not_reached(); + } +} + +static hwaddr npcm7xx_ticr_index(hwaddr reg) +{ + switch (reg) { + case NPCM7XX_TIMER_TICR0: + return 0; + case NPCM7XX_TIMER_TICR1: + return 1; + case NPCM7XX_TIMER_TICR2: + return 2; + case NPCM7XX_TIMER_TICR3: + return 3; + case NPCM7XX_TIMER_TICR4: + return 4; + default: + g_assert_not_reached(); + } +} + +static hwaddr npcm7xx_tdr_index(hwaddr reg) +{ + switch (reg) { + case NPCM7XX_TIMER_TDR0: + return 0; + case NPCM7XX_TIMER_TDR1: + return 1; + case NPCM7XX_TIMER_TDR2: + return 2; + case NPCM7XX_TIMER_TDR3: + return 3; + case NPCM7XX_TIMER_TDR4: + return 4; + default: + g_assert_not_reached(); + } +} + +static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size) +{ + NPCM7xxTimerCtrlState *s = opaque; + uint64_t value = 0; + hwaddr reg; + + reg = offset / sizeof(uint32_t); + switch (reg) { + case NPCM7XX_TIMER_TCSR0: + case NPCM7XX_TIMER_TCSR1: + case NPCM7XX_TIMER_TCSR2: + case NPCM7XX_TIMER_TCSR3: + case NPCM7XX_TIMER_TCSR4: + value = s->timer[npcm7xx_tcsr_index(reg)].tcsr; + break; + + case NPCM7XX_TIMER_TICR0: + case NPCM7XX_TIMER_TICR1: + case NPCM7XX_TIMER_TICR2: + case NPCM7XX_TIMER_TICR3: + case NPCM7XX_TIMER_TICR4: + value = s->timer[npcm7xx_ticr_index(reg)].ticr; + break; + + case NPCM7XX_TIMER_TDR0: + case NPCM7XX_TIMER_TDR1: + case NPCM7XX_TIMER_TDR2: + case NPCM7XX_TIMER_TDR3: + case NPCM7XX_TIMER_TDR4: + value = npcm7xx_timer_read_tdr(&s->timer[npcm7xx_tdr_index(reg)]); + break; + + case NPCM7XX_TIMER_TISR: + value = s->tisr; + break; + + case NPCM7XX_TIMER_WTCR: + value = s->wtcr; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid offset 0x%04" HWADDR_PRIx "\n", + __func__, offset); + break; + } + + trace_npcm7xx_timer_read(DEVICE(s)->canonical_path, offset, value); + + return value; +} + +static void npcm7xx_timer_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ + uint32_t reg = offset / sizeof(uint32_t); + NPCM7xxTimerCtrlState *s = opaque; + uint32_t value = v; + + trace_npcm7xx_timer_write(DEVICE(s)->canonical_path, offset, value); + + switch (reg) { + case NPCM7XX_TIMER_TCSR0: + case NPCM7XX_TIMER_TCSR1: + case NPCM7XX_TIMER_TCSR2: + case NPCM7XX_TIMER_TCSR3: + case NPCM7XX_TIMER_TCSR4: + npcm7xx_timer_write_tcsr(&s->timer[npcm7xx_tcsr_index(reg)], value); + return; + + case NPCM7XX_TIMER_TICR0: + case NPCM7XX_TIMER_TICR1: + case NPCM7XX_TIMER_TICR2: + case NPCM7XX_TIMER_TICR3: + case NPCM7XX_TIMER_TICR4: + npcm7xx_timer_write_ticr(&s->timer[npcm7xx_ticr_index(reg)], value); + return; + + case NPCM7XX_TIMER_TDR0: + case NPCM7XX_TIMER_TDR1: + case NPCM7XX_TIMER_TDR2: + case NPCM7XX_TIMER_TDR3: + case NPCM7XX_TIMER_TDR4: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n", + __func__, offset); + return; + + case NPCM7XX_TIMER_TISR: + s->tisr &= ~value; + return; + + case NPCM7XX_TIMER_WTCR: + qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n", + __func__, value); + return; + } + + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid offset 0x%04" HWADDR_PRIx "\n", + __func__, offset); +} + +static const struct MemoryRegionOps npcm7xx_timer_ops = { + .read = npcm7xx_timer_read, + .write = npcm7xx_timer_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +/* Called when the QEMU timer expires. */ +static void npcm7xx_timer_expired(void *opaque) +{ + NPCM7xxTimer *t = opaque; + + if (t->tcsr & NPCM7XX_TCSR_CEN) { + npcm7xx_timer_reached_zero(t); + } +} + +static void npcm7xx_timer_enter_reset(Object *obj, ResetType type) +{ + NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); + int i; + + for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { + NPCM7xxTimer *t = &s->timer[i]; + + timer_del(&t->qtimer); + t->expires_ns = 0; + t->remaining_ns = 0; + t->tcsr = 0x00000005; + t->ticr = 0x00000000; + } + + s->tisr = 0x00000000; + s->wtcr = 0x00000400; +} + +static void npcm7xx_timer_hold_reset(Object *obj) +{ + NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); + int i; + + for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { + qemu_irq_lower(s->timer[i].irq); + } +} + +static void npcm7xx_timer_realize(DeviceState *dev, Error **errp) +{ + NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev); + SysBusDevice *sbd = &s->parent; + int i; + + for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { + NPCM7xxTimer *t = &s->timer[i]; + t->ctrl = s; + timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t); + sysbus_init_irq(sbd, &t->irq); + } + + memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s, + TYPE_NPCM7XX_TIMER, 4 * KiB); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_npcm7xx_timer = { + .name = "npcm7xx-timer", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_TIMER(qtimer, NPCM7xxTimer), + VMSTATE_INT64(expires_ns, NPCM7xxTimer), + VMSTATE_INT64(remaining_ns, NPCM7xxTimer), + VMSTATE_UINT32(tcsr, NPCM7xxTimer), + VMSTATE_UINT32(ticr, NPCM7xxTimer), + VMSTATE_END_OF_LIST(), + }, +}; + +static const VMStateDescription vmstate_npcm7xx_timer_ctrl = { + .name = "npcm7xx-timer-ctrl", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState), + VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState), + VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState, + NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer, + NPCM7xxTimer), + VMSTATE_END_OF_LIST(), + }, +}; + +static void npcm7xx_timer_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "NPCM7xx Timer Controller"; + dc->realize = npcm7xx_timer_realize; + dc->vmsd = &vmstate_npcm7xx_timer_ctrl; + rc->phases.enter = npcm7xx_timer_enter_reset; + rc->phases.hold = npcm7xx_timer_hold_reset; +} + +static const TypeInfo npcm7xx_timer_info = { + .name = TYPE_NPCM7XX_TIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCM7xxTimerCtrlState), + .class_init = npcm7xx_timer_class_init, +}; + +static void npcm7xx_timer_register_type(void) +{ + type_register_static(&npcm7xx_timer_info); +} +type_init(npcm7xx_timer_register_type); diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 1303b13e0d..d245b73571 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -14,6 +14,7 @@ common-obj-$(CONFIG_IMX) += imx_epit.o common-obj-$(CONFIG_IMX) += imx_gpt.o common-obj-$(CONFIG_LM32) += lm32_timer.o common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_timer.o common-obj-$(CONFIG_NRF51_SOC) += nrf51_timer.o common-obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 447b7c405b..ee66d8c84f 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -66,6 +66,11 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" +# npcm7xx_timer.c +npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64 +npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64 +npcm7xx_timer_irq(const char *id, int timer, int state) "%s timer %d state %d" + # nrf51_timer.c nrf51_timer_read(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" nrf51_timer_write(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" From patchwork Fri Jul 17 06:02:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669033 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9165F618 for ; Fri, 17 Jul 2020 06:08:26 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 57B81206BE for ; Fri, 17 Jul 2020 06:08:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="bUskrMdn" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 57B81206BE Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:52624 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJXl-00040q-LH for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:08:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60070) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3Jj8RXwsKCucQbTRWWNVXNWPXXPUN.LXVZNVd-MNeNUWXWPWd.XaP@flex--hskinnemoen.bounces.google.com>) id 1jwJSu-0003XQ-9O for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:24 -0400 Received: from mail-pl1-x649.google.com ([2607:f8b0:4864:20::649]:49185) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3Jj8RXwsKCucQbTRWWNVXNWPXXPUN.LXVZNVd-MNeNUWXWPWd.XaP@flex--hskinnemoen.bounces.google.com>) id 1jwJSr-0005Fq-1v for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:23 -0400 Received: by mail-pl1-x649.google.com with SMTP id p4so5941500pls.16 for ; Thu, 16 Jul 2020 23:03:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=E+lY6xeBY55G5SogqOYyjK4EaTCBDMXPYX8p9j4OOpw=; b=bUskrMdni+jMBtG0AkHtBH00no6GUo/RdDGElZebpzaFTZFFcNqMaCdIk8hwz6S3qx i8zueKNdvka4u0Shml50J0Pknsm+3lbP2y7gHtslZFJxGmnjexbM5Hp1a0lVFd45V1EU qXkoedA2y1Km9Fk7jBWP//S1F6GRd8wgK7Z3r/OkLdQmft/MXnUtbeGLaCNGm7XHK5Pm jpBbhdAeT9jehLCHi7Twce3V5P6MJnFkB/NDUGYGGYuSmHoHF6Xa3IQLe4oL5QiHf3zB KfVocSXh/TNiqsOksncNzmm6xqnZ5PpmLKybFuEA4whf+8vQCtFk8sf84G0AbPGOhzpo dsSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=E+lY6xeBY55G5SogqOYyjK4EaTCBDMXPYX8p9j4OOpw=; b=QmakrftgwN+NUgNHWK11XlZe7cMDwJxolxnYf/P69lxS6Dfygl7hdOdgO0PqTDojfV 4AiR9BBqwiAp5jXZNtv3Xr3+yZnWBzj2yycdzc1jc1o/kNxvauTvfrR14JS3xs3XhteU LWCChvm6ygKGtgrElg4tToTXsnmmmRBPa5ambU4np9pQd4LRDtr+/PqYSrJQ5jF5kbiz LqjnQBqJlsruYdXNs8fbjlmdRoMq1jkFSYPkRuv6G6UWXJ5ve/8S/W2dEf1jKTXxnQyv rxwE+Y+fwaDkwf8sCJdU/AHB2SNsoGCq0obOWBDoFA9DW9SgAl9ORo2ovKpWws36hzSY FtBQ== X-Gm-Message-State: AOAM531m7bUQpu6jbbLbLta42fBOszbHHQTlENixf18lO7K8KYtKeicm 8aqkzH2pfRuVQoFldv84/URGZrbIwyPzX4M9/BS5BuHL2RfdzkmkQMihsHC6oVdERjUv5+924OU duOdRb3FLveYwjYKZ06Zt3ZNO5eZSksEZjv8e45+ttHwqwW5TFv6B9aHH/PbIWAVjTL7VQf0Rlg == X-Google-Smtp-Source: ABdhPJxGpiIIP0JGBT6UT8LwXfNMeR4WUk91c76/jD0qwhly25ttdNwk4bMcfNLPwMzem0BORVndB6TDvZ5BBR7KLA== X-Received: by 2002:a17:90a:6c97:: with SMTP id y23mr8465868pjj.28.1594965798906; Thu, 16 Jul 2020 23:03:18 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:49 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-5-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 04/13] hw/arm: Add NPCM730 and NPCM750 SoC models From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , Joel Stanley , " =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::649; envelope-from=3Jj8RXwsKCucQbTRWWNVXNWPXXPUN.LXVZNVd-MNeNUWXWPWd.XaP@flex--hskinnemoen.bounces.google.com; helo=mail-pl1-x649.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" The Nuvoton NPCM7xx SoC family are used to implement Baseboard Management Controllers in servers. While the family includes four SoCs, this patch implements limited support for two of them: NPCM730 (targeted for Data Center applications) and NPCM750 (targeted for Enterprise applications). This patch includes little more than the bare minimum needed to boot a Linux kernel built with NPCM7xx support in direct-kernel mode: - Two Cortex-A9 CPU cores with built-in periperhals. - Global Configuration Registers. - Clock Management. - 3 Timer Modules with 5 timers each. - 4 serial ports. The chips themselves have a lot more features, some of which will be added to the model at a later stage. Reviewed-by: Tyrone Ting Reviewed-by: Joel Stanley Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Havard Skinnemoen --- include/hw/arm/npcm7xx.h | 85 ++++++++ hw/arm/npcm7xx.c | 407 +++++++++++++++++++++++++++++++++++++++ hw/arm/Kconfig | 5 + hw/arm/Makefile.objs | 1 + 4 files changed, 498 insertions(+) create mode 100644 include/hw/arm/npcm7xx.h create mode 100644 hw/arm/npcm7xx.c diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h new file mode 100644 index 0000000000..e68d9c79e6 --- /dev/null +++ b/include/hw/arm/npcm7xx.h @@ -0,0 +1,85 @@ +/* + * Nuvoton NPCM7xx SoC family. + * + * Copyright 2020 Google LLC + * + * 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. + */ +#ifndef NPCM7XX_H +#define NPCM7XX_H + +#include "hw/boards.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/misc/npcm7xx_clk.h" +#include "hw/misc/npcm7xx_gcr.h" +#include "hw/timer/npcm7xx_timer.h" +#include "target/arm/cpu.h" + +#define NPCM7XX_MAX_NUM_CPUS (2) + +/* The first half of the address space is reserved for DDR4 DRAM. */ +#define NPCM7XX_DRAM_BA (0x00000000) +#define NPCM7XX_DRAM_SZ (2 * GiB) + +/* Magic addresses for setting up direct kernel booting and SMP boot stubs. */ +#define NPCM7XX_LOADER_START (0x00000000) /* Start of SDRAM */ +#define NPCM7XX_SMP_LOADER_START (0xffff0000) /* Boot ROM */ +#define NPCM7XX_SMP_BOOTREG_ADDR (0xf080013c) /* GCR.SCRPAD */ +#define NPCM7XX_GIC_CPU_IF_ADDR (0xf03fe100) /* GIC within A9 */ + +typedef struct NPCM7xxState { + DeviceState parent; + + ARMCPU cpu[NPCM7XX_MAX_NUM_CPUS]; + A9MPPrivState a9mpcore; + + MemoryRegion sram; + MemoryRegion irom; + MemoryRegion ram3; + MemoryRegion *dram; + + NPCM7xxGCRState gcr; + NPCM7xxCLKState clk; + NPCM7xxTimerCtrlState tim[3]; +} NPCM7xxState; + +#define TYPE_NPCM7XX "npcm7xx" +#define NPCM7XX(obj) OBJECT_CHECK(NPCM7xxState, (obj), TYPE_NPCM7XX) + +#define TYPE_NPCM730 "npcm730" +#define TYPE_NPCM750 "npcm750" + +typedef struct NPCM7xxClass { + DeviceClass parent; + + /* Bitmask of modules that are permanently disabled on this chip. */ + uint32_t disabled_modules; + /* Number of CPU cores enabled in this SoC class (may be 1 or 2). */ + uint32_t num_cpus; +} NPCM7xxClass; + +#define NPCM7XX_CLASS(klass) \ + OBJECT_CLASS_CHECK(NPCM7xxClass, (klass), TYPE_NPCM7XX) +#define NPCM7XX_GET_CLASS(obj) \ + OBJECT_GET_CLASS(NPCM7xxClass, (obj), TYPE_NPCM7XX) + +/** + * npcm7xx_load_kernel - Loads memory with everything needed to boot + * @machine - The machine containing the SoC to be booted. + * @soc - The SoC containing the CPU to be booted. + * + * This will set up the ARM boot info structure for the specific NPCM7xx + * derivative and call arm_load_kernel() to set up loading of the kernel, etc. + * into memory, if requested by the user. + */ +void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc); + +#endif /* NPCM7XX_H */ diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c new file mode 100644 index 0000000000..9669ac5fa0 --- /dev/null +++ b/hw/arm/npcm7xx.c @@ -0,0 +1,407 @@ +/* + * Nuvoton NPCM7xx SoC family. + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "exec/address-spaces.h" +#include "hw/arm/boot.h" +#include "hw/arm/npcm7xx.h" +#include "hw/char/serial.h" +#include "hw/loader.h" +#include "hw/misc/unimp.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "qemu/units.h" +#include "sysemu/sysemu.h" + +/* + * This covers the whole MMIO space. We'll use this to catch any MMIO accesses + * that aren't handled by any device. + */ +#define NPCM7XX_MMIO_BA (0x80000000) +#define NPCM7XX_MMIO_SZ (0x7ffd0000) + +/* Core system modules. */ +#define NPCM7XX_L2C_BA (0xf03fc000) +#define NPCM7XX_CPUP_BA (0xf03fe000) +#define NPCM7XX_GCR_BA (0xf0800000) +#define NPCM7XX_CLK_BA (0xf0801000) + +/* Internal AHB SRAM */ +#define NPCM7XX_RAM3_BA (0xc0008000) +#define NPCM7XX_RAM3_SZ (4 * KiB) + +/* Memory blocks at the end of the address space */ +#define NPCM7XX_RAM2_BA (0xfffd0000) +#define NPCM7XX_RAM2_SZ (128 * KiB) +#define NPCM7XX_ROM_BA (0xffff0000) +#define NPCM7XX_ROM_SZ (64 * KiB) + +/* + * Interrupt lines going into the GIC. This does not include internal Cortex-A9 + * interrupts. + */ +enum NPCM7xxInterrupt { + NPCM7XX_UART0_IRQ = 2, + NPCM7XX_UART1_IRQ, + NPCM7XX_UART2_IRQ, + NPCM7XX_UART3_IRQ, + NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */ + NPCM7XX_TIMER1_IRQ, + NPCM7XX_TIMER2_IRQ, + NPCM7XX_TIMER3_IRQ, + NPCM7XX_TIMER4_IRQ, + NPCM7XX_TIMER5_IRQ, /* Timer Module 1 */ + NPCM7XX_TIMER6_IRQ, + NPCM7XX_TIMER7_IRQ, + NPCM7XX_TIMER8_IRQ, + NPCM7XX_TIMER9_IRQ, + NPCM7XX_TIMER10_IRQ, /* Timer Module 2 */ + NPCM7XX_TIMER11_IRQ, + NPCM7XX_TIMER12_IRQ, + NPCM7XX_TIMER13_IRQ, + NPCM7XX_TIMER14_IRQ, +}; + +/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */ +#define NPCM7XX_NUM_IRQ (160) + +/* Register base address for each Timer Module */ +static const hwaddr npcm7xx_tim_addr[] = { + 0xf0008000, + 0xf0009000, + 0xf000a000, +}; + +/* Register base address for each 16550 UART */ +static const hwaddr npcm7xx_uart_addr[] = { + 0xf0001000, + 0xf0002000, + 0xf0003000, + 0xf0004000, +}; + +static void npcm7xx_write_secondary_boot(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + /* + * The default smpboot stub halts the secondary CPU with a 'wfi' + * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux kernel + * does not send an IPI to wake it up, so the second CPU fails to boot. So + * we need to provide our own smpboot stub that can not use 'wfi', it has + * to spin the secondary CPU until the first CPU writes to the SCRPAD reg. + */ + uint32_t smpboot[] = { + 0xe59f2018, /* ldr r2, bootreg_addr */ + 0xe3a00000, /* mov r0, #0 */ + 0xe5820000, /* str r0, [r2] */ + 0xe320f002, /* wfe */ + 0xe5921000, /* ldr r1, [r2] */ + 0xe1110001, /* tst r1, r1 */ + 0x0afffffb, /* beq */ + 0xe12fff11, /* bx r1 */ + NPCM7XX_SMP_BOOTREG_ADDR, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(smpboot); i++) { + smpboot[i] = tswap32(smpboot[i]); + } + + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), + NPCM7XX_SMP_LOADER_START); +} + +static struct arm_boot_info npcm7xx_binfo = { + .loader_start = NPCM7XX_LOADER_START, + .smp_loader_start = NPCM7XX_SMP_LOADER_START, + .smp_bootreg_addr = NPCM7XX_SMP_BOOTREG_ADDR, + .gic_cpu_if_addr = NPCM7XX_GIC_CPU_IF_ADDR, + .write_secondary_boot = npcm7xx_write_secondary_boot, + .board_id = -1, +}; + +void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc) +{ + NPCM7xxClass *sc = NPCM7XX_GET_CLASS(soc); + + npcm7xx_binfo.ram_size = machine->ram_size; + npcm7xx_binfo.nb_cpus = sc->num_cpus; + + arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo); +} + +static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n) +{ + return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n); +} + +static void npcm7xx_init(Object *obj) +{ + NPCM7xxState *s = NPCM7XX(obj); + int i; + + for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) { + object_initialize_child(obj, "cpu[*]", &s->cpu[i], + ARM_CPU_TYPE_NAME("cortex-a9")); + } + + object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV); + object_initialize_child(obj, "gcr", &s->gcr, TYPE_NPCM7XX_GCR); + object_property_add_alias(obj, "power-on-straps", OBJECT(&s->gcr), + "power-on-straps"); + object_initialize_child(obj, "clk", &s->clk, TYPE_NPCM7XX_CLK); + + for (i = 0; i < ARRAY_SIZE(s->tim); i++) { + object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER); + } +} + +static void npcm7xx_realize(DeviceState *dev, Error **errp) +{ + NPCM7xxState *s = NPCM7XX(dev); + NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s); + int i; + + if (memory_region_size(s->dram) > NPCM7XX_DRAM_SZ) { + error_setg(errp, "%s: NPCM7xx cannot address more than %" PRIu64 + " MiB of DRAM", __func__, NPCM7XX_DRAM_SZ / MiB); + return; + } + + /* CPUs */ + for (i = 0; i < nc->num_cpus; i++) { + object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity", + arm_cpu_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS), + &error_abort); + object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", + NPCM7XX_GIC_CPU_IF_ADDR, &error_abort); + object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true, + &error_abort); + + /* Disable security extensions. */ + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false, + &error_abort); + + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { + return; + } + } + + /* A9MPCORE peripherals. Can only fail if we pass bad parameters here. */ + object_property_set_int(OBJECT(&s->a9mpcore), "num-cpu", nc->num_cpus, + &error_abort); + object_property_set_int(OBJECT(&s->a9mpcore), "num-irq", NPCM7XX_NUM_IRQ, + &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, NPCM7XX_CPUP_BA); + + for (i = 0; i < nc->num_cpus; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i, + qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + nc->num_cpus, + qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); + } + + /* L2 cache controller */ + sysbus_create_simple("l2x0", NPCM7XX_L2C_BA, NULL); + + /* System Global Control Registers (GCR). Can fail due to user input. */ + object_property_set_int(OBJECT(&s->gcr), "disabled-modules", + nc->disabled_modules, &error_abort); + object_property_add_const_link(OBJECT(&s->gcr), "dram-mr", OBJECT(s->dram)); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM7XX_GCR_BA); + + /* Clock Control Registers (CLK). Cannot fail. */ + sysbus_realize(SYS_BUS_DEVICE(&s->clk), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM7XX_CLK_BA); + + /* Timer Modules (TIM). Cannot fail. */ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim)); + for (i = 0; i < ARRAY_SIZE(s->tim); i++) { + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->tim[i]); + int first_irq; + int j; + + sysbus_realize(sbd, &error_abort); + sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]); + + first_irq = NPCM7XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL; + for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) { + qemu_irq irq = npcm7xx_irq(s, first_irq + j); + sysbus_connect_irq(sbd, j, irq); + } + } + + /* UART0..3 (16550 compatible) */ + for (i = 0; i < ARRAY_SIZE(npcm7xx_uart_addr); i++) { + serial_mm_init(get_system_memory(), npcm7xx_uart_addr[i], 2, + npcm7xx_irq(s, NPCM7XX_UART0_IRQ + i), 115200, + serial_hd(i), DEVICE_LITTLE_ENDIAN); + } + + /* RAM2 (SRAM) */ + memory_region_init_ram(&s->sram, OBJECT(dev), "ram2", + NPCM7XX_RAM2_SZ, &error_abort); + memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM2_BA, &s->sram); + + /* RAM3 (SRAM) */ + memory_region_init_ram(&s->ram3, OBJECT(dev), "ram3", + NPCM7XX_RAM3_SZ, &error_abort); + memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM3_BA, &s->ram3); + + /* Internal ROM */ + memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM7XX_ROM_SZ, + &error_abort); + memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom); + + create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB); + create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB); + create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB); + create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB); + create_unimplemented_device("npcm7xx.rng", 0xf000b000, 4 * KiB); + create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB); + create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[1]", 0xf0011000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[2]", 0xf0012000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[3]", 0xf0013000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[4]", 0xf0014000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[5]", 0xf0015000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[6]", 0xf0016000, 4 * KiB); + create_unimplemented_device("npcm7xx.gpio[7]", 0xf0017000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[0]", 0xf0080000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[1]", 0xf0081000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[2]", 0xf0082000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[3]", 0xf0083000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[4]", 0xf0084000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[5]", 0xf0085000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[6]", 0xf0086000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[7]", 0xf0087000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[8]", 0xf0088000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[9]", 0xf0089000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[10]", 0xf008a000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[11]", 0xf008b000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[12]", 0xf008c000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[13]", 0xf008d000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[14]", 0xf008e000, 4 * KiB); + create_unimplemented_device("npcm7xx.smbus[15]", 0xf008f000, 4 * KiB); + create_unimplemented_device("npcm7xx.espi", 0xf009f000, 4 * KiB); + create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB); + create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB); + create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB); + create_unimplemented_device("npcm7xx.pwm[0]", 0xf0103000, 4 * KiB); + create_unimplemented_device("npcm7xx.pwm[1]", 0xf0104000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[3]", 0xf0183000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[4]", 0xf0184000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[5]", 0xf0185000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[6]", 0xf0186000, 4 * KiB); + create_unimplemented_device("npcm7xx.mft[7]", 0xf0187000, 4 * KiB); + create_unimplemented_device("npcm7xx.pspi1", 0xf0200000, 4 * KiB); + create_unimplemented_device("npcm7xx.pspi2", 0xf0201000, 4 * KiB); + create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB); + create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB); + create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB); + create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB); + create_unimplemented_device("npcm7xx.ehci", 0xf0806000, 4 * KiB); + create_unimplemented_device("npcm7xx.ohci", 0xf0807000, 4 * KiB); + create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB); + create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB); + create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB); + create_unimplemented_device("npcm7xx.emc1", 0xf0825000, 4 * KiB); + create_unimplemented_device("npcm7xx.emc2", 0xf0826000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[0]", 0xf0830000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[1]", 0xf0831000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[2]", 0xf0832000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[3]", 0xf0833000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[4]", 0xf0834000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[5]", 0xf0835000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[6]", 0xf0836000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[7]", 0xf0837000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[8]", 0xf0838000, 4 * KiB); + create_unimplemented_device("npcm7xx.usbd[9]", 0xf0839000, 4 * KiB); + create_unimplemented_device("npcm7xx.sd", 0xf0840000, 8 * KiB); + create_unimplemented_device("npcm7xx.mmc", 0xf0842000, 8 * KiB); + create_unimplemented_device("npcm7xx.pcimbx", 0xf0848000, 512 * KiB); + create_unimplemented_device("npcm7xx.aes", 0xf0858000, 4 * KiB); + create_unimplemented_device("npcm7xx.des", 0xf0859000, 4 * KiB); + create_unimplemented_device("npcm7xx.sha", 0xf085a000, 4 * KiB); + create_unimplemented_device("npcm7xx.secacc", 0xf085b000, 4 * KiB); + create_unimplemented_device("npcm7xx.spixcs0", 0xf8000000, 16 * MiB); + create_unimplemented_device("npcm7xx.spixcs1", 0xf9000000, 16 * MiB); + create_unimplemented_device("npcm7xx.spix", 0xfb001000, 4 * KiB); +} + +static Property npcm7xx_properties[] = { + DEFINE_PROP_LINK("dram-mr", NPCM7xxState, dram, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void npcm7xx_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = npcm7xx_realize; + dc->user_creatable = false; + device_class_set_props(dc, npcm7xx_properties); +} + +static void npcm730_class_init(ObjectClass *oc, void *data) +{ + NPCM7xxClass *nc = NPCM7XX_CLASS(oc); + + /* NPCM730 is optimized for data center use, so no graphics, etc. */ + nc->disabled_modules = 0x00300395; + nc->num_cpus = 2; +} + +static void npcm750_class_init(ObjectClass *oc, void *data) +{ + NPCM7xxClass *nc = NPCM7XX_CLASS(oc); + + /* NPCM750 has 2 cores and a full set of peripherals */ + nc->disabled_modules = 0x00000000; + nc->num_cpus = 2; +} + +static const TypeInfo npcm7xx_soc_types[] = { + { + .name = TYPE_NPCM7XX, + .parent = TYPE_DEVICE, + .instance_size = sizeof(NPCM7xxState), + .instance_init = npcm7xx_init, + .class_size = sizeof(NPCM7xxClass), + .class_init = npcm7xx_class_init, + .abstract = true, + }, { + .name = TYPE_NPCM730, + .parent = TYPE_NPCM7XX, + .class_init = npcm730_class_init, + }, { + .name = TYPE_NPCM750, + .parent = TYPE_NPCM7XX, + .class_init = npcm750_class_init, + }, +}; + +DEFINE_TYPES(npcm7xx_soc_types); diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 192a8dec3b..a31d0d282f 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -356,6 +356,11 @@ config XLNX_VERSAL config NPCM7XX bool + select A9MPCORE + select ARM_GIC + select PL310 # cache controller + select SERIAL + select UNIMP config FSL_IMX25 bool diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 534a6a119e..13d163a599 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -41,6 +41,7 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o obj-$(CONFIG_STM32F405_SOC) += stm32f405_soc.o obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o +obj-$(CONFIG_NPCM7XX) += npcm7xx.o obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o From patchwork Fri Jul 17 06:02:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669031 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 593CB618 for ; Fri, 17 Jul 2020 06:08:22 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2CA29206BE for ; Fri, 17 Jul 2020 06:08:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="dm8Cz0mW" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2CA29206BE Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:52180 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJXh-0003qE-B3 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:08:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60100) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3KD8RXwsKCukSdVTYYPXZPYRZZRWP.NZXbPXf-OPgPWYZYRYf.ZcR@flex--hskinnemoen.bounces.google.com>) id 1jwJSv-0003ap-Mn for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:25 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:42990) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3KD8RXwsKCukSdVTYYPXZPYRZZRWP.NZXbPXf-OPgPWYZYRYf.ZcR@flex--hskinnemoen.bounces.google.com>) id 1jwJSs-0005GG-IM for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:25 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id i203so10128378yba.9 for ; Thu, 16 Jul 2020 23:03:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=UmmS/IEQWs/xO2jg8Dkq6wyYPgQ1kHSlf3Cj11NzpS8=; b=dm8Cz0mW1eMX95iDy5eY9AXyn5yRuckaBbaYUDot9gWxvuocQAHIOocpZ4sG3+UduA IpwCiqq0kHWIO3ldGMzQvXSQOEkwOn4RU6y5vtqn+ed7/waUUba3GmayCQ1VarxKbP6g d/NDZIuWM9sM8FkxO5ue5u/AVIf3LE51OuQWkz2Ja0UfayvhhoPNeN2KMZpMDmDpsQB4 szWwIf7gXVcR9u381eRlKntGHWQtByON8ZSHb6a2Sm6lEJkLuTdB74FXNOA3LXNcNrOZ XrfINADdetaRqPa3Hf58gPecxYZ9lhsLTGWjiqm7gtF8Eva5+10LPUtvQ20eeE9aP3Z7 G6Pw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=UmmS/IEQWs/xO2jg8Dkq6wyYPgQ1kHSlf3Cj11NzpS8=; b=P+gYbMP0LJE9yEoQyETjUOBl8f2hbNvNhZtEt8o/tw6pIKG5ZtQGQXQ6Mi9fJHwGmR t2CnhxfK6i5hYX1sweDrGQKiIEp7cygu/UW3kQUSh3dvAg1HVU4L9SdSIwiqdu5X5Edd 4DRtEvVWvshCspZ7M6EF0x+3WkLO3DK5PmtPQ4v9Qt+HpQ5oPtjvzs1irHHQpXdvOsOQ hOr+rovBkhny0DHHhpYbjcnFMAu6V6EQAFqiMoW69j4cTbq88HWvwPy3SUVX6uXRMPWu KSJGseMtWBb/wj7fkQwg9UiTQK6rRYRQuKK5R49XP1d7LRRnvQWRLGFonteX7HHtZimG sM4w== X-Gm-Message-State: AOAM533NmcpU4rKdxJylblMtjfSjE+NHj3dK5ZYJK2suOEGoMlWpr7XS cbE5P+yiQxR/Nx1HD5JrMwiuJDftHLBAySWd8vS+RtW9g9EROxA6eCqP+a09/nzcl2V64QnWVma e9kSRBy4VSmT165NxJM6XGGcl28dwPnW+35oQWkyMuDr5LJpXKTN0yDSo3LVbNLFxm315uVs7BA == X-Google-Smtp-Source: ABdhPJy7Nv0haMjwyg451jPAw2psENkUyYVGqIQei9lRI0ujLT9RP3r68eFv8BxtqO7pRd+KTIaYM+5x6jC563II2Q== X-Received: by 2002:a25:ac02:: with SMTP id w2mr12249939ybi.57.1594965800850; Thu, 16 Jul 2020 23:03:20 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:50 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-6-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 05/13] hw/arm: Add two NPCM7xx-based machines From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , Joel Stanley , " =?utf-8?q?C=C3=A9dric_Le_Goater?= " , " =?utf-8?q?Philippe?= =?utf-8?q?_Mathieu-Daud=C3=A9?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3KD8RXwsKCukSdVTYYPXZPYRZZRWP.NZXbPXf-OPgPWYZYRYf.ZcR@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This adds two new machines, both supported by OpenBMC: - npcm750-evb: Nuvoton NPCM750 Evaluation Board. - quanta-gsj: A board with a NPCM730 chip. They rely on the NPCM7xx SoC device to do the heavy lifting. They are almost completely identical at the moment, apart from the SoC type, which currently only changes the reset contents of one register (GCR.MDLR), but they might grow apart a bit more as more functionality is added. Both machines can boot the Linux kernel into /bin/sh. Reviewed-by: Tyrone Ting Reviewed-by: Joel Stanley Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Havard Skinnemoen --- default-configs/arm-softmmu.mak | 1 + include/hw/arm/npcm7xx.h | 19 +++++ hw/arm/npcm7xx_boards.c | 144 ++++++++++++++++++++++++++++++++ hw/arm/Makefile.objs | 2 +- 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 hw/arm/npcm7xx_boards.c diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 8fc09a4a51..9a94ebd0be 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -27,6 +27,7 @@ CONFIG_GUMSTIX=y CONFIG_SPITZ=y CONFIG_TOSA=y CONFIG_Z2=y +CONFIG_NPCM7XX=y CONFIG_COLLIE=y CONFIG_ASPEED_SOC=y CONFIG_NETDUINO2=y diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h index e68d9c79e6..ba7495869d 100644 --- a/include/hw/arm/npcm7xx.h +++ b/include/hw/arm/npcm7xx.h @@ -35,6 +35,25 @@ #define NPCM7XX_SMP_BOOTREG_ADDR (0xf080013c) /* GCR.SCRPAD */ #define NPCM7XX_GIC_CPU_IF_ADDR (0xf03fe100) /* GIC within A9 */ +typedef struct NPCM7xxMachine { + MachineState parent; +} NPCM7xxMachine; + +#define TYPE_NPCM7XX_MACHINE MACHINE_TYPE_NAME("npcm7xx") +#define NPCM7XX_MACHINE(obj) \ + OBJECT_CHECK(NPCM7xxMachine, (obj), TYPE_NPCM7XX_MACHINE) + +typedef struct NPCM7xxMachineClass { + MachineClass parent; + + const char *soc_type; +} NPCM7xxMachineClass; + +#define NPCM7XX_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(NPCM7xxMachineClass, (klass), TYPE_NPCM7XX_MACHINE) +#define NPCM7XX_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(NPCM7xxMachineClass, (obj), TYPE_NPCM7XX_MACHINE) + typedef struct NPCM7xxState { DeviceState parent; diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c new file mode 100644 index 0000000000..0b9dce2b35 --- /dev/null +++ b/hw/arm/npcm7xx_boards.c @@ -0,0 +1,144 @@ +/* + * Machine definitions for boards featuring an NPCM7xx SoC. + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/arm/npcm7xx.h" +#include "hw/core/cpu.h" +#include "qapi/error.h" +#include "qemu/units.h" + +#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7 +#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff + +static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram) +{ + memory_region_add_subregion(get_system_memory(), NPCM7XX_DRAM_BA, dram); + + object_property_set_link(OBJECT(soc), "dram-mr", OBJECT(dram), + &error_abort); +} + +static NPCM7xxState *npcm7xx_create_soc(MachineState *machine, + uint32_t hw_straps) +{ + NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine); + MachineClass *mc = &nmc->parent; + Object *obj; + + if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) { + error_report("This board can only be used with %s", + mc->default_cpu_type); + exit(1); + } + + obj = object_new_with_props(nmc->soc_type, OBJECT(machine), "soc", + &error_abort, NULL); + object_property_set_uint(obj, "power-on-straps", hw_straps, &error_abort); + + return NPCM7XX(obj); +} + +static void npcm750_evb_init(MachineState *machine) +{ + NPCM7xxState *soc; + + soc = npcm7xx_create_soc(machine, NPCM750_EVB_POWER_ON_STRAPS); + npcm7xx_connect_dram(soc, machine->ram); + qdev_realize(DEVICE(soc), NULL, &error_fatal); + + npcm7xx_load_kernel(machine, soc); +} + +static void quanta_gsj_init(MachineState *machine) +{ + NPCM7xxState *soc; + + soc = npcm7xx_create_soc(machine, QUANTA_GSJ_POWER_ON_STRAPS); + npcm7xx_connect_dram(soc, machine->ram); + qdev_realize(DEVICE(soc), NULL, &error_fatal); + + npcm7xx_load_kernel(machine, soc); +} + +static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type) +{ + NPCM7xxClass *sc = NPCM7XX_CLASS(object_class_by_name(type)); + MachineClass *mc = MACHINE_CLASS(nmc); + + nmc->soc_type = type; + mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus; +} + +static void npcm7xx_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; + mc->default_ram_id = "ram"; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); +} + +/* + * Schematics: + * https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf + */ +static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data) +{ + NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); + MachineClass *mc = MACHINE_CLASS(oc); + + npcm7xx_set_soc_type(nmc, TYPE_NPCM750); + + mc->desc = "Nuvoton NPCM750 Evaluation Board (Cortex A9)"; + mc->init = npcm750_evb_init; + mc->default_ram_size = 512 * MiB; +}; + +static void gsj_machine_class_init(ObjectClass *oc, void *data) +{ + NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); + MachineClass *mc = MACHINE_CLASS(oc); + + npcm7xx_set_soc_type(nmc, TYPE_NPCM730); + + mc->desc = "Quanta GSJ (Cortex A9)"; + mc->init = quanta_gsj_init; + mc->default_ram_size = 512 * MiB; +}; + +static const TypeInfo npcm7xx_machine_types[] = { + { + .name = TYPE_NPCM7XX_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(NPCM7xxMachine), + .class_size = sizeof(NPCM7xxMachineClass), + .class_init = npcm7xx_machine_class_init, + .abstract = true, + }, { + .name = MACHINE_TYPE_NAME("npcm750-evb"), + .parent = TYPE_NPCM7XX_MACHINE, + .class_init = npcm750_evb_machine_class_init, + }, { + .name = MACHINE_TYPE_NAME("quanta-gsj"), + .parent = TYPE_NPCM7XX_MACHINE, + .class_init = gsj_machine_class_init, + }, +}; + +DEFINE_TYPES(npcm7xx_machine_types) diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 13d163a599..c333548ce1 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -41,7 +41,7 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o obj-$(CONFIG_STM32F405_SOC) += stm32f405_soc.o obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o -obj-$(CONFIG_NPCM7XX) += npcm7xx.o +obj-$(CONFIG_NPCM7XX) += npcm7xx.o npcm7xx_boards.o obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o From patchwork Fri Jul 17 06:02:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669039 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 59895618 for ; Fri, 17 Jul 2020 06:10:00 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2B0B2206BE for ; Fri, 17 Jul 2020 06:10:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="dl8L0zAV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2B0B2206BE Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:58640 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJZH-0006Sq-Cr for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:09:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60116) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3Kz8RXwsKCuwVgYWbbSacSbUccUZS.QcaeSai-RSjSZbcbUbi.cfU@flex--hskinnemoen.bounces.google.com>) id 1jwJSw-0003dQ-SA for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:26 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:38519) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3Kz8RXwsKCuwVgYWbbSacSbUccUZS.QcaeSai-RSjSZbcbUbi.cfU@flex--hskinnemoen.bounces.google.com>) id 1jwJSv-0005GZ-8o for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:26 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id 124so10323155ybb.5 for ; Thu, 16 Jul 2020 23:03:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=zj8bIibIdnQybBaGQVDBz5aPKtzt2hn+lBo9PsbHCSU=; b=dl8L0zAV5p9vyPHtd2jPDRxweLQ0c8kKpugeUt/93A3FJF6Ap9mAi41K3wB9Z6LtLe hmsRCp6FtY8Q8t/pD1brTV/92Y2Iur9KiPpJZxh1L5PuRRExEuW4EkUOQQqtK5qobE1f eZ/JdG9pIbdr++98CmpHH7GQmE9UhXZs20hHZPNVyp11Jfs/Wq6fi2LTT22m778k0SXA xmZshiu5KeL34gASswhlOodTBgxdYPCI+9oy4MFvmXMcXU6veg4QgKWz/BqfiR7xEaZC qkRVVHS4ibOLktbJXjRa9LQnuX2iJXqWOCBzp17117liAB3bayOrviIb7f9QrQNo6lVn JPtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=zj8bIibIdnQybBaGQVDBz5aPKtzt2hn+lBo9PsbHCSU=; b=T+43pADCdVNebZZWIstbtQ8mzgaLwguawmk69fE+5abo0qIJ6CevM/4ah7Vqqk2nBb r2hOy9w8gl4Q8HtCA8jnKCTjDLQZT4UIak789grbi+1u57Dz7bHK4+cH6rZ2SvtYa4+1 3vCF4kUz7iuAZ46JzehdYR0+wOTBB/bdYiJOIVHMiUHV+AlPm+2u3LSs223a7WNJXTwS X9E1Hom7pizFfGwz6YrkJkLrBYE2tHuA6ErSbY+kqqbDzq22qvY7+tIuLDbRtAaAhOXl hvyXCPEF5Oqud6+Iat43wyPrjDYyogPqeqkdQU5WJEAuqYfb7wC+PEawic7Pp6HnpvAP wnZA== X-Gm-Message-State: AOAM532YqnYMA+REm4Cl0zeGOko5kVwYXr7eJli3jeanPwc/C7ie3MDQ oWLjIfOWaXHao7cKi4K+/0nSXNAuS/sYAHXQaNePx309FsR/kgWRik0vKsZVKpq6cg0nlIPG/Zy +SmRev1BIwKW3nfIWJtdJK2EqINhvkJXwEE35PJFLDecwOC30vzD5odcg8CzMCciOdJxN9oQ8Ew == X-Google-Smtp-Source: ABdhPJzIPes5ARqBTwRSQh/yiSG/In/XPsoc71cWr3Uyzhbud/7oK1FJ7f/+rkO5VI3TdxWlMhOfF6af5q+ECgcyHg== X-Received: by 2002:a25:3752:: with SMTP id e79mr11533382yba.263.1594965803184; Thu, 16 Jul 2020 23:03:23 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:51 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-7-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 06/13] roms: Add virtual Boot ROM for NPCM7xx SoCs From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3Kz8RXwsKCuwVgYWbbSacSbUccUZS.QcaeSai-RSjSZbcbUbi.cfU@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This is a minimalistic boot ROM written specifically for use with QEMU. It supports loading the second-stage loader from SPI flash into RAM, SMP boot, and not much else. Signed-off-by: Havard Skinnemoen --- Makefile | 1 + .gitmodules | 3 +++ pc-bios/npcm7xx_bootrom.bin | Bin 0 -> 768 bytes roms/Makefile | 7 +++++++ roms/vbootrom | 1 + 5 files changed, 12 insertions(+) create mode 100644 pc-bios/npcm7xx_bootrom.bin create mode 160000 roms/vbootrom diff --git a/Makefile b/Makefile index 32345c610e..56473c788d 100644 --- a/Makefile +++ b/Makefile @@ -838,6 +838,7 @@ s390-ccw.img s390-netboot.img \ slof.bin skiboot.lid \ palcode-clipper \ u-boot.e500 u-boot-sam460-20100605.bin \ +npcm7xx_bootrom.bin \ qemu_vga.ndrv \ edk2-licenses.txt \ hppa-firmware.img \ diff --git a/.gitmodules b/.gitmodules index 9c0501a4d4..c95eaf8284 100644 --- a/.gitmodules +++ b/.gitmodules @@ -58,3 +58,6 @@ [submodule "roms/qboot"] path = roms/qboot url = https://github.com/bonzini/qboot +[submodule "roms/vbootrom"] + path = roms/vbootrom + url = https://github.com/google/vbootrom.git diff --git a/pc-bios/npcm7xx_bootrom.bin b/pc-bios/npcm7xx_bootrom.bin new file mode 100644 index 0000000000000000000000000000000000000000..38f89d1b97b0c2e133af2a9fbed0521be132065b GIT binary patch literal 768 zcmd5)JxClu6n-9S05p1#kf90Sj5Z(jG8}+)IZIp~iXK=T&)dL`%d-q*8aR#mq{7 z9`=6;Dr(H0ACe72R5x?!)^86Qj-X%{+!K9iZNA@*wkBAV&iZ(l^I9?!Gz=S2I_*1d zr+tTQDHjvyzKnw(hu00yX`u!FvC;DilBe_YlkeSUVHA-crNk+k jtiF_MudA X-Patchwork-Id: 11669043 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9183618 for ; Fri, 17 Jul 2020 06:11:43 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9ED832071A for ; Fri, 17 Jul 2020 06:11:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="T1puZXUB" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9ED832071A Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:36690 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJaw-0000iE-UU for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:11:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60138) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3LT8RXwsKCu4XiaYddUceUdWeeWbU.SecgUck-TUlUbdedWdk.ehW@flex--hskinnemoen.bounces.google.com>) id 1jwJSy-0003i4-LD for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:28 -0400 Received: from mail-pg1-x549.google.com ([2607:f8b0:4864:20::549]:37628) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3LT8RXwsKCu4XiaYddUceUdWeeWbU.SecgUck-TUlUbdedWdk.ehW@flex--hskinnemoen.bounces.google.com>) id 1jwJSx-0005HE-1w for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:28 -0400 Received: by mail-pg1-x549.google.com with SMTP id h5so7200291pgq.4 for ; Thu, 16 Jul 2020 23:03:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=frc86mILmkHC+wqWcKw1PPJTa/OZk2Y3JpwlzSnJqMM=; b=T1puZXUBXlcMoWFROgqScO4xHSDWK+e87YnMYExRLrvuOElQ1MiJjWpRy9oWD00nYY e3TtVfyQq0btj5BpL9h1tTV1DmZzVGXo9203v9qOB8TJZ8rnGPebuQLb2Kk3p134Q6Z1 ZmsxSzqlv6g77zysQCmoNU1qW9aPtyot4Z5ZFzJIC2wiyhORxU4jnnt6c1st8jaLuL/p qm1icrFywU5nfUrMZoYzntgvNw/wnDQ3OqMEDzikN0XG/+w5u+Su/Gq/XUJSkHUcgu+9 Gyc8suo9S5Ld6gjeKt+tV/4vdUZFNmRF8dXZ2bJk3n5snZVsiasvCeL874XauV1DyrYk lVfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=frc86mILmkHC+wqWcKw1PPJTa/OZk2Y3JpwlzSnJqMM=; b=BM3TItZxBLBSlXq7NQP9gDkAVBza+illoWn6sfkrUh2RemviqNcWxoZD12Lwr7Fkq3 Gm9pAwXx5I/2BYSxqHAlhrKXl076EXYARXtxjN1dTgnElnmC1F+Bk4LQ3+7nIAAJFHYk F8q62+WcfFHPLYbRNdOUWraa4yts49lRrlEHU1x1eCtDf2U50YYFNOGMYmoi0c+iZkZR h22ukT+5+2P73hNtonzR6n+KMWWZir1pVNm0fRKMznG7GPSHnCq0kWu1BJqI8Kqnza3N 9LOPXybW3foeeM3mryp5kNFKU3EouFXjBC0b7qbcSYp7Bfv4vkTE7MeaKtQmgnLhjfwo eTFg== X-Gm-Message-State: AOAM532Hp8SU2YvfCJ3N1jCoqF6ABiJtz6+MO6tz9IBzpyXgcu7RxO7a HZa4u1s5tYRjoWZ3WkieDE1zmyEWvjZMKYAkgQkKaIMFcA3quJAT5RrheefmiwxKDdJD06KDRoc 1gutfhXR3dUOSqXt85MnUY+LlesAZfUkhiKTMlfh/ODdjZHQDAoD5EQqoRFmGRR2xOYeP7DS6Dg == X-Google-Smtp-Source: ABdhPJyJcR0Nj1CMZAmFs/XMLczYOutOsMaasTMgPmxSpuR2lkPCg9vekBOeG1LGukIOwTfdWFEyVZYMrSP7UwdQcg== X-Received: by 2002:a17:90b:194f:: with SMTP id nk15mr8495696pjb.189.1594965805094; Thu, 16 Jul 2020 23:03:25 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:52 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-8-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 07/13] hw/arm: Load -bios image as a boot ROM for npcm7xx From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen Received-SPF: pass client-ip=2607:f8b0:4864:20::549; envelope-from=3LT8RXwsKCu4XiaYddUceUdWeeWbU.SecgUck-TUlUbdedWdk.ehW@flex--hskinnemoen.bounces.google.com; helo=mail-pg1-x549.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" If a -bios option is specified on the command line, load the image into the internal ROM memory region, which contains the first instructions run by the CPU after reset. If -bios is not specified, the vbootrom included with qemu is loaded by default. Reviewed-by: Tyrone Ting Signed-off-by: Havard Skinnemoen Reviewed-by: Cédric Le Goater --- hw/arm/npcm7xx_boards.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index 0b9dce2b35..f32557e0e1 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -18,12 +18,41 @@ #include "hw/arm/npcm7xx.h" #include "hw/core/cpu.h" +#include "hw/loader.h" #include "qapi/error.h" +#include "qemu-common.h" #include "qemu/units.h" +#include "sysemu/sysemu.h" #define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7 #define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff +static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin"; + +static void npcm7xx_load_bootrom(NPCM7xxState *soc) +{ + g_autofree char *filename = NULL; + const char *bootrom; + int ret; + + if (bios_name) { + bootrom = bios_name; + } else { + bootrom = npcm7xx_default_bootrom; + } + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bootrom); + if (!filename) { + error_report("Could not find ROM image '%s'", bootrom); + exit(1); + } + ret = load_image_mr(filename, &soc->irom); + if (ret < 0) { + error_report("Failed to load ROM image '%s'", filename); + exit(1); + } +} + static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram) { memory_region_add_subregion(get_system_memory(), NPCM7XX_DRAM_BA, dram); @@ -60,6 +89,7 @@ static void npcm750_evb_init(MachineState *machine) npcm7xx_connect_dram(soc, machine->ram); qdev_realize(DEVICE(soc), NULL, &error_fatal); + npcm7xx_load_bootrom(soc); npcm7xx_load_kernel(machine, soc); } @@ -71,6 +101,7 @@ static void quanta_gsj_init(MachineState *machine) npcm7xx_connect_dram(soc, machine->ram); qdev_realize(DEVICE(soc), NULL, &error_fatal); + npcm7xx_load_bootrom(soc); npcm7xx_load_kernel(machine, soc); } From patchwork Fri Jul 17 06:02:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669023 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 40EBF1751 for ; Fri, 17 Jul 2020 06:05:46 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 071482070A for ; Fri, 17 Jul 2020 06:05:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="C0pv9Vpq" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 071482070A Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:39940 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJVB-0007I1-8X for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:05:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60200) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3Lz8RXwsKCvAZkcaffWegWfYggYdW.UgeiWem-VWnWdfgfYfm.gjY@flex--hskinnemoen.bounces.google.com>) id 1jwJT5-0003nF-6y for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:35 -0400 Received: from mail-pl1-x64a.google.com ([2607:f8b0:4864:20::64a]:50281) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3Lz8RXwsKCvAZkcaffWegWfYggYdW.UgeiWem-VWnWdfgfYfm.gjY@flex--hskinnemoen.bounces.google.com>) id 1jwJT0-0005HX-FI for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:34 -0400 Received: by mail-pl1-x64a.google.com with SMTP id x23so5924399plr.17 for ; Thu, 16 Jul 2020 23:03:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=IbFarr6PyXbKMrUCcTktm6h/NoDAD0DUXRZ/zzxFCHg=; b=C0pv9Vpqvq89Zo0HILTeWC5WnbFzgvnmGAMw808UZGaMaiJyZOAN6ecRPpMaOR5Fbs 2Mxwk/cB5zFXFZKLI12e3y3ClcL06nHY4iOBPNin8U438vm/Rgfd1IUJSjbwUM7ImwSK zL7ypanUTjXbmzKEDusWrZeKhemVIM3pTU9urmbjq4kwqKOB8/BzTwYSNROiHoOIYfC/ rmMLbp4yB1BKu4pQzbhxFEaeMsZ8aiWN4hKNrqy9+OtC+ELOVAzNV/8nY0GoaTd2NZ12 mcw6FIfJyjW0Q6oGzdHgSJiluNpPgKkPoffqqOyXB2HX4CvuxAMPoeDuHvxxtdznykk4 HACA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=IbFarr6PyXbKMrUCcTktm6h/NoDAD0DUXRZ/zzxFCHg=; b=qc0PqXBQuURTgVLfI42rJDxIrrM9krYcvVAjjLTn351cWpaVX7JtX34NM74+lFMw/A d8JVjQ1MhP5BRW86zGw446t5xyvwX3FaY3bzPfvHA6gz3lcmx+ThscLbfaz89B3HiRYf L8Rw6NUgYlt6/lR5FejNVPVz6D1GLADIGty2xP2lWQu+Yy6C0oPMiAIuJYEUHFieEFRi leN0j6zJmhAxGJN2x2LqZx3v3MNrmcgDntI2nurHVI/+LkgbvHB5Fy4ECNUm3M0zVKBV TNzZiEl3dZ0BqqD6OWZqUnQpPG45Flklk3924y80nv0ykatMXJSXmEQkbKrF9swE9HXf z6eQ== X-Gm-Message-State: AOAM531NWusr1G55ObR2eqDxF8tU1rDKYJMcDB4A27oTMOYV9Xw6JLVO f6lQZK62a4EpaX4lj+czoMy9UyIVck9S2eq9zraBVffd1bJNA+SaAIDrNJ+x19y0TeXT6bhjf8L jZt8XxY00rN4++roEbSfMdhHL1ZnHxoCHRjwn3h9OhwG1cWwKtvlsibLIGOApbtT/r2Z50vrj2A == X-Google-Smtp-Source: ABdhPJwEwRWSR47sb6TfzBfRO0UftmfmmQnBJ94ZBT8lZ2y6zo7hpTEPKIYZzjc8kGK+NSnNmPmoaFqgW8yxRvRzMw== X-Received: by 2002:a17:90a:a68:: with SMTP id o95mr9195473pjo.64.1594965807212; Thu, 16 Jul 2020 23:03:27 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:53 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-9-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 08/13] hw/nvram: NPCM7xx OTP device model From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , Avi Fishman , " =?utf-8?q?Philippe_Mathieu-Daud?= =?utf-8?q?=C3=A9?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::64a; envelope-from=3Lz8RXwsKCvAZkcaffWegWfYggYdW.UgeiWem-VWnWdfgfYfm.gjY@flex--hskinnemoen.bounces.google.com; helo=mail-pl1-x64a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This supports reading and writing OTP fuses and keys. Only fuse reading has been tested. Protection is not implemented. Reviewed-by: Avi Fishman Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Havard Skinnemoen --- include/hw/arm/npcm7xx.h | 3 + include/hw/nvram/npcm7xx_otp.h | 88 +++++++ hw/arm/npcm7xx.c | 29 +++ hw/nvram/npcm7xx_otp.c | 424 +++++++++++++++++++++++++++++++++ hw/nvram/Makefile.objs | 1 + 5 files changed, 545 insertions(+) create mode 100644 include/hw/nvram/npcm7xx_otp.h create mode 100644 hw/nvram/npcm7xx_otp.c diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h index ba7495869d..5816a07a72 100644 --- a/include/hw/arm/npcm7xx.h +++ b/include/hw/arm/npcm7xx.h @@ -20,6 +20,7 @@ #include "hw/cpu/a9mpcore.h" #include "hw/misc/npcm7xx_clk.h" #include "hw/misc/npcm7xx_gcr.h" +#include "hw/nvram/npcm7xx_otp.h" #include "hw/timer/npcm7xx_timer.h" #include "target/arm/cpu.h" @@ -68,6 +69,8 @@ typedef struct NPCM7xxState { NPCM7xxGCRState gcr; NPCM7xxCLKState clk; NPCM7xxTimerCtrlState tim[3]; + NPCM7xxOTPState key_storage; + NPCM7xxOTPState fuse_array; } NPCM7xxState; #define TYPE_NPCM7XX "npcm7xx" diff --git a/include/hw/nvram/npcm7xx_otp.h b/include/hw/nvram/npcm7xx_otp.h new file mode 100644 index 0000000000..c4c1b751d4 --- /dev/null +++ b/include/hw/nvram/npcm7xx_otp.h @@ -0,0 +1,88 @@ +/* + * Nuvoton NPCM7xx OTP (Fuse Array) Interface + * + * Copyright 2020 Google LLC + * + * 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. + */ +#ifndef NPCM7XX_OTP_H +#define NPCM7XX_OTP_H + +#include "exec/memory.h" +#include "hw/sysbus.h" + +/* Each OTP module holds 8192 bits of one-time programmable storage */ +#define NPCM7XX_OTP_ARRAY_BITS (8192) +#define NPCM7XX_OTP_ARRAY_BYTES (NPCM7XX_OTP_ARRAY_BITS / BITS_PER_BYTE) + +/* Fuse array offsets */ +#define NPCM7XX_FUSE_FUSTRAP (0) +#define NPCM7XX_FUSE_CP_FUSTRAP (12) +#define NPCM7XX_FUSE_DAC_CALIB (16) +#define NPCM7XX_FUSE_ADC_CALIB (24) +#define NPCM7XX_FUSE_DERIVATIVE (64) +#define NPCM7XX_FUSE_TEST_SIG (72) +#define NPCM7XX_FUSE_DIE_LOCATION (74) +#define NPCM7XX_FUSE_GP1 (80) +#define NPCM7XX_FUSE_GP2 (128) + +/** + * enum NPCM7xxOTPRegister - 32-bit register indices. + */ +typedef enum NPCM7xxOTPRegister { + NPCM7XX_OTP_FST, + NPCM7XX_OTP_FADDR, + NPCM7XX_OTP_FDATA, + NPCM7XX_OTP_FCFG, + /* Offset 0x10 is FKEYIND in OTP1, FUSTRAP in OTP2 */ + NPCM7XX_OTP_FKEYIND = 0x0010 / sizeof(uint32_t), + NPCM7XX_OTP_FUSTRAP = 0x0010 / sizeof(uint32_t), + NPCM7XX_OTP_FCTL, + NPCM7XX_OTP_NR_REGS, +} NPCM7xxOTPRegister; + +/** + * struct NPCM7xxOTPState - Device state for one OTP module. + * @parent: System bus device. + * @mmio: Memory region through which registers are accessed. + * @regs: Register contents. + * @array: OTP storage array. + */ +typedef struct NPCM7xxOTPState { + SysBusDevice parent; + + MemoryRegion mmio; + uint32_t regs[NPCM7XX_OTP_NR_REGS]; + uint8_t array[NPCM7XX_OTP_ARRAY_BYTES]; +} NPCM7xxOTPState; + +#define TYPE_NPCM7XX_OTP "npcm7xx-otp" +#define NPCM7XX_OTP(obj) OBJECT_CHECK(NPCM7xxOTPState, (obj), TYPE_NPCM7XX_OTP) + +#define TYPE_NPCM7XX_KEY_STORAGE "npcm7xx-key-storage" +#define TYPE_NPCM7XX_FUSE_ARRAY "npcm7xx-fuse-array" + +typedef struct NPCM7xxOTPClass NPCM7xxOTPClass; + +/** + * npcm7xx_otp_array_write - ECC encode and write data to OTP array. + * @s: OTP module. + * @data: Data to be encoded and written. + * @offset: Offset of first byte to be written in the OTP array. + * @len: Number of bytes before ECC encoding. + * + * Each nibble of data is encoded into a byte, so the number of bytes written + * to the array will be @len * 2. + */ +extern void npcm7xx_otp_array_write(NPCM7xxOTPState *s, const void *data, + unsigned int offset, unsigned int len); + +#endif /* NPCM7XX_OTP_H */ diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index 9669ac5fa0..9166002598 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -34,6 +34,10 @@ #define NPCM7XX_MMIO_BA (0x80000000) #define NPCM7XX_MMIO_SZ (0x7ffd0000) +/* OTP key storage and fuse strap array */ +#define NPCM7XX_OTP1_BA (0xf0189000) +#define NPCM7XX_OTP2_BA (0xf018a000) + /* Core system modules. */ #define NPCM7XX_L2C_BA (0xf03fc000) #define NPCM7XX_CPUP_BA (0xf03fe000) @@ -144,6 +148,20 @@ void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc) arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo); } +static void npcm7xx_init_fuses(NPCM7xxState *s) +{ + NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s); + uint32_t value; + + /* + * The initial mask of disabled modules indicates the chip derivative (e.g. + * NPCM750 or NPCM730). + */ + value = tswap32(nc->disabled_modules); + npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE, + sizeof(value)); +} + static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n) { return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n); @@ -164,6 +182,10 @@ static void npcm7xx_init(Object *obj) object_property_add_alias(obj, "power-on-straps", OBJECT(&s->gcr), "power-on-straps"); object_initialize_child(obj, "clk", &s->clk, TYPE_NPCM7XX_CLK); + object_initialize_child(obj, "otp1", &s->key_storage, + TYPE_NPCM7XX_KEY_STORAGE); + object_initialize_child(obj, "otp2", &s->fuse_array, + TYPE_NPCM7XX_FUSE_ARRAY); for (i = 0; i < ARRAY_SIZE(s->tim); i++) { object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER); @@ -232,6 +254,13 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->clk), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM7XX_CLK_BA); + /* OTP key storage and fuse strap array. Cannot fail. */ + sysbus_realize(SYS_BUS_DEVICE(&s->key_storage), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->key_storage), 0, NPCM7XX_OTP1_BA); + sysbus_realize(SYS_BUS_DEVICE(&s->fuse_array), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->fuse_array), 0, NPCM7XX_OTP2_BA); + npcm7xx_init_fuses(s); + /* Timer Modules (TIM). Cannot fail. */ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim)); for (i = 0; i < ARRAY_SIZE(s->tim); i++) { diff --git a/hw/nvram/npcm7xx_otp.c b/hw/nvram/npcm7xx_otp.c new file mode 100644 index 0000000000..b67d69fdf9 --- /dev/null +++ b/hw/nvram/npcm7xx_otp.c @@ -0,0 +1,424 @@ +/* + * Nuvoton NPCM7xx OTP (Fuse Array) Interface + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/nvram/npcm7xx_otp.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" + +/* Each module has 4 KiB of register space. Only a fraction of it is used. */ +#define NPCM7XX_OTP_REGS_SIZE (4 * KiB) + +/* Register field definitions. */ +#define FST_RIEN BIT(2) +#define FST_RDST BIT(1) +#define FST_RDY BIT(0) +#define FST_RO_MASK (FST_RDST | FST_RDY) + +#define FADDR_BYTEADDR(rv) extract32((rv), 0, 10) +#define FADDR_BITPOS(rv) extract32((rv), 10, 3) + +#define FDATA_CLEAR 0x00000001 + +#define FCFG_FDIS BIT(31) +#define FCFG_FCFGLK_MASK 0x00ff0000 + +#define FCTL_PROG_CMD1 0x00000001 +#define FCTL_PROG_CMD2 0xbf79e5d0 +#define FCTL_READ_CMD 0x00000002 + +/** + * struct NPCM7xxOTPClass - OTP module class. + * @parent: System bus device class. + * @mmio_ops: MMIO register operations for this type of module. + * + * The two OTP modules (key-storage and fuse-array) have slightly different + * behavior, so we give them different MMIO register operations. + */ +struct NPCM7xxOTPClass { + SysBusDeviceClass parent; + + const MemoryRegionOps *mmio_ops; +}; + +#define NPCM7XX_OTP_CLASS(klass) \ + OBJECT_CLASS_CHECK(NPCM7xxOTPClass, (klass), TYPE_NPCM7XX_OTP) +#define NPCM7XX_OTP_GET_CLASS(obj) \ + OBJECT_GET_CLASS(NPCM7xxOTPClass, (obj), TYPE_NPCM7XX_OTP) + +static uint8_t ecc_encode_nibble(uint8_t n) +{ + uint8_t result = n; + + result |= (((n >> 0) & 1) ^ ((n >> 1) & 1)) << 4; + result |= (((n >> 2) & 1) ^ ((n >> 3) & 1)) << 5; + result |= (((n >> 0) & 1) ^ ((n >> 2) & 1)) << 6; + result |= (((n >> 1) & 1) ^ ((n >> 3) & 1)) << 7; + + return result; +} + +void npcm7xx_otp_array_write(NPCM7xxOTPState *s, const void *data, + unsigned int offset, unsigned int len) +{ + const uint8_t *src = data; + uint8_t *dst = &s->array[offset]; + + while (len-- > 0) { + uint8_t c = *src++; + + *dst++ = ecc_encode_nibble(extract8(c, 0, 4)); + *dst++ = ecc_encode_nibble(extract8(c, 4, 4)); + } +} + +/* Common register read handler for both OTP classes. */ +static uint64_t npcm7xx_otp_read(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg) +{ + uint32_t value = 0; + + switch (reg) { + case NPCM7XX_OTP_FST: + case NPCM7XX_OTP_FADDR: + case NPCM7XX_OTP_FDATA: + case NPCM7XX_OTP_FCFG: + value = s->regs[reg]; + break; + + case NPCM7XX_OTP_FCTL: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: read from write-only FCTL register\n", + DEVICE(s)->canonical_path); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: read from invalid offset 0x%zx\n", + DEVICE(s)->canonical_path, reg * sizeof(uint32_t)); + break; + } + + return value; +} + +/* Read a byte from the OTP array into the data register. */ +static void npcm7xx_otp_read_array(NPCM7xxOTPState *s) +{ + uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR]; + + s->regs[NPCM7XX_OTP_FDATA] = s->array[FADDR_BYTEADDR(faddr)]; + s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY; +} + +/* Program a byte from the data register into the OTP array. */ +static void npcm7xx_otp_program_array(NPCM7xxOTPState *s) +{ + uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR]; + + /* Bits can only go 0->1, never 1->0. */ + s->array[FADDR_BYTEADDR(faddr)] |= (1U << FADDR_BITPOS(faddr)); + s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY; +} + +/* Compute the next value of the FCFG register. */ +static uint32_t npcm7xx_otp_compute_fcfg(uint32_t cur_value, uint32_t new_value) +{ + uint32_t lock_mask; + uint32_t value; + + /* + * FCFGLK holds sticky bits 16..23, indicating which bits in FPRGLK (8..15) + * and FRDLK (0..7) that are read-only. + */ + lock_mask = (cur_value & FCFG_FCFGLK_MASK) >> 8; + lock_mask |= lock_mask >> 8; + /* FDIS and FCFGLK bits are sticky (write 1 to set; can't clear). */ + value = cur_value & (FCFG_FDIS | FCFG_FCFGLK_MASK); + /* Preserve read-only bits in FPRGLK and FRDLK */ + value |= cur_value & lock_mask; + /* Set all bits that aren't read-only. */ + value |= new_value & ~lock_mask; + + return value; +} + +/* Common register write handler for both OTP classes. */ +static void npcm7xx_otp_write(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg, + uint32_t value) +{ + switch (reg) { + case NPCM7XX_OTP_FST: + /* RDST is cleared by writing 1 to it. */ + if (value & FST_RDST) { + s->regs[NPCM7XX_OTP_FST] &= ~FST_RDST; + } + /* Preserve read-only and write-one-to-clear bits */ + value &= ~FST_RO_MASK; + value |= s->regs[NPCM7XX_OTP_FST] & FST_RO_MASK; + break; + + case NPCM7XX_OTP_FADDR: + break; + + case NPCM7XX_OTP_FDATA: + /* + * This register is cleared by writing a magic value to it; no other + * values can be written. + */ + if (value == FDATA_CLEAR) { + value = 0; + } else { + value = s->regs[NPCM7XX_OTP_FDATA]; + } + break; + + case NPCM7XX_OTP_FCFG: + value = npcm7xx_otp_compute_fcfg(s->regs[NPCM7XX_OTP_FCFG], value); + break; + + case NPCM7XX_OTP_FCTL: + switch (value) { + case FCTL_READ_CMD: + npcm7xx_otp_read_array(s); + break; + + case FCTL_PROG_CMD1: + /* + * Programming requires writing two separate magic values to this + * register; this is the first one. Just store it so it can be + * verified later when the second magic value is received. + */ + break; + + case FCTL_PROG_CMD2: + /* + * Only initiate programming if we received the first half of the + * command immediately before this one. + */ + if (s->regs[NPCM7XX_OTP_FCTL] == FCTL_PROG_CMD1) { + npcm7xx_otp_program_array(s); + } + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: unrecognized FCNTL value 0x%" PRIx32 "\n", + DEVICE(s)->canonical_path, value); + break; + } + if (value != FCTL_PROG_CMD1) { + value = 0; + } + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: write to invalid offset 0x%zx\n", + DEVICE(s)->canonical_path, reg * sizeof(uint32_t)); + return; + } + + s->regs[reg] = value; +} + +/* Register read handler specific to the fuse array OTP module. */ +static uint64_t npcm7xx_fuse_array_read(void *opaque, hwaddr addr, + unsigned int size) +{ + NPCM7xxOTPRegister reg = addr / sizeof(uint32_t); + NPCM7xxOTPState *s = opaque; + uint32_t value; + + /* + * Only the Fuse Strap register needs special handling; all other registers + * work the same way for both kinds of OTP modules. + */ + if (reg != NPCM7XX_OTP_FUSTRAP) { + value = npcm7xx_otp_read(s, reg); + } else { + /* FUSTRAP is stored as three copies in the OTP array. */ + uint32_t fustrap[3]; + + memcpy(fustrap, &s->array[0], sizeof(fustrap)); + + /* Determine value by a majority vote on each bit. */ + value = (fustrap[0] & fustrap[1]) | (fustrap[0] & fustrap[2]) | + (fustrap[1] & fustrap[2]); + } + + return value; +} + +/* Register write handler specific to the fuse array OTP module. */ +static void npcm7xx_fuse_array_write(void *opaque, hwaddr addr, uint64_t v, + unsigned int size) +{ + NPCM7xxOTPRegister reg = addr / sizeof(uint32_t); + NPCM7xxOTPState *s = opaque; + + /* + * The Fuse Strap register is read-only. Other registers are handled by + * common code. + */ + if (reg != NPCM7XX_OTP_FUSTRAP) { + npcm7xx_otp_write(s, reg, v); + } +} + +static const MemoryRegionOps npcm7xx_fuse_array_ops = { + .read = npcm7xx_fuse_array_read, + .write = npcm7xx_fuse_array_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +/* Register read handler specific to the key storage OTP module. */ +static uint64_t npcm7xx_key_storage_read(void *opaque, hwaddr addr, + unsigned int size) +{ + NPCM7xxOTPRegister reg = addr / sizeof(uint32_t); + NPCM7xxOTPState *s = opaque; + + /* + * Only the Fuse Key Index register needs special handling; all other + * registers work the same way for both kinds of OTP modules. + */ + if (reg != NPCM7XX_OTP_FKEYIND) { + return npcm7xx_otp_read(s, reg); + } + + qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__); + + return s->regs[NPCM7XX_OTP_FKEYIND]; +} + +/* Register write handler specific to the key storage OTP module. */ +static void npcm7xx_key_storage_write(void *opaque, hwaddr addr, uint64_t v, + unsigned int size) +{ + NPCM7xxOTPRegister reg = addr / sizeof(uint32_t); + NPCM7xxOTPState *s = opaque; + + /* + * Only the Fuse Key Index register needs special handling; all other + * registers work the same way for both kinds of OTP modules. + */ + if (reg != NPCM7XX_OTP_FKEYIND) { + npcm7xx_otp_write(s, reg, v); + return; + } + + qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__); + + s->regs[NPCM7XX_OTP_FKEYIND] = v; +} + +static const MemoryRegionOps npcm7xx_key_storage_ops = { + .read = npcm7xx_key_storage_read, + .write = npcm7xx_key_storage_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void npcm7xx_otp_enter_reset(Object *obj, ResetType type) +{ + NPCM7xxOTPState *s = NPCM7XX_OTP(obj); + + memset(s->regs, 0, sizeof(s->regs)); + + s->regs[NPCM7XX_OTP_FST] = 0x00000001; + s->regs[NPCM7XX_OTP_FCFG] = 0x20000000; +} + +static void npcm7xx_otp_realize(DeviceState *dev, Error **errp) +{ + NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev); + NPCM7xxOTPState *s = NPCM7XX_OTP(dev); + SysBusDevice *sbd = &s->parent; + + memset(s->array, 0, sizeof(s->array)); + + memory_region_init_io(&s->mmio, OBJECT(s), oc->mmio_ops, s, "regs", + NPCM7XX_OTP_REGS_SIZE); + sysbus_init_mmio(sbd, &s->mmio); +} + +static const VMStateDescription vmstate_npcm7xx_otp = { + .name = "npcm7xx-otp", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, NPCM7xxOTPState, NPCM7XX_OTP_NR_REGS), + VMSTATE_UINT8_ARRAY(array, NPCM7xxOTPState, NPCM7XX_OTP_ARRAY_BYTES), + VMSTATE_END_OF_LIST(), + }, +}; + +static void npcm7xx_otp_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = npcm7xx_otp_realize; + dc->vmsd = &vmstate_npcm7xx_otp; + rc->phases.enter = npcm7xx_otp_enter_reset; +} + +static void npcm7xx_key_storage_class_init(ObjectClass *klass, void *data) +{ + NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass); + + oc->mmio_ops = &npcm7xx_key_storage_ops; +} + +static void npcm7xx_fuse_array_class_init(ObjectClass *klass, void *data) +{ + NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass); + + oc->mmio_ops = &npcm7xx_fuse_array_ops; +} + +static const TypeInfo npcm7xx_otp_types[] = { + { + .name = TYPE_NPCM7XX_OTP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCM7xxOTPState), + .class_init = npcm7xx_otp_class_init, + .abstract = true, + }, + { + .name = TYPE_NPCM7XX_KEY_STORAGE, + .parent = TYPE_NPCM7XX_OTP, + .class_init = npcm7xx_key_storage_class_init, + }, + { + .name = TYPE_NPCM7XX_FUSE_ARRAY, + .parent = TYPE_NPCM7XX_OTP, + .class_init = npcm7xx_fuse_array_class_init, + }, +}; +DEFINE_TYPES(npcm7xx_otp_types); diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs index f3ad921382..0270f0bbf7 100644 --- a/hw/nvram/Makefile.objs +++ b/hw/nvram/Makefile.objs @@ -4,5 +4,6 @@ common-obj-$(CONFIG_AT24C) += eeprom_at24c.o common-obj-y += fw_cfg.o common-obj-$(CONFIG_CHRP_NVRAM) += chrp_nvram.o common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_otp.o common-obj-$(CONFIG_NRF51_SOC) += nrf51_nvm.o obj-$(CONFIG_PSERIES) += spapr_nvram.o From patchwork Fri Jul 17 06:02:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669021 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2472013B6 for ; Fri, 17 Jul 2020 06:05:29 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EAE67206BE for ; Fri, 17 Jul 2020 06:05:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="jwV7ZMBT" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EAE67206BE Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:38620 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJUu-0006ka-6s for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:05:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60210) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3MT8RXwsKCvIbmechhYgiYhaiiafY.WigkYgo-XYpYfhihaho.ila@flex--hskinnemoen.bounces.google.com>) id 1jwJT6-0003o8-3h for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:36 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:44370) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3MT8RXwsKCvIbmechhYgiYhaiiafY.WigkYgo-XYpYfhihaho.ila@flex--hskinnemoen.bounces.google.com>) id 1jwJT0-0005Hz-Sc for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:35 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id k127so10090024ybk.11 for ; Thu, 16 Jul 2020 23:03:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=qsJ/ZygQks0Y4Kmg+GGXR1DhNMa+QMME0tEXCYJ4szY=; b=jwV7ZMBT38HSfoR6RyJXkKLqUiW2k59B6qiAZ/Wc2FP9Im3sUKAHSVJ/1jyPp+7dCE zl2a82+k8Yk7fGI+CmD7CKNl6rMt41wMoK61NDz17nH3ks9dE9IKWnUiCdQ7LPJ765s0 qiI1R/ePjTzbTEx4+qA+lKXo59rPr7YHhcdPoK9+4zkgvVbld7IycnqHTjj2iHTG72dF jt30rhdwd3EUiOt16qwrHP+rpyoEx6RbR+ygH741Tf2cc1nL66q6Rj1daAzGwSmaKU7U U7ACyFVhKR1mQN2jhqtieufeCqC6lSqF2liCI26dABDTZhUzkglFoDPmKppPdseyxVEw 9G/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=qsJ/ZygQks0Y4Kmg+GGXR1DhNMa+QMME0tEXCYJ4szY=; b=fL7WVVAd079qZL9C2RJM+FDBxrhX5VMYvBt7zAgapo3IJAhEEb/THDnhX2LA+BLgAt XrF0EP66y7m3e7RL+RxnEdH0VP4bdixhdOl5NBb4yNIdjNucBb7UV5LB5Jcucbcxjhpk Y69vxfMTlK7JGjDh3I8k50elQyTKwvUMHkjUquToEEm3DFrHr5B1cy2HhIudPqJDtbB6 eAezs5MB3wqnxvqS3y/mwum6swFgNRSYhnUghCkIb3vBUmWC5wLkcjwzir9GU7CbCPPJ SXd5nrpEgEMID6FlLQmr5IeqAFTK192E4vbcNN61WXo9rF4pLrpvkc+hc3iruczDo2XH BpEw== X-Gm-Message-State: AOAM532qgobeRdXDjzB+dhXOyMXqMXoxkqIMenJPosnjLyr2jqY6Tpqp N10CHr8JN+PlWHcXjV6GDgjf5XO6LtUive2SUQXvfTrDNNHCt6vc1jTgU0T2NFeZZ2/jejwHzNE rY+1CwnpHyKNbZs6XJbzXIDM/PDKsTOqkFxyc3kHW5o0cn7eeRxtpamab4MQiInIc2G6uJsckjg == X-Google-Smtp-Source: ABdhPJxumLxMHVs5MLxMWUIoXljRjVWPCEtSsK6L2roFCiGFN3CTrLEZmKm/m1glQh0KBUszRcKW/p05Y68NVqppow== X-Received: by 2002:a25:3788:: with SMTP id e130mr12380185yba.372.1594965809220; Thu, 16 Jul 2020 23:03:29 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:54 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-10-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 09/13] hw/mem: Stubbed out NPCM7xx Memory Controller model From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , " =?utf-8?q?C=C3=A9dric_Le_Go?= =?utf-8?q?ater?= " , " =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3MT8RXwsKCvIbmechhYgiYhaiiafY.WigkYgo-XYpYfhihaho.ila@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This just implements the bare minimum to cause the boot block to skip memory initialization. Reviewed-by: Tyrone Ting Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Havard Skinnemoen --- include/hw/arm/npcm7xx.h | 2 + include/hw/mem/npcm7xx_mc.h | 36 ++++++++++++++++ hw/arm/npcm7xx.c | 6 +++ hw/mem/npcm7xx_mc.c | 84 +++++++++++++++++++++++++++++++++++++ hw/mem/Makefile.objs | 1 + 5 files changed, 129 insertions(+) create mode 100644 include/hw/mem/npcm7xx_mc.h create mode 100644 hw/mem/npcm7xx_mc.c diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h index 5816a07a72..9fa84a0702 100644 --- a/include/hw/arm/npcm7xx.h +++ b/include/hw/arm/npcm7xx.h @@ -18,6 +18,7 @@ #include "hw/boards.h" #include "hw/cpu/a9mpcore.h" +#include "hw/mem/npcm7xx_mc.h" #include "hw/misc/npcm7xx_clk.h" #include "hw/misc/npcm7xx_gcr.h" #include "hw/nvram/npcm7xx_otp.h" @@ -71,6 +72,7 @@ typedef struct NPCM7xxState { NPCM7xxTimerCtrlState tim[3]; NPCM7xxOTPState key_storage; NPCM7xxOTPState fuse_array; + NPCM7xxMCState mc; } NPCM7xxState; #define TYPE_NPCM7XX "npcm7xx" diff --git a/include/hw/mem/npcm7xx_mc.h b/include/hw/mem/npcm7xx_mc.h new file mode 100644 index 0000000000..7ed38be243 --- /dev/null +++ b/include/hw/mem/npcm7xx_mc.h @@ -0,0 +1,36 @@ +/* + * Nuvoton NPCM7xx Memory Controller stub + * + * Copyright 2020 Google LLC + * + * 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. + */ +#ifndef NPCM7XX_MC_H +#define NPCM7XX_MC_H + +#include "exec/memory.h" +#include "hw/sysbus.h" + +/** + * struct NPCM7xxMCState - Device state for the memory controller. + * @parent: System bus device. + * @mmio: Memory region through which registers are accessed. + */ +typedef struct NPCM7xxMCState { + SysBusDevice parent; + + MemoryRegion mmio; +} NPCM7xxMCState; + +#define TYPE_NPCM7XX_MC "npcm7xx-mc" +#define NPCM7XX_MC(obj) OBJECT_CHECK(NPCM7xxMCState, (obj), TYPE_NPCM7XX_MC) + +#endif /* NPCM7XX_MC_H */ diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index 9166002598..6bb1693833 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -43,6 +43,7 @@ #define NPCM7XX_CPUP_BA (0xf03fe000) #define NPCM7XX_GCR_BA (0xf0800000) #define NPCM7XX_CLK_BA (0xf0801000) +#define NPCM7XX_MC_BA (0xf0824000) /* Internal AHB SRAM */ #define NPCM7XX_RAM3_BA (0xc0008000) @@ -186,6 +187,7 @@ static void npcm7xx_init(Object *obj) TYPE_NPCM7XX_KEY_STORAGE); object_initialize_child(obj, "otp2", &s->fuse_array, TYPE_NPCM7XX_FUSE_ARRAY); + object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC); for (i = 0; i < ARRAY_SIZE(s->tim); i++) { object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER); @@ -261,6 +263,10 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->fuse_array), 0, NPCM7XX_OTP2_BA); npcm7xx_init_fuses(s); + /* Fake Memory Controller (MC). Cannot fail. */ + sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA); + /* Timer Modules (TIM). Cannot fail. */ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim)); for (i = 0; i < ARRAY_SIZE(s->tim); i++) { diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c new file mode 100644 index 0000000000..0435d06ab4 --- /dev/null +++ b/hw/mem/npcm7xx_mc.c @@ -0,0 +1,84 @@ +/* + * Nuvoton NPCM7xx Memory Controller stub + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/mem/npcm7xx_mc.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" + +#define NPCM7XX_MC_REGS_SIZE (4 * KiB) + +static uint64_t npcm7xx_mc_read(void *opaque, hwaddr addr, unsigned int size) +{ + /* + * If bits 8..11 @ offset 0 are not zero, the boot block thinks the memory + * controller has already been initialized and will skip DDR training. + */ + if (addr == 0) { + return 0x100; + } + + qemu_log_mask(LOG_UNIMP, "%s: mostly unimplemented\n", __func__); + + return 0; +} + +static void npcm7xx_mc_write(void *opaque, hwaddr addr, uint64_t v, + unsigned int size) +{ + qemu_log_mask(LOG_UNIMP, "%s: mostly unimplemented\n", __func__); +} + +static const MemoryRegionOps npcm7xx_mc_ops = { + .read = npcm7xx_mc_read, + .write = npcm7xx_mc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void npcm7xx_mc_realize(DeviceState *dev, Error **errp) +{ + NPCM7xxMCState *s = NPCM7XX_MC(dev); + + memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs", + NPCM7XX_MC_REGS_SIZE); + sysbus_init_mmio(&s->parent, &s->mmio); +} + +static void npcm7xx_mc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "NPCM7xx Memory Controller stub"; + dc->realize = npcm7xx_mc_realize; +} + +static const TypeInfo npcm7xx_mc_types[] = { + { + .name = TYPE_NPCM7XX_MC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCM7xxMCState), + .class_init = npcm7xx_mc_class_init, + }, +}; +DEFINE_TYPES(npcm7xx_mc_types); diff --git a/hw/mem/Makefile.objs b/hw/mem/Makefile.objs index 56345befd0..9a33ef7b35 100644 --- a/hw/mem/Makefile.objs +++ b/hw/mem/Makefile.objs @@ -1,3 +1,4 @@ common-obj-$(CONFIG_DIMM) += pc-dimm.o common-obj-y += memory-device.o +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_mc.o common-obj-$(CONFIG_NVDIMM) += nvdimm.o From patchwork Fri Jul 17 06:02:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669029 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CE04F138C for ; Fri, 17 Jul 2020 06:07:31 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 93207206BE for ; Fri, 17 Jul 2020 06:07:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="IQn6LB/1" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 93207206BE Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:47096 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJWs-0001nV-SM for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:07:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60270) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3Mz8RXwsKCvQdogejjaikajckkcha.Ykimaiq-Zarahjkjcjq.knc@flex--hskinnemoen.bounces.google.com>) id 1jwJT9-0003uO-Lj for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:39 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:50718) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3Mz8RXwsKCvQdogejjaikajckkcha.Ykimaiq-Zarahjkjcjq.knc@flex--hskinnemoen.bounces.google.com>) id 1jwJT4-0005IR-Is for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:39 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id u189so10076816ybg.17 for ; Thu, 16 Jul 2020 23:03:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=JQUK9TNkxeOK9tuhzefguiCLkOl8X0/nez0rlaFDFlc=; b=IQn6LB/1tvIQ1+dIHUaxd0NqzZo2ndHQ1x8FkML8h3c09QkPJ3wsxadvoAIpTMyaRh fSoqY481Q4T+Eprs24dRSWTxqsuPZSEHrrD6EqrYbMyhq5N9vkkRGqDOLcD3vl4+tzj7 wmx/3SupsmnA/U7cKeNDDHsD2KNu21opEJYSxxQdOZziVFxrD9/nz30JrIPsg/nVSnef HJmIcR/pqaXmMbujw2pVbVrasc7T1WtKmKZxOXOeXRM50fB44WOQ/KxN5gStqZs4tt75 8UAbykzJXEB8krTlMzQD5HP52b2hselntkVz95jybKHm1No0NspMdqMOIVV6LZnpHpwD Laig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=JQUK9TNkxeOK9tuhzefguiCLkOl8X0/nez0rlaFDFlc=; b=KqmNzmf1BEtYJTaXxo515ECZ09Po6+UTDQTZbJn/9NVwv7J1RqjjuQHrCJmbkft0o6 FPdofr0NMqnaBaV+6lXsf88XYgYfdLbY5uslYZnjdvLmgpMlrugkjDkYKHyeAq9pKKAY Z+k7EALWVbxDE7sRmsATRJimCzyOhm/WQgAM4737YRcg0RUjftGlDFtoR96vhTvCLU9E KfqM7xTS3nS2QF0Fblc41b9SQGFdAplO6Ff9PUnprQXn8wvqtz66T0zmsBKuKzm61S5a +9NO0IPwxkSAIJ96mWxk5xWp6BKM34yiSvHuAzht+iPpbLZ2Pheopnnh1P36/2zJ0rX7 R+jg== X-Gm-Message-State: AOAM530cxkX5Q1i+wyEnici6lMmCud6SvGTX4CDq80C6s1d5SSKQTzFr l4xKsgJ3SCqqY2PuSae2Vu51xAH/JxAPB9kApwsNKydGfnBMAKsS1PsVkmDqH9DP+POZUROfR/Q jKMX9y8pQ6ogwLKRXwfgT//b+/tQ+LNV63ylWgS0MjEeyMTtG5Eh9RKtHn7WKh+aF1BaT/wvZoA == X-Google-Smtp-Source: ABdhPJxW3oo0GmrUknjmv1rF+X0wl70J7Mo2srKmgL9p//+2Kk9WHzYEpkt3CTxtb5W2agbONBTtGgPF+peeFFJrEA== X-Received: by 2002:a5b:1c4:: with SMTP id f4mr12437127ybp.472.1594965811636; Thu, 16 Jul 2020 23:03:31 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:55 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-11-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 10/13] hw/ssi: NPCM7xx Flash Interface Unit device model From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , " =?utf-8?q?C=C3=A9dric_Le_Go?= =?utf-8?q?ater?= " , " =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3Mz8RXwsKCvQdogejjaikajckkcha.Ykimaiq-Zarahjkjcjq.knc@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This implements a device model for the NPCM7xx SPI flash controller. Direct reads and writes, and user-mode transactions have been tested in various modes. Protection features are not implemented yet. All the FIU instances are available in the SoC's address space, regardless of whether or not they're connected to actual flash chips. Reviewed-by: Tyrone Ting Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Havard Skinnemoen --- include/hw/arm/npcm7xx.h | 2 + include/hw/ssi/npcm7xx_fiu.h | 100 +++++++ hw/arm/npcm7xx.c | 58 ++++ hw/ssi/npcm7xx_fiu.c | 539 +++++++++++++++++++++++++++++++++++ hw/arm/Kconfig | 1 + hw/ssi/Makefile.objs | 1 + hw/ssi/trace-events | 11 + 7 files changed, 712 insertions(+) create mode 100644 include/hw/ssi/npcm7xx_fiu.h create mode 100644 hw/ssi/npcm7xx_fiu.c diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h index 9fa84a0702..78d0d78c52 100644 --- a/include/hw/arm/npcm7xx.h +++ b/include/hw/arm/npcm7xx.h @@ -23,6 +23,7 @@ #include "hw/misc/npcm7xx_gcr.h" #include "hw/nvram/npcm7xx_otp.h" #include "hw/timer/npcm7xx_timer.h" +#include "hw/ssi/npcm7xx_fiu.h" #include "target/arm/cpu.h" #define NPCM7XX_MAX_NUM_CPUS (2) @@ -73,6 +74,7 @@ typedef struct NPCM7xxState { NPCM7xxOTPState key_storage; NPCM7xxOTPState fuse_array; NPCM7xxMCState mc; + NPCM7xxFIUState fiu[2]; } NPCM7xxState; #define TYPE_NPCM7XX "npcm7xx" diff --git a/include/hw/ssi/npcm7xx_fiu.h b/include/hw/ssi/npcm7xx_fiu.h new file mode 100644 index 0000000000..b867bd0429 --- /dev/null +++ b/include/hw/ssi/npcm7xx_fiu.h @@ -0,0 +1,100 @@ +/* + * Nuvoton NPCM7xx Flash Interface Unit (FIU) + * + * Copyright 2020 Google LLC + * + * 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. + */ +#ifndef NPCM7XX_FIU_H +#define NPCM7XX_FIU_H + +#include "hw/ssi/ssi.h" +#include "hw/sysbus.h" + +/** + * enum NPCM7xxFIURegister - 32-bit FIU register indices. + */ +enum NPCM7xxFIURegister { + NPCM7XX_FIU_DRD_CFG, + NPCM7XX_FIU_DWR_CFG, + NPCM7XX_FIU_UMA_CFG, + NPCM7XX_FIU_UMA_CTS, + NPCM7XX_FIU_UMA_CMD, + NPCM7XX_FIU_UMA_ADDR, + NPCM7XX_FIU_PRT_CFG, + NPCM7XX_FIU_UMA_DW0 = 0x0020 / sizeof(uint32_t), + NPCM7XX_FIU_UMA_DW1, + NPCM7XX_FIU_UMA_DW2, + NPCM7XX_FIU_UMA_DW3, + NPCM7XX_FIU_UMA_DR0, + NPCM7XX_FIU_UMA_DR1, + NPCM7XX_FIU_UMA_DR2, + NPCM7XX_FIU_UMA_DR3, + NPCM7XX_FIU_PRT_CMD0, + NPCM7XX_FIU_PRT_CMD1, + NPCM7XX_FIU_PRT_CMD2, + NPCM7XX_FIU_PRT_CMD3, + NPCM7XX_FIU_PRT_CMD4, + NPCM7XX_FIU_PRT_CMD5, + NPCM7XX_FIU_PRT_CMD6, + NPCM7XX_FIU_PRT_CMD7, + NPCM7XX_FIU_PRT_CMD8, + NPCM7XX_FIU_PRT_CMD9, + NPCM7XX_FIU_CFG = 0x78 / sizeof(uint32_t), + NPCM7XX_FIU_NR_REGS, +}; + +typedef struct NPCM7xxFIUState NPCM7xxFIUState; + +/** + * struct NPCM7xxFIUFlash - Per-chipselect flash controller state. + * @direct_access: Memory region for direct flash access. + * @fiu: Pointer to flash controller shared state. + */ +typedef struct NPCM7xxFIUFlash { + MemoryRegion direct_access; + NPCM7xxFIUState *fiu; +} NPCM7xxFIUFlash; + +/** + * NPCM7xxFIUState - Device state for one Flash Interface Unit. + * @parent: System bus device. + * @mmio: Memory region for register access. + * @cs_count: Number of flash chips that may be connected to this module. + * @active_cs: Currently active chip select, or -1 if no chip is selected. + * @cs_lines: GPIO lines that may be wired to flash chips. + * @flash: Array of @cs_count per-flash-chip state objects. + * @spi: The SPI bus mastered by this controller. + * @regs: Register contents. + * + * Each FIU has a shared bank of registers, and controls up to four chip + * selects. Each chip select has a dedicated memory region which may be used to + * read and write the flash connected to that chip select as if it were memory. + */ +struct NPCM7xxFIUState { + SysBusDevice parent; + + MemoryRegion mmio; + + int32_t cs_count; + int32_t active_cs; + qemu_irq *cs_lines; + NPCM7xxFIUFlash *flash; + + SSIBus *spi; + + uint32_t regs[NPCM7XX_FIU_NR_REGS]; +}; + +#define TYPE_NPCM7XX_FIU "npcm7xx-fiu" +#define NPCM7XX_FIU(obj) OBJECT_CHECK(NPCM7xxFIUState, (obj), TYPE_NPCM7XX_FIU) + +#endif /* NPCM7XX_FIU_H */ diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index 6bb1693833..7884b2b03d 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -99,6 +99,39 @@ static const hwaddr npcm7xx_uart_addr[] = { 0xf0004000, }; +/* Direct memory-mapped access to SPI0 CS0-1. */ +static const hwaddr npcm7xx_fiu0_flash_addr[] = { + 0x80000000, /* CS0 */ + 0x88000000, /* CS1 */ +}; + +/* Direct memory-mapped access to SPI3 CS0-3. */ +static const hwaddr npcm7xx_fiu3_flash_addr[] = { + 0xa0000000, /* CS0 */ + 0xa8000000, /* CS1 */ + 0xb0000000, /* CS2 */ + 0xb8000000, /* CS3 */ +}; + +static const struct { + const char *name; + hwaddr regs_addr; + int cs_count; + const hwaddr *flash_addr; +} npcm7xx_fiu[] = { + { + .name = "fiu0", + .regs_addr = 0xfb000000, + .cs_count = ARRAY_SIZE(npcm7xx_fiu0_flash_addr), + .flash_addr = npcm7xx_fiu0_flash_addr, + }, { + .name = "fiu3", + .regs_addr = 0xc0000000, + .cs_count = ARRAY_SIZE(npcm7xx_fiu3_flash_addr), + .flash_addr = npcm7xx_fiu3_flash_addr, + }, +}; + static void npcm7xx_write_secondary_boot(ARMCPU *cpu, const struct arm_boot_info *info) { @@ -192,6 +225,12 @@ static void npcm7xx_init(Object *obj) for (i = 0; i < ARRAY_SIZE(s->tim); i++) { object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER); } + + QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu)); + for (i = 0; i < ARRAY_SIZE(s->fiu); i++) { + object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i], + TYPE_NPCM7XX_FIU); + } } static void npcm7xx_realize(DeviceState *dev, Error **errp) @@ -291,6 +330,25 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) serial_hd(i), DEVICE_LITTLE_ENDIAN); } + /* + * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects + * specified, but this is a programming error. + */ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu)); + for (i = 0; i < ARRAY_SIZE(s->fiu); i++) { + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->fiu[i]); + int j; + + object_property_set_int(OBJECT(sbd), "cs-count", + npcm7xx_fiu[i].cs_count, &error_abort); + sysbus_realize(sbd, &error_abort); + + sysbus_mmio_map(sbd, 0, npcm7xx_fiu[i].regs_addr); + for (j = 0; j < npcm7xx_fiu[i].cs_count; j++) { + sysbus_mmio_map(sbd, j + 1, npcm7xx_fiu[i].flash_addr[j]); + } + } + /* RAM2 (SRAM) */ memory_region_init_ram(&s->sram, OBJECT(dev), "ram2", NPCM7XX_RAM2_SZ, &error_abort); diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c new file mode 100644 index 0000000000..f1677da160 --- /dev/null +++ b/hw/ssi/npcm7xx_fiu.c @@ -0,0 +1,539 @@ +/* + * Nuvoton NPCM7xx Flash Interface Unit (FIU) + * + * Copyright 2020 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/ssi/npcm7xx_fiu.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" + +#include "trace.h" + +/* Up to 128 MiB of flash may be accessed directly as memory. */ +#define NPCM7XX_FIU_FLASH_WINDOW_SIZE (128 * MiB) + +/* Each module has 4 KiB of register space. Only a fraction of it is used. */ +#define NPCM7XX_FIU_CTRL_REGS_SIZE (4 * KiB) + +/* FIU_{DRD,DWR,UMA,PTR}_CFG cannot be written when this bit is set. */ +#define NPCM7XX_FIU_CFG_LCK BIT(31) + +/* Direct Read configuration register fields. */ +#define FIU_DRD_CFG_ADDSIZ(rv) extract32(rv, 16, 2) +#define FIU_ADDSIZ_3BYTES 0 +#define FIU_ADDSIZ_4BYTES 1 +#define FIU_DRD_CFG_DBW(rv) extract32(rv, 12, 2) +#define FIU_DRD_CFG_ACCTYPE(rv) extract32(rv, 8, 2) +#define FIU_DRD_CFG_RDCMD(rv) extract32(rv, 0, 8) + +/* Direct Write configuration register fields. */ +#define FIU_DWR_CFG_ADDSIZ(rv) extract32(rv, 16, 2) +#define FIU_DWR_CFG_WRCMD(rv) extract32(rv, 0, 8) + +/* User-Mode Access register fields. */ + +/* Command Mode Lock and the bits protected by it. */ +#define FIU_UMA_CFG_CMMLCK BIT(30) +#define FIU_UMA_CFG_CMMLCK_MASK 0x00000403 + +#define FIU_UMA_CFG_RDATSIZ(rv) extract32(rv, 24, 5) +#define FIU_UMA_CFG_DBSIZ(rv) extract32(rv, 21, 3) +#define FIU_UMA_CFG_WDATSIZ(rv) extract32(rv, 16, 5) +#define FIU_UMA_CFG_ADDSIZ(rv) extract32(rv, 11, 3) +#define FIU_UMA_CFG_CMDSIZ(rv) extract32(rv, 10, 1) +#define FIU_UMA_CFG_DBPCK(rv) extract32(rv, 6, 2) + +#define FIU_UMA_CTS_RDYIE BIT(25) +#define FIU_UMA_CTS_RDYST BIT(24) +#define FIU_UMA_CTS_SW_CS BIT(16) +#define FIU_UMA_CTS_DEV_NUM(rv) extract32(rv, 8, 2) +#define FIU_UMA_CTS_EXEC_DONE BIT(0) + +/* + * Returns the index of flash in the fiu->flash array. This corresponds to the + * chip select ID of the flash. + */ +static int npcm7xx_fiu_cs_index(NPCM7xxFIUState *fiu, NPCM7xxFIUFlash *flash) +{ + int index = flash - fiu->flash; + + g_assert(index >= 0 && index < fiu->cs_count); + + return index; +} + +/* Assert the chip select specified in the UMA Control/Status Register. */ +static void npcm7xx_fiu_select(NPCM7xxFIUState *s, int cs_id) +{ + trace_npcm7xx_fiu_select(DEVICE(s)->canonical_path, cs_id); + + if (cs_id < s->cs_count) { + qemu_irq_lower(s->cs_lines[cs_id]); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: UMA to CS%d; this module has only %d chip selects", + DEVICE(s)->canonical_path, cs_id, s->cs_count); + cs_id = -1; + } + + s->active_cs = cs_id; +} + +/* Deassert the currently active chip select. */ +static void npcm7xx_fiu_deselect(NPCM7xxFIUState *s) +{ + if (s->active_cs < 0) { + return; + } + + trace_npcm7xx_fiu_deselect(DEVICE(s)->canonical_path, s->active_cs); + + qemu_irq_raise(s->cs_lines[s->active_cs]); + s->active_cs = -1; +} + +/* Direct flash memory read handler. */ +static uint64_t npcm7xx_fiu_flash_read(void *opaque, hwaddr addr, + unsigned int size) +{ + NPCM7xxFIUFlash *f = opaque; + NPCM7xxFIUState *fiu = f->fiu; + uint64_t value = 0; + uint32_t drd_cfg; + int dummy_cycles; + int i; + + if (fiu->active_cs != -1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: direct flash read with CS%d already active", + DEVICE(fiu)->canonical_path, fiu->active_cs); + } + + npcm7xx_fiu_select(fiu, npcm7xx_fiu_cs_index(fiu, f)); + + drd_cfg = fiu->regs[NPCM7XX_FIU_DRD_CFG]; + ssi_transfer(fiu->spi, FIU_DRD_CFG_RDCMD(drd_cfg)); + + switch (FIU_DRD_CFG_ADDSIZ(drd_cfg)) { + case FIU_ADDSIZ_4BYTES: + ssi_transfer(fiu->spi, extract32(addr, 24, 8)); + /* fall through */ + case FIU_ADDSIZ_3BYTES: + ssi_transfer(fiu->spi, extract32(addr, 16, 8)); + ssi_transfer(fiu->spi, extract32(addr, 8, 8)); + ssi_transfer(fiu->spi, extract32(addr, 0, 8)); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad address size %d\n", + DEVICE(fiu)->canonical_path, FIU_DRD_CFG_ADDSIZ(drd_cfg)); + break; + } + + /* Flash chip model expects one transfer per dummy bit, not byte */ + dummy_cycles = + (FIU_DRD_CFG_DBW(drd_cfg) * 8) >> FIU_DRD_CFG_ACCTYPE(drd_cfg); + for (i = 0; i < dummy_cycles; i++) { + ssi_transfer(fiu->spi, 0); + } + + for (i = 0; i < size; i++) { + value = deposit64(value, 8 * i, 8, ssi_transfer(fiu->spi, 0)); + } + + trace_npcm7xx_fiu_flash_read(DEVICE(fiu)->canonical_path, fiu->active_cs, + addr, size, value); + + npcm7xx_fiu_deselect(fiu); + + return value; +} + +/* Direct flash memory write handler. */ +static void npcm7xx_fiu_flash_write(void *opaque, hwaddr addr, uint64_t v, + unsigned int size) +{ + NPCM7xxFIUFlash *f = opaque; + NPCM7xxFIUState *fiu = f->fiu; + uint32_t dwr_cfg; + int cs_id; + int i; + + if (fiu->active_cs != -1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: direct flash write with CS%d already active", + DEVICE(fiu)->canonical_path, fiu->active_cs); + } + + cs_id = npcm7xx_fiu_cs_index(fiu, f); + trace_npcm7xx_fiu_flash_write(DEVICE(fiu)->canonical_path, cs_id, addr, + size, v); + npcm7xx_fiu_select(fiu, cs_id); + + dwr_cfg = fiu->regs[NPCM7XX_FIU_DWR_CFG]; + ssi_transfer(fiu->spi, FIU_DWR_CFG_WRCMD(dwr_cfg)); + + switch (FIU_DWR_CFG_ADDSIZ(dwr_cfg)) { + case FIU_ADDSIZ_4BYTES: + ssi_transfer(fiu->spi, extract32(addr, 24, 8)); + /* fall through */ + case FIU_ADDSIZ_3BYTES: + ssi_transfer(fiu->spi, extract32(addr, 16, 8)); + ssi_transfer(fiu->spi, extract32(addr, 8, 8)); + ssi_transfer(fiu->spi, extract32(addr, 0, 8)); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad address size %d\n", + DEVICE(fiu)->canonical_path, FIU_DWR_CFG_ADDSIZ(dwr_cfg)); + break; + } + + for (i = 0; i < size; i++) { + ssi_transfer(fiu->spi, extract64(v, i * 8, 8)); + } + + npcm7xx_fiu_deselect(fiu); +} + +static const MemoryRegionOps npcm7xx_fiu_flash_ops = { + .read = npcm7xx_fiu_flash_read, + .write = npcm7xx_fiu_flash_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, +}; + +/* Control register read handler. */ +static uint64_t npcm7xx_fiu_ctrl_read(void *opaque, hwaddr addr, + unsigned int size) +{ + hwaddr reg = addr / sizeof(uint32_t); + NPCM7xxFIUState *s = opaque; + uint32_t value; + + if (reg < NPCM7XX_FIU_NR_REGS) { + value = s->regs[reg]; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: read from invalid offset 0x%" PRIx64 "\n", + DEVICE(s)->canonical_path, addr); + value = 0; + } + + trace_npcm7xx_fiu_ctrl_read(DEVICE(s)->canonical_path, addr, value); + + return value; +} + +/* Send the specified number of address bytes from the UMA address register. */ +static void send_address(SSIBus *spi, unsigned int addsiz, uint32_t addr) +{ + switch (addsiz) { + case 4: + ssi_transfer(spi, extract32(addr, 24, 8)); + /* fall through */ + case 3: + ssi_transfer(spi, extract32(addr, 16, 8)); + /* fall through */ + case 2: + ssi_transfer(spi, extract32(addr, 8, 8)); + /* fall through */ + case 1: + ssi_transfer(spi, extract32(addr, 0, 8)); + /* fall through */ + case 0: + break; + } +} + +/* Send the number of dummy bits specified in the UMA config register. */ +static void send_dummy_bits(SSIBus *spi, uint32_t uma_cfg, uint32_t uma_cmd) +{ + unsigned int bits_per_clock = 1U << FIU_UMA_CFG_DBPCK(uma_cfg); + unsigned int i; + + for (i = 0; i < FIU_UMA_CFG_DBSIZ(uma_cfg); i++) { + /* Use bytes 0 and 1 first, then keep repeating byte 2 */ + unsigned int field = (i < 2) ? ((i + 1) * 8) : 24; + unsigned int j; + + for (j = 0; j < 8; j += bits_per_clock) { + ssi_transfer(spi, extract32(uma_cmd, field + j, bits_per_clock)); + } + } +} + +/* Perform a User-Mode Access transaction. */ +static void npcm7xx_fiu_uma_transaction(NPCM7xxFIUState *s) +{ + uint32_t uma_cts = s->regs[NPCM7XX_FIU_UMA_CTS]; + uint32_t uma_cfg; + unsigned int i; + + /* SW_CS means the CS is already forced low, so don't touch it. */ + if (uma_cts & FIU_UMA_CTS_SW_CS) { + int cs_id = FIU_UMA_CTS_DEV_NUM(s->regs[NPCM7XX_FIU_UMA_CTS]); + npcm7xx_fiu_select(s, cs_id); + } + + /* Send command, if present. */ + uma_cfg = s->regs[NPCM7XX_FIU_UMA_CFG]; + if (FIU_UMA_CFG_CMDSIZ(uma_cfg) > 0) { + ssi_transfer(s->spi, extract32(s->regs[NPCM7XX_FIU_UMA_CMD], 0, 8)); + } + + /* Send address, if present. */ + send_address(s->spi, FIU_UMA_CFG_ADDSIZ(uma_cfg), + s->regs[NPCM7XX_FIU_UMA_ADDR]); + + /* Write data, if present. */ + for (i = 0; i < FIU_UMA_CFG_WDATSIZ(uma_cfg); i++) { + unsigned int reg = + (i < 16) ? (NPCM7XX_FIU_UMA_DW0 + i / 4) : NPCM7XX_FIU_UMA_DW3; + unsigned int field = (i % 4) * 8; + + ssi_transfer(s->spi, extract32(s->regs[reg], field, 8)); + } + + /* Send dummy bits, if present. */ + send_dummy_bits(s->spi, uma_cfg, s->regs[NPCM7XX_FIU_UMA_CMD]); + + /* Read data, if present. */ + for (i = 0; i < FIU_UMA_CFG_RDATSIZ(uma_cfg); i++) { + unsigned int reg = NPCM7XX_FIU_UMA_DR0 + i / 4; + unsigned int field = (i % 4) * 8; + uint8_t c; + + c = ssi_transfer(s->spi, 0); + if (reg <= NPCM7XX_FIU_UMA_DR3) { + s->regs[reg] = deposit32(s->regs[reg], field, 8, c); + } + } + + /* Again, don't touch CS if the user is forcing it low. */ + if (uma_cts & FIU_UMA_CTS_SW_CS) { + npcm7xx_fiu_deselect(s); + } + + /* RDYST means a command has completed since it was cleared. */ + s->regs[NPCM7XX_FIU_UMA_CTS] |= FIU_UMA_CTS_RDYST; + /* EXEC_DONE means Execute Command / Not Done, so clear it here. */ + s->regs[NPCM7XX_FIU_UMA_CTS] &= ~FIU_UMA_CTS_EXEC_DONE; +} + +/* Control register write handler. */ +static void npcm7xx_fiu_ctrl_write(void *opaque, hwaddr addr, uint64_t v, + unsigned int size) +{ + hwaddr reg = addr / sizeof(uint32_t); + NPCM7xxFIUState *s = opaque; + uint32_t value = v; + + trace_npcm7xx_fiu_ctrl_write(DEVICE(s)->canonical_path, addr, value); + + switch (reg) { + case NPCM7XX_FIU_UMA_CFG: + if (s->regs[reg] & FIU_UMA_CFG_CMMLCK) { + value &= ~FIU_UMA_CFG_CMMLCK_MASK; + value |= (s->regs[reg] & FIU_UMA_CFG_CMMLCK_MASK); + } + /* fall through */ + case NPCM7XX_FIU_DRD_CFG: + case NPCM7XX_FIU_DWR_CFG: + if (s->regs[reg] & NPCM7XX_FIU_CFG_LCK) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to locked register @ 0x%" PRIx64 "\n", + DEVICE(s)->canonical_path, addr); + return; + } + s->regs[reg] = value; + break; + + case NPCM7XX_FIU_UMA_CTS: + if (value & FIU_UMA_CTS_RDYST) { + value &= ~FIU_UMA_CTS_RDYST; + } else { + value |= s->regs[reg] & FIU_UMA_CTS_RDYST; + } + if ((s->regs[reg] ^ value) & FIU_UMA_CTS_SW_CS) { + if (value & FIU_UMA_CTS_SW_CS) { + /* + * Don't drop CS if there's a transfer in progress, or we're + * about to start one. + */ + if (!((value | s->regs[reg]) & FIU_UMA_CTS_EXEC_DONE)) { + npcm7xx_fiu_deselect(s); + } + } else { + int cs_id = FIU_UMA_CTS_DEV_NUM(s->regs[NPCM7XX_FIU_UMA_CTS]); + npcm7xx_fiu_select(s, cs_id); + } + } + s->regs[reg] = value | (s->regs[reg] & FIU_UMA_CTS_EXEC_DONE); + if (value & FIU_UMA_CTS_EXEC_DONE) { + npcm7xx_fiu_uma_transaction(s); + } + break; + + case NPCM7XX_FIU_UMA_DR0 ... NPCM7XX_FIU_UMA_DR3: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to read-only register @ 0x%" PRIx64 "\n", + DEVICE(s)->canonical_path, addr); + return; + + case NPCM7XX_FIU_PRT_CFG: + case NPCM7XX_FIU_PRT_CMD0 ... NPCM7XX_FIU_PRT_CMD9: + qemu_log_mask(LOG_UNIMP, "%s: PRT is not implemented\n", __func__); + break; + + case NPCM7XX_FIU_UMA_CMD: + case NPCM7XX_FIU_UMA_ADDR: + case NPCM7XX_FIU_UMA_DW0 ... NPCM7XX_FIU_UMA_DW3: + case NPCM7XX_FIU_CFG: + s->regs[reg] = value; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to invalid offset 0x%" PRIx64 "\n", + DEVICE(s)->canonical_path, addr); + return; + } +} + +static const MemoryRegionOps npcm7xx_fiu_ctrl_ops = { + .read = npcm7xx_fiu_ctrl_read, + .write = npcm7xx_fiu_ctrl_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void npcm7xx_fiu_enter_reset(Object *obj, ResetType type) +{ + NPCM7xxFIUState *s = NPCM7XX_FIU(obj); + + trace_npcm7xx_fiu_enter_reset(DEVICE(obj)->canonical_path, type); + + memset(s->regs, 0, sizeof(s->regs)); + + s->regs[NPCM7XX_FIU_DRD_CFG] = 0x0300100b; + s->regs[NPCM7XX_FIU_DWR_CFG] = 0x03000002; + s->regs[NPCM7XX_FIU_UMA_CFG] = 0x00000400; + s->regs[NPCM7XX_FIU_UMA_CTS] = 0x00010000; + s->regs[NPCM7XX_FIU_UMA_CMD] = 0x0000000b; + s->regs[NPCM7XX_FIU_PRT_CFG] = 0x00000400; + s->regs[NPCM7XX_FIU_CFG] = 0x0000000b; +} + +static void npcm7xx_fiu_hold_reset(Object *obj) +{ + NPCM7xxFIUState *s = NPCM7XX_FIU(obj); + int i; + + trace_npcm7xx_fiu_hold_reset(DEVICE(obj)->canonical_path); + + for (i = 0; i < s->cs_count; i++) { + qemu_irq_raise(s->cs_lines[i]); + } +} + +static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp) +{ + NPCM7xxFIUState *s = NPCM7XX_FIU(dev); + SysBusDevice *sbd = &s->parent; + int i; + + if (s->cs_count <= 0) { + error_setg(errp, "%s: %d chip selects specified, need at least one", + dev->canonical_path, s->cs_count); + return; + } + + s->spi = ssi_create_bus(dev, "spi"); + s->cs_lines = g_new0(qemu_irq, s->cs_count); + qdev_init_gpio_out_named(DEVICE(s), s->cs_lines, "cs", s->cs_count); + s->flash = g_new0(NPCM7xxFIUFlash, s->cs_count); + + /* + * Register the control registers region first. It may be followed by one + * or more direct flash access regions. + */ + memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_fiu_ctrl_ops, s, "ctrl", + NPCM7XX_FIU_CTRL_REGS_SIZE); + sysbus_init_mmio(sbd, &s->mmio); + + for (i = 0; i < s->cs_count; i++) { + NPCM7xxFIUFlash *flash = &s->flash[i]; + flash->fiu = s; + memory_region_init_io(&flash->direct_access, OBJECT(s), + &npcm7xx_fiu_flash_ops, &s->flash[i], "flash", + NPCM7XX_FIU_FLASH_WINDOW_SIZE); + sysbus_init_mmio(sbd, &flash->direct_access); + } +} + +static const VMStateDescription vmstate_npcm7xx_fiu = { + .name = "npcm7xx-fiu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_INT32(active_cs, NPCM7xxFIUState), + VMSTATE_UINT32_ARRAY(regs, NPCM7xxFIUState, NPCM7XX_FIU_NR_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + +static Property npcm7xx_fiu_properties[] = { + DEFINE_PROP_INT32("cs-count", NPCM7xxFIUState, cs_count, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void npcm7xx_fiu_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "NPCM7xx Flash Interface Unit"; + dc->realize = npcm7xx_fiu_realize; + dc->vmsd = &vmstate_npcm7xx_fiu; + rc->phases.enter = npcm7xx_fiu_enter_reset; + rc->phases.hold = npcm7xx_fiu_hold_reset; + device_class_set_props(dc, npcm7xx_fiu_properties); +} + +static const TypeInfo npcm7xx_fiu_types[] = { + { + .name = TYPE_NPCM7XX_FIU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCM7xxFIUState), + .class_init = npcm7xx_fiu_class_init, + }, +}; +DEFINE_TYPES(npcm7xx_fiu_types); diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index a31d0d282f..8d0ef0593b 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -360,6 +360,7 @@ config NPCM7XX select ARM_GIC select PL310 # cache controller select SERIAL + select SSI select UNIMP config FSL_IMX25 diff --git a/hw/ssi/Makefile.objs b/hw/ssi/Makefile.objs index 07a85f1967..cab48e72c9 100644 --- a/hw/ssi/Makefile.objs +++ b/hw/ssi/Makefile.objs @@ -5,6 +5,7 @@ common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o common-obj-$(CONFIG_MSF2) += mss-spi.o +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_fiu.o common-obj-$(CONFIG_OMAP) += omap_spi.o common-obj-$(CONFIG_IMX) += imx_spi.o diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events index 0ea498de91..2f83ef833f 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -9,3 +9,14 @@ aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x" aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x" aspeed_smc_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64 aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect" + +# npcm7xx_fiu.c + +npcm7xx_fiu_enter_reset(const char *id, int reset_type) "%s reset type: %d" +npcm7xx_fiu_hold_reset(const char *id) "%s" +npcm7xx_fiu_select(const char *id, int cs) "%s select CS%d" +npcm7xx_fiu_deselect(const char *id, int cs) "%s deselect CS%d" +npcm7xx_fiu_ctrl_read(const char *id, uint64_t addr, uint32_t data) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 +npcm7xx_fiu_ctrl_write(const char *id, uint64_t addr, uint32_t data) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 +npcm7xx_fiu_flash_read(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64 +npcm7xx_fiu_flash_write(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64 From patchwork Fri Jul 17 06:02:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669041 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1EBF5138C for ; Fri, 17 Jul 2020 06:10:29 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E844A206BE for ; Fri, 17 Jul 2020 06:10:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="U5E5x+EO" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E844A206BE Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:60036 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJZk-00072c-5y for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:10:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60246) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3Nj8RXwsKCvcgrjhmmdlndmfnnfkd.bnlpdlt-cdudkmnmfmt.nqf@flex--hskinnemoen.bounces.google.com>) id 1jwJT7-0003s6-PR for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:37 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:46291) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3Nj8RXwsKCvcgrjhmmdlndmfnnfkd.bnlpdlt-cdudkmnmfmt.nqf@flex--hskinnemoen.bounces.google.com>) id 1jwJT5-0005JB-EJ for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:37 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id u64so10003664ybf.13 for ; Thu, 16 Jul 2020 23:03:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=PjXLdj2cihq5uXhjGbzoxvHE0ecuRwdA46uT+Gv/ofM=; b=U5E5x+EOSE/8ywjo1Ovd65pvoosOvCUIsqsf8issRPni+uTW1XoDut4cjqkto/hCX1 2oKXZlL3HXa6ipC3etHj9xuCb2Yxd9HXR/EnJ2xiM1pcAZtR9r6OMfMYeeyZcY4bhA6m fugH59VDatn+rzoFzRXEzjOpKggBjyqNQihK5C78wgfSVJ1VqNBWNDZNK59iff0xSYrV mot3MIs8YFf3OIN+74LCM+dsSdadgjYxuuPt/EU5ydaQQocZsat2hiY7DOSVpOlhFQcy LQ2eEZQ7XuCEh0djEhbQR/BdBkNK5IZM7E+IrT3+Plk603jarFT2SI8j3YMEKHySdHfS rNYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=PjXLdj2cihq5uXhjGbzoxvHE0ecuRwdA46uT+Gv/ofM=; b=FppInfN30MCYqQ9c/Ou4slmqsEsuMNirH2DDZQnWXbZtmTvp9yUkoBAYIz8alTZ6Hl i5HaFSW5F7vl5YjDIpZkW9DQrnmy7NcdughPqtyfL0U13NHcQMNFnliZQu01zSXVu/3a W0KmUMGUrM74diO1JkOVhW9+qtyUduoeHFf/E8MN9nbq3qQwMCCSBXm6fLzoz+9o4kdg 4Odu6Mb/57SvsIBief9H/UqyknYS67JLsnVxqTZx4iByu0qRBqtS+ARkAX0DUQLwCOrs aJX0E+tpdWvWNvCGyhJ8EfQmYnO9VeqDT8qDBIMZYedn7I333gY7YShdVHn0Fs5ep1Q6 Yi5A== X-Gm-Message-State: AOAM533tyoHd50xeW/kakCqbFDg2nic5PpBo6RhF/3k8u1pLVoySgp7h LX3peMm6htd3jnUQpc2NY7LkHfpC46GZYMPgan2A0LXnDPxdh2IvmhsbKZRioGjD4GarIGBJSOV 7UoHDE+XSgjTNrAqdPUHSaDoX3nrPIipzWvth9zvGlKlyuQMElzk07mtKBUQnWWAVZj9jrFOnzg == X-Google-Smtp-Source: ABdhPJxanI8jzYLHes88d4C/JneKvjZOOotpEs+1yzg3Ud1x/iYIz3PHCcaHJFFtI80ve6YN+iYNKVAu3NV+RoalEQ== X-Received: by 2002:a25:aba9:: with SMTP id v38mr12183884ybi.54.1594965814164; Thu, 16 Jul 2020 23:03:34 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:56 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-12-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 11/13] hw/arm: Wire up BMC boot flash for npcm750-evb and quanta-gsj From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , " =?utf-8?q?C=C3=A9dric_Le_Go?= =?utf-8?q?ater?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3Nj8RXwsKCvcgrjhmmdlndmfnnfkd.bnlpdlt-cdudkmnmfmt.nqf@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This allows these NPCM7xx-based boards to boot from a flash image, e.g. one built with OpenBMC. For example like this: IMAGE=${OPENBMC}/build/tmp/deploy/images/gsj/image-bmc qemu-system-arm -machine quanta-gsj -nographic \ -drive file=${IMAGE},if=mtd,bus=0,unit=0,format=raw,snapshot=on Reviewed-by: Tyrone Ting Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Signed-off-by: Havard Skinnemoen --- hw/arm/npcm7xx_boards.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index f32557e0e1..565ee6f671 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -19,6 +19,7 @@ #include "hw/arm/npcm7xx.h" #include "hw/core/cpu.h" #include "hw/loader.h" +#include "hw/qdev-properties.h" #include "qapi/error.h" #include "qemu-common.h" #include "qemu/units.h" @@ -53,6 +54,22 @@ static void npcm7xx_load_bootrom(NPCM7xxState *soc) } } +static void npcm7xx_connect_flash(NPCM7xxFIUState *fiu, int cs_no, + const char *flash_type, DriveInfo *dinfo) +{ + DeviceState *flash; + qemu_irq flash_cs; + + flash = qdev_new(flash_type); + if (dinfo) { + qdev_prop_set_drive(flash, "drive", blk_by_legacy_dinfo(dinfo)); + } + qdev_realize_and_unref(flash, BUS(fiu->spi), &error_fatal); + + flash_cs = qdev_get_gpio_in_named(flash, SSI_GPIO_CS, 0); + qdev_connect_gpio_out_named(DEVICE(fiu), "cs", cs_no, flash_cs); +} + static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram) { memory_region_add_subregion(get_system_memory(), NPCM7XX_DRAM_BA, dram); @@ -90,6 +107,7 @@ static void npcm750_evb_init(MachineState *machine) qdev_realize(DEVICE(soc), NULL, &error_fatal); npcm7xx_load_bootrom(soc); + npcm7xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0)); npcm7xx_load_kernel(machine, soc); } @@ -102,6 +120,8 @@ static void quanta_gsj_init(MachineState *machine) qdev_realize(DEVICE(soc), NULL, &error_fatal); npcm7xx_load_bootrom(soc); + npcm7xx_connect_flash(&soc->fiu[0], 0, "mx25l25635e", + drive_get(IF_MTD, 0, 0)); npcm7xx_load_kernel(machine, soc); } From patchwork Fri Jul 17 06:02:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669037 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EEE47138C for ; Fri, 17 Jul 2020 06:09:54 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BF0A3206BE for ; Fri, 17 Jul 2020 06:09:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rPSTAZEE" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BF0A3206BE Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:58078 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJZC-0006Eg-28 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:09:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60290) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3OD8RXwsKCvkitljoofnpfohpphmf.dpnrfnv-efwfmopohov.psh@flex--hskinnemoen.bounces.google.com>) id 1jwJTA-0003xA-O8 for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:40 -0400 Received: from mail-pg1-x54a.google.com ([2607:f8b0:4864:20::54a]:43532) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3OD8RXwsKCvkitljoofnpfohpphmf.dpnrfnv-efwfmopohov.psh@flex--hskinnemoen.bounces.google.com>) id 1jwJT8-0005K1-8k for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:40 -0400 Received: by mail-pg1-x54a.google.com with SMTP id s1so7183150pgq.10 for ; Thu, 16 Jul 2020 23:03:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=WJHL2RP44qCbss7g+JVirS3Ai2qR2QDTEKM2FUYBsXc=; b=rPSTAZEEnJFFlS9nxAmAJbo2rnYRy805xv0Vmxg0h56mLiD9Y2rSI/5T5NK0C3Tx/k F4bHAc3HzCrriaKBmsKkyyz2bTgDT2YUp8bZOlSqta2gMtpNaTRuqqm3V3MuNJ/+WzXL qNwW932hkJ/P57oLpwSyVdFcbwskJ+41JL2NCW+qMPv+2p+BfDztHzF/OeKYHk5bxt/o dEri+Uk3lxVd0bnTUaf3mdp20DgpKzg4TngTPTSYV4BdlxOdkbbeKvlTFiZhYCMvgpQN XXtuzdG+5K+Dm4qvE9eNlmkMJKT4swZ+/VTYYoYdXTI8g9yONg7xSv8y3IsNwSkyfFEz R7XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=WJHL2RP44qCbss7g+JVirS3Ai2qR2QDTEKM2FUYBsXc=; b=T6zb54poN3yEprxuET8XhiJGYL0ruiv3YvNK8sYo9G9smW59+4ZtrVDMBkgGnsXUvV E17zvdbamnR3XFzZLZyYFVLq1owmScPymjkutNBHcrIZ1qthsUAJoLpX1gakexhcrAjB WExq2WrshmNOvpj7b+V7HwD4hhbgqwnKZW8ySIMCy2wvx6dwYHseUxNq7fspPQtHdibn u66VHhNiieT4ABiYxK9Bvz6PhlKde2g/wjMo0Kd5ZSotVs15Dpqgg4QKMR4h0NJPJTAV 7vAcBZe659wynYGsatmdxB7XuALpdLSLexaCobDxAhxobz4q15nPM8tOSEcoYWqLF2aP fOSQ== X-Gm-Message-State: AOAM530crV2WnHlbokUbDLB0N5aVq7BOvUK0CRE9bFXzG0PMwzShf9sX qhThnT6aR0Pik+S1fDZk6ToIDWM7Qu1W+HTijk2PEhe2SFAi/51n1zHacUSJf4raqCO9/YjOx2p xWMl0zWANvK93VwdFdWZNrqOL6XMH8HSvGT8OMyci7/OLDZZ0HPDGEdnAzKbH7O5uUk1nCJ6F8Q == X-Google-Smtp-Source: ABdhPJwtyHoqz+6ND2K9RPjOQsytC1rJ0+fEOe019Dbo/Bk8GLmQ9l1ZGMFXF29qzmYQuinXJNxvWs9cbMalxVloAQ== X-Received: by 2002:a63:135b:: with SMTP id 27mr7564767pgt.37.1594965816178; Thu, 16 Jul 2020 23:03:36 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:57 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-13-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 12/13] docs/system: Add Nuvoton machine documentation From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen , " =?utf-8?q?C=C3=A9dric_Le_Go?= =?utf-8?q?ater?= " Received-SPF: pass client-ip=2607:f8b0:4864:20::54a; envelope-from=3OD8RXwsKCvkitljoofnpfohpphmf.dpnrfnv-efwfmopohov.psh@flex--hskinnemoen.bounces.google.com; helo=mail-pg1-x54a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, PDS_OTHER_BAD_TLD=1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Reviewed-by: Cédric Le Goater Signed-off-by: Havard Skinnemoen --- docs/system/arm/nuvoton.rst | 90 +++++++++++++++++++++++++++++++++++++ docs/system/target-arm.rst | 1 + 2 files changed, 91 insertions(+) create mode 100644 docs/system/arm/nuvoton.rst diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst new file mode 100644 index 0000000000..36bf901122 --- /dev/null +++ b/docs/system/arm/nuvoton.rst @@ -0,0 +1,90 @@ +Nuvoton iBMC boards (``npcm750-evb``, ``quanta-gsj``) +===================================================== + +The `Nuvoton iBMC`_ chips (NPCM7xx) are a family of ARM-based SoCs that are +designed to be used as Baseboard Management Controllers (BMCs) in various +servers. They all feature one or two ARM Cortex A9 CPU cores, as well as an +assortment of peripherals targeted for either Enterprise or Data Center / +Hyperscale applications. The former is a superset of the latter, so NPCM750 has +all the peripherals of NPCM730 and more. + +.. _Nuvoton iBMC: https://www.nuvoton.com/products/cloud-computing/ibmc/ + +The NPCM750 SoC has two Cortex A9 cores and is targeted for the Enterprise +segment. The following machines are based on this chip : + +- ``npcm750-evb`` Nuvoton NPCM750 Evaluation board + +The NPCM730 SoC has two Cortex A9 cores and is targeted for Data Center and +Hyperscale applications. The following machines are based on this chip : + +- ``quanta-gsj`` Quanta GSJ server BMC + +There are also two more SoCs, NPCM710 and NPCM705, which are single-core +variants of NPCM750 and NPCM730, respectively. These are currently not +supported by QEMU. + +Supported devices +----------------- + + * SMP (Dual Core Cortex-A9) + * Cortex-A9MPCore built-in peripherals: SCU, GIC, Global Timer, Private Timer + and Watchdog. + * SRAM, ROM and DRAM mappings + * System Global Control Registers (GCR) + * Clock and reset controller (CLK) + * Timer controller (TIM) + * Serial ports (16550-based) + * DDR4 memory controller (dummy interface indicating memory training is done) + * OTP controllers (no protection features) + * Flash Interface Unit (FIU; no protection features) + +Missing devices +--------------- + + * GPIO controller + * LPC/eSPI host-to-BMC interface, including + + * Keyboard and mouse controller interface (KBCI) + * Keyboard Controller Style (KCS) channels + * BIOS POST code FIFO + * System Wake-up Control (SWC) + * Shared memory (SHM) + * eSPI slave interface + + * Ethernet controllers (GMAC and EMC) + * USB host (USBH) + * USB device (USBD) + * SMBus controller (SMBF) + * Peripheral SPI controller (PSPI) + * Analog to Digital Converter (ADC) + * SD/MMC host + * Random Number Generator (RNG) + * PECI interface + * Pulse Width Modulation (PWM) + * Tachometer + * PCI and PCIe root complex and bridges + * VDM and MCTP support + * Serial I/O expansion + * LPC/eSPI host + * Coprocessor + * Graphics + * Video capture + * Encoding compression engine + * Security features + +Boot options +------------ + +The Nuvoton machines can boot from an OpenBMC firmware image, or directly into +a kernel using the ``-kernel`` option. OpenBMC images for `quanta-gsj` and +possibly others can be downloaded from the OpenPOWER jenkins : + + https://openpower.xyz/ + +The firmware image should be attached as an MTD drive. Example : + +.. code-block:: bash + + $ qemu-system-arm -machine quanta-gsj -nographic \ + -drive file=image-bmc,if=mtd,bus=0,unit=0,format=raw diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 1bd477a293..38a9daa9b9 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -84,6 +84,7 @@ undocumented; you can get a complete list by running arm/aspeed arm/musicpal arm/nseries + arm/nuvoton arm/orangepi arm/palm arm/xscale From patchwork Fri Jul 17 06:02:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Havard Skinnemoen X-Patchwork-Id: 11669045 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8AC92138C for ; Fri, 17 Jul 2020 06:13:36 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5F9462071A for ; Fri, 17 Jul 2020 06:13:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="DtJCKWoy" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5F9462071A Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:43960 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jwJcl-0003fC-Lw for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jul 2020 02:13:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60318) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3OT8RXwsKCvojumkppgoqgpiqqing.eqosgow-fgxgnpqpipw.qti@flex--hskinnemoen.bounces.google.com>) id 1jwJTL-0004Lx-Eo for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:51 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:48860) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3OT8RXwsKCvojumkppgoqgpiqqing.eqosgow-fgxgnpqpipw.qti@flex--hskinnemoen.bounces.google.com>) id 1jwJTJ-0005Kx-PR for qemu-devel@nongnu.org; Fri, 17 Jul 2020 02:03:51 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id i62so10125003ybc.15 for ; Thu, 16 Jul 2020 23:03:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=uKYickmWfL8+Bpz4+Fgl3zDCXqjlabRC8OPCW303i24=; b=DtJCKWoyTbqCyJyptQo1hAbDf/mlqLPt9u/Y6hOFA08VJA7neJJOjZMJVTNUa72fzI Ebt541FTz5yT75aJy1CXE3ld/qMiWdwUETvoiZf1DmtSqP2LLG5tISeMAsHd7ROSoYMH bQHdv5SK0EBNCUSZnaUsqxcBvfitMUJYCtDhdLw8768lF9b73oRPAQSPCNv0nBKqjJHE oSDz+YtLKfSAj5iFExGZnrSgJbShiMYkUd0Pc/QHCAKOC3g+2BUtt/ipN4be1Onw3pRv n3J+/eoD42relsvUExE6PUja1g4hkk9zTtlwsno7yXuHZ5pQaD82TgToWDvnNgEIUaBi YFow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=uKYickmWfL8+Bpz4+Fgl3zDCXqjlabRC8OPCW303i24=; b=JXEyCm0S2ArytNXluXrBlpIH4X5NB8MoM/qV1O0vh85BC3IaqsPUmXi/yjKDLO4IDa repOacfR7x2/bKiuUVJ4QN+6nug8LeVm3GLjwQgdA4TEeTwY0k/m2vH63h4LrrgGohX/ D7fEtWxBc9M69xncZtB5wQB9LgqsDVPnyUSlDV5x5QK7BRy2oyELCsmADJw97Nw1Ak3+ pmBHXITt5RchpDjjiJn6ell6a/V85jSwV+IEP++1dtvIDFjz5RJFpHGMKso14cH5Cuzy 1uqCqfvNJsgfL0X0h57i4Y+W3/mOsQ/i6wlQTgPZAdvFLvcCwUsuBdbNnQb/xQecWxOE RBng== X-Gm-Message-State: AOAM530i8YncJRQTIDvnr2q7M3MGhWcfEG+sGui68acuqV0YvyEBQtKe cBMLdkt7hhINoZn1Ob1JfuY0mqWuRFwDOF0ozWpw8lGanS7HRnFeGB6AO2cIzU9ah55MMvzROb4 X6xSax4okXYsslYycjEbvOHe8cJnT1BRdt3D+VZsVJf73rzAHuzZmsPC2Ylq+UrdwNNd4yJiANg == X-Google-Smtp-Source: ABdhPJweYZwScHMJKchaH/lYiylSGlbUqKyGFJ89JRcywnKz90WhM3c3zoSZ3dXarKeSHfCvBYjD20fJboxynntgdQ== X-Received: by 2002:a25:21d6:: with SMTP id h205mr11269020ybh.460.1594965817938; Thu, 16 Jul 2020 23:03:37 -0700 (PDT) Date: Thu, 16 Jul 2020 23:02:58 -0700 In-Reply-To: <20200717060258.1602319-1-hskinnemoen@google.com> Message-Id: <20200717060258.1602319-14-hskinnemoen@google.com> Mime-Version: 1.0 References: <20200717060258.1602319-1-hskinnemoen@google.com> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog Subject: [PATCH v6 13/13] tests/acceptance: console boot tests for quanta-gsj From: Havard Skinnemoen To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Avi.Fishman@nuvoton.com, kfting@nuvoton.com, Havard Skinnemoen Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3OT8RXwsKCvojumkppgoqgpiqqing.eqosgow-fgxgnpqpipw.qti@flex--hskinnemoen.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This adds two acceptance tests for the quanta-gsj machine. One test downloads a lightly patched openbmc flash image from github and verifies that it boots all the way to the login prompt. The other test downloads a kernel, initrd and dtb built from the same openbmc source and verifies that the kernel detects all CPUs and boots to the point where it can't find the root filesystem (because we have no flash image in this case). Signed-off-by: Havard Skinnemoen Reviewed-by: Philippe Mathieu-Daudé --- tests/acceptance/boot_linux_console.py | 65 ++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 73cc69c499..1d82fc7ff8 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -569,6 +569,71 @@ class BootLinuxConsole(LinuxKernelTest): 'sda') # cubieboard's reboot is not functioning; omit reboot test. + def test_arm_quanta_gsj(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:quanta-gsj + """ + # 25 MiB compressed, 32 MiB uncompressed. + image_url = ( + 'https://github.com/hskinnemoen/openbmc/releases/download/' + '20200711-gsj-qemu-0/obmc-phosphor-image-gsj.static.mtd.gz') + image_hash = '14895e634923345cb5c8776037ff7876df96f6b1' + image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash) + image_name = os.path.splitext(os.path.basename(image_path_gz))[0] + image_path = os.path.join(self.workdir, image_name) + archive.gzip_uncompress(image_path_gz, image_path) + + self.vm.set_console() + drive_args = 'file=' + image_path + ',if=mtd,bus=0,unit=0' + self.vm.add_args('-drive', drive_args) + self.vm.launch() + + self.wait_for_console_pattern('> BootBlock by Nuvoton') + self.wait_for_console_pattern('>Device: Poleg BMC NPCM730') + self.wait_for_console_pattern('>Skip DDR init.') + self.wait_for_console_pattern('U-Boot ') + self.wait_for_console_pattern('Booting Linux on physical CPU 0x0') + self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0') + self.wait_for_console_pattern('OpenBMC Project Reference Distro') + self.wait_for_console_pattern('gsj login:') + + def test_arm_quanta_gsj_initrd(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:quanta-gsj + """ + initrd_url = ( + 'https://github.com/hskinnemoen/openbmc/releases/download/' + '20200711-gsj-qemu-0/obmc-phosphor-initramfs-gsj.cpio.xz') + initrd_hash = '98fefe5d7e56727b1eb17d5c00311b1b5c945300' + initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash) + kernel_url = ( + 'https://github.com/hskinnemoen/openbmc/releases/download/' + '20200711-gsj-qemu-0/uImage-gsj.bin') + kernel_hash = 'fa67b2f141d56d39b3c54305c0e8a899c99eb2c7' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + dtb_url = ( + 'https://github.com/hskinnemoen/openbmc/releases/download/' + '20200711-gsj-qemu-0/nuvoton-npcm730-gsj.dtb') + dtb_hash = '18315f7006d7b688d8312d5c727eecd819aa36a4' + dtb_path = self.fetch_asset(dtb_url, asset_hash=dtb_hash) + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0,115200n8 ' + 'earlycon=uart8250,mmio32,0xf0001000') + self.vm.add_args('-kernel', kernel_path, + '-initrd', initrd_path, + '-dtb', dtb_path, + '-append', kernel_command_line) + self.vm.launch() + + self.wait_for_console_pattern('Booting Linux on physical CPU 0x0') + self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0') + self.wait_for_console_pattern( + 'Give root password for system maintenance') + def test_arm_orangepi(self): """ :avocado: tags=arch:arm