From patchwork Mon Dec 26 22:02:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Strahinja Jankovic X-Patchwork-Id: 1719544 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=fYxBFnpp; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NgsKr0cF6z23dc for ; Tue, 27 Dec 2022 09:05:36 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9vZH-0004ot-0P; Mon, 26 Dec 2022 17:03:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p9vZ5-0004l2-MS; Mon, 26 Dec 2022 17:03:24 -0500 Received: from mail-ed1-x52c.google.com ([2a00:1450:4864:20::52c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9vZ2-0003X7-Sj; Mon, 26 Dec 2022 17:03:23 -0500 Received: by mail-ed1-x52c.google.com with SMTP id c34so10279155edf.0; Mon, 26 Dec 2022 14:03:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0iC1DLdK7rM2+2JgfrCCzhIOuJpyhzdQ5lAlF2+ubgA=; b=fYxBFnppCy6dXLvOA5a9VTW27Kei6VeNXWcr9WZytxhL/St56QdXFlcGU2D6M9TNAc xz7P49YNWA7UAWlS1wLq9DgS9L7FXZPfQnRfZNs7LqbCNVM4Kx/qzAvZx8YwgA4923x5 4whY3GdfX413kMGQfR9e2yC/wpRlLvVwGDdJYo3ZPgvx3fMm8v/libj2MbsTjv+a+ak5 rAeW4ZpfE8W0c2IgiNSDi+ZKRCUFnUEOZWcnKrFGiUKgFlBkBBj4d+F1+9ZM/PTX+lBl fnY/QAPAT0jUVEoI3Z+wYBzDm21u/i6IUnpwN13M5rDRlLYtCcrD74BCdzW/EXwzMvlx fIXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0iC1DLdK7rM2+2JgfrCCzhIOuJpyhzdQ5lAlF2+ubgA=; b=5ijhKz3t+aJe5g2jdti8drlRw5EGldmClWQ8wpPvi/7wNMdPubDO/OZv4+vQqe0olR Rxk1UqVuZG40JdD7ePbypw1ILo+cGLaED10jQzFnGAwY92nKal2dJWxdI6/+/q82cu6p 8thfjquXOU9E4fZsefVd+zdpcehJW0kSrKYciXYkNcxL6ncu+yk3iITXc7gRYBvjq51N CGKNXIDfdieJo+tQ38ELPKdncKmM2Ch6hcQgCw+vQrPl8zxqRA2Yc81thavg6H1WlX7m b4a2zOpBbz7TuaaKXncSbovJV5yBX7O2Mmmgtq9xqNtmN0Aa1QM/OYm5c+35wsfFvpl/ b2iA== X-Gm-Message-State: AFqh2kp7Ckw+IRE3nEaP9o0QsydF9uJrmhVZde8hEo9uqEdzzZGEuobH O1J1aOgSb5Y7eY9ob8KwKAw= X-Google-Smtp-Source: AMrXdXuLcfl4+Kw4J7QlToFG7BocgWpYyj3sI82tjbX4FhMWs6pJ/u0DcIX7bJeBxMcDamCZ43lXQQ== X-Received: by 2002:a50:eac6:0:b0:461:d042:80db with SMTP id u6-20020a50eac6000000b00461d04280dbmr16756241edp.0.1672092198151; Mon, 26 Dec 2022 14:03:18 -0800 (PST) Received: from penguin.lxd ([87.116.176.120]) by smtp.googlemail.com with ESMTPSA id u1-20020aa7d541000000b0046951b43e84sm5111467edr.55.2022.12.26.14.03.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 14:03:17 -0800 (PST) From: Strahinja Jankovic X-Google-Original-From: Strahinja Jankovic To: Peter Maydell Cc: Beniamino Galvani , Niek Linnenbank , philmd@linaro.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org, Strahinja Jankovic Subject: [PATCH v3 1/7] hw/misc: Allwinner-A10 Clock Controller Module Emulation Date: Mon, 26 Dec 2022 23:02:57 +0100 Message-Id: <20221226220303.14420-2-strahinja.p.jankovic@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> References: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::52c; envelope-from=strahinjapjankovic@gmail.com; helo=mail-ed1-x52c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org During SPL boot several Clock Controller Module (CCM) registers are read, most important are PLL and Tuning, as well as divisor registers. This patch adds these registers and initializes reset values from user's guide. Signed-off-by: Strahinja Jankovic Reviewed-by: Niek Linnenbank --- hw/arm/Kconfig | 1 + hw/arm/allwinner-a10.c | 7 + hw/misc/Kconfig | 3 + hw/misc/allwinner-a10-ccm.c | 224 ++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + include/hw/arm/allwinner-a10.h | 2 + include/hw/misc/allwinner-a10-ccm.h | 67 +++++++++ 7 files changed, 305 insertions(+) create mode 100644 hw/misc/allwinner-a10-ccm.c create mode 100644 include/hw/misc/allwinner-a10-ccm.h diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 17fcde8e1c..14f52b41af 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -319,6 +319,7 @@ config ALLWINNER_A10 select AHCI select ALLWINNER_A10_PIT select ALLWINNER_A10_PIC + select ALLWINNER_A10_CCM select ALLWINNER_EMAC select SERIAL select UNIMP diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 79082289ea..86baeeeca2 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -26,6 +26,7 @@ #include "hw/usb/hcd-ohci.h" #define AW_A10_MMC0_BASE 0x01c0f000 +#define AW_A10_CCM_BASE 0x01c20000 #define AW_A10_PIC_REG_BASE 0x01c20400 #define AW_A10_PIT_REG_BASE 0x01c20c00 #define AW_A10_UART0_REG_BASE 0x01c28000 @@ -46,6 +47,8 @@ static void aw_a10_init(Object *obj) object_initialize_child(obj, "timer", &s->timer, TYPE_AW_A10_PIT); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_AW_A10_CCM); + object_initialize_child(obj, "emac", &s->emac, TYPE_AW_EMAC); object_initialize_child(obj, "sata", &s->sata, TYPE_ALLWINNER_AHCI); @@ -103,6 +106,10 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(get_system_memory(), 0x00000000, &s->sram_a); create_unimplemented_device("a10-sram-ctrl", 0x01c00000, 4 * KiB); + /* Clock Control Module */ + sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, AW_A10_CCM_BASE); + /* FIXME use qdev NIC properties instead of nd_table[] */ if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index cbabe9f78c..ed07bf4133 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -174,4 +174,7 @@ config VIRT_CTRL config LASI bool +config ALLWINNER_A10_CCM + bool + source macio/Kconfig diff --git a/hw/misc/allwinner-a10-ccm.c b/hw/misc/allwinner-a10-ccm.c new file mode 100644 index 0000000000..68146ee340 --- /dev/null +++ b/hw/misc/allwinner-a10-ccm.c @@ -0,0 +1,224 @@ +/* + * Allwinner A10 Clock Control Module emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 CCU, + * by Niek Linnenbank. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/misc/allwinner-a10-ccm.h" + +/* CCM register offsets */ +enum { + REG_PLL1_CFG = 0x0000, /* PLL1 Control */ + REG_PLL1_TUN = 0x0004, /* PLL1 Tuning */ + REG_PLL2_CFG = 0x0008, /* PLL2 Control */ + REG_PLL2_TUN = 0x000C, /* PLL2 Tuning */ + REG_PLL3_CFG = 0x0010, /* PLL3 Control */ + REG_PLL4_CFG = 0x0018, /* PLL4 Control */ + REG_PLL5_CFG = 0x0020, /* PLL5 Control */ + REG_PLL5_TUN = 0x0024, /* PLL5 Tuning */ + REG_PLL6_CFG = 0x0028, /* PLL6 Control */ + REG_PLL6_TUN = 0x002C, /* PLL6 Tuning */ + REG_PLL7_CFG = 0x0030, /* PLL7 Control */ + REG_PLL1_TUN2 = 0x0038, /* PLL1 Tuning2 */ + REG_PLL5_TUN2 = 0x003C, /* PLL5 Tuning2 */ + REG_PLL8_CFG = 0x0040, /* PLL8 Control */ + REG_OSC24M_CFG = 0x0050, /* OSC24M Control */ + REG_CPU_AHB_APB0_CFG = 0x0054, /* CPU, AHB and APB0 Divide Ratio */ +}; + +#define REG_INDEX(offset) (offset / sizeof(uint32_t)) + +/* CCM register reset values */ +enum { + REG_PLL1_CFG_RST = 0x21005000, + REG_PLL1_TUN_RST = 0x0A101000, + REG_PLL2_CFG_RST = 0x08100010, + REG_PLL2_TUN_RST = 0x00000000, + REG_PLL3_CFG_RST = 0x0010D063, + REG_PLL4_CFG_RST = 0x21009911, + REG_PLL5_CFG_RST = 0x11049280, + REG_PLL5_TUN_RST = 0x14888000, + REG_PLL6_CFG_RST = 0x21009911, + REG_PLL6_TUN_RST = 0x00000000, + REG_PLL7_CFG_RST = 0x0010D063, + REG_PLL1_TUN2_RST = 0x00000000, + REG_PLL5_TUN2_RST = 0x00000000, + REG_PLL8_CFG_RST = 0x21009911, + REG_OSC24M_CFG_RST = 0x00138013, + REG_CPU_AHB_APB0_CFG_RST = 0x00010010, +}; + +static uint64_t allwinner_a10_ccm_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwA10ClockCtlState *s = AW_A10_CCM(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_PLL1_CFG: + case REG_PLL1_TUN: + case REG_PLL2_CFG: + case REG_PLL2_TUN: + case REG_PLL3_CFG: + case REG_PLL4_CFG: + case REG_PLL5_CFG: + case REG_PLL5_TUN: + case REG_PLL6_CFG: + case REG_PLL6_TUN: + case REG_PLL7_CFG: + case REG_PLL1_TUN2: + case REG_PLL5_TUN2: + case REG_PLL8_CFG: + case REG_OSC24M_CFG: + case REG_CPU_AHB_APB0_CFG: + break; + case 0x158 ... AW_A10_CCM_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented read offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + return s->regs[idx]; +} + +static void allwinner_a10_ccm_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwA10ClockCtlState *s = AW_A10_CCM(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_PLL1_CFG: + case REG_PLL1_TUN: + case REG_PLL2_CFG: + case REG_PLL2_TUN: + case REG_PLL3_CFG: + case REG_PLL4_CFG: + case REG_PLL5_CFG: + case REG_PLL5_TUN: + case REG_PLL6_CFG: + case REG_PLL6_TUN: + case REG_PLL7_CFG: + case REG_PLL1_TUN2: + case REG_PLL5_TUN2: + case REG_PLL8_CFG: + case REG_OSC24M_CFG: + case REG_CPU_AHB_APB0_CFG: + break; + case 0x158 ... AW_A10_CCM_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + } + + s->regs[idx] = (uint32_t) val; +} + +static const MemoryRegionOps allwinner_a10_ccm_ops = { + .read = allwinner_a10_ccm_read, + .write = allwinner_a10_ccm_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static void allwinner_a10_ccm_reset_enter(Object *obj, ResetType type) +{ + AwA10ClockCtlState *s = AW_A10_CCM(obj); + + /* Set default values for registers */ + s->regs[REG_INDEX(REG_PLL1_CFG)] = REG_PLL1_CFG_RST; + s->regs[REG_INDEX(REG_PLL1_TUN)] = REG_PLL1_TUN_RST; + s->regs[REG_INDEX(REG_PLL2_CFG)] = REG_PLL2_CFG_RST; + s->regs[REG_INDEX(REG_PLL2_TUN)] = REG_PLL2_TUN_RST; + s->regs[REG_INDEX(REG_PLL3_CFG)] = REG_PLL3_CFG_RST; + s->regs[REG_INDEX(REG_PLL4_CFG)] = REG_PLL4_CFG_RST; + s->regs[REG_INDEX(REG_PLL5_CFG)] = REG_PLL5_CFG_RST; + s->regs[REG_INDEX(REG_PLL5_TUN)] = REG_PLL5_TUN_RST; + s->regs[REG_INDEX(REG_PLL6_CFG)] = REG_PLL6_CFG_RST; + s->regs[REG_INDEX(REG_PLL6_TUN)] = REG_PLL6_TUN_RST; + s->regs[REG_INDEX(REG_PLL7_CFG)] = REG_PLL7_CFG_RST; + s->regs[REG_INDEX(REG_PLL1_TUN2)] = REG_PLL1_TUN2_RST; + s->regs[REG_INDEX(REG_PLL5_TUN2)] = REG_PLL5_TUN2_RST; + s->regs[REG_INDEX(REG_PLL8_CFG)] = REG_PLL8_CFG_RST; + s->regs[REG_INDEX(REG_OSC24M_CFG)] = REG_OSC24M_CFG_RST; + s->regs[REG_INDEX(REG_CPU_AHB_APB0_CFG)] = REG_CPU_AHB_APB0_CFG_RST; +} + +static void allwinner_a10_ccm_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + AwA10ClockCtlState *s = AW_A10_CCM(obj); + + /* Memory mapping */ + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_a10_ccm_ops, s, + TYPE_AW_A10_CCM, AW_A10_CCM_IOSIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription allwinner_a10_ccm_vmstate = { + .name = "allwinner-a10-ccm", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AwA10ClockCtlState, AW_A10_CCM_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_a10_ccm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = allwinner_a10_ccm_reset_enter; + dc->vmsd = &allwinner_a10_ccm_vmstate; +} + +static const TypeInfo allwinner_a10_ccm_info = { + .name = TYPE_AW_A10_CCM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = allwinner_a10_ccm_init, + .instance_size = sizeof(AwA10ClockCtlState), + .class_init = allwinner_a10_ccm_class_init, +}; + +static void allwinner_a10_ccm_register(void) +{ + type_register_static(&allwinner_a10_ccm_info); +} + +type_init(allwinner_a10_ccm_register) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index ed0598dc9e..c828dbeb26 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -38,6 +38,7 @@ subdir('macio') softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c')) +softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_CCM', if_true: files('allwinner-a10-ccm.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-ccu.c')) specific_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-cpucfg.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c')) diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h index a76dc7b84d..45d0fc2f7e 100644 --- a/include/hw/arm/allwinner-a10.h +++ b/include/hw/arm/allwinner-a10.h @@ -12,6 +12,7 @@ #include "hw/usb/hcd-ohci.h" #include "hw/usb/hcd-ehci.h" #include "hw/rtc/allwinner-rtc.h" +#include "hw/misc/allwinner-a10-ccm.h" #include "target/arm/cpu.h" #include "qom/object.h" @@ -30,6 +31,7 @@ struct AwA10State { /*< public >*/ ARMCPU cpu; + AwA10ClockCtlState ccm; AwA10PITState timer; AwA10PICState intc; AwEmacState emac; diff --git a/include/hw/misc/allwinner-a10-ccm.h b/include/hw/misc/allwinner-a10-ccm.h new file mode 100644 index 0000000000..7f22532efa --- /dev/null +++ b/include/hw/misc/allwinner-a10-ccm.h @@ -0,0 +1,67 @@ +/* + * Allwinner A10 Clock Control Module emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 CCU, + * by Niek Linnenbank. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef HW_MISC_ALLWINNER_A10_CCM_H +#define HW_MISC_ALLWINNER_A10_CCM_H + +#include "qom/object.h" +#include "hw/sysbus.h" + +/** + * @name Constants + * @{ + */ + +/** Size of register I/O address space used by CCM device */ +#define AW_A10_CCM_IOSIZE (0x400) + +/** Total number of known registers */ +#define AW_A10_CCM_REGS_NUM (AW_A10_CCM_IOSIZE / sizeof(uint32_t)) + +/** @} */ + +/** + * @name Object model + * @{ + */ + +#define TYPE_AW_A10_CCM "allwinner-a10-ccm" +OBJECT_DECLARE_SIMPLE_TYPE(AwA10ClockCtlState, AW_A10_CCM) + +/** @} */ + +/** + * Allwinner A10 CCM object instance state. + */ +struct AwA10ClockCtlState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + /** Maps I/O registers in physical memory */ + MemoryRegion iomem; + + /** Array of hardware registers */ + uint32_t regs[AW_A10_CCM_REGS_NUM]; +}; + +#endif /* HW_MISC_ALLWINNER_H3_CCU_H */ From patchwork Mon Dec 26 22:02:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Strahinja Jankovic X-Patchwork-Id: 1719543 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=IDJ+k65D; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NgsKS0KX7z23f2 for ; Tue, 27 Dec 2022 09:05:16 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9vZH-0004q8-UG; Mon, 26 Dec 2022 17:03:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p9vZ6-0004lI-Pp; Mon, 26 Dec 2022 17:03:24 -0500 Received: from mail-ed1-x536.google.com ([2a00:1450:4864:20::536]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9vZ3-0003XB-D6; Mon, 26 Dec 2022 17:03:24 -0500 Received: by mail-ed1-x536.google.com with SMTP id u28so12018365edd.10; Mon, 26 Dec 2022 14:03:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IA9DLwdDIWXg6Vm5V2G0ugLwqd09BSX4sLQfHIli23s=; b=IDJ+k65DjqarMJ81A7LGkK0y59cDPAPRqaFou1X8E4P5S0TMysvPUVMTskk09gYtOr tA8JXCG/GWoCQwKtiGGLrfhd+AoUMQvTIevQiliLQhcHvVSJAZ2zEPtnsAtLckCP7pcB D6KrbaR57ACRKM+eO6Iq7zvz6+wB3gAuZWqO9ZHU1zjPnPN9x5UOjuoInBT2FaHhkllS 7SgHypaoCiYm4Ooz0xGrFnvUakcpjYwnTk0HhZmmeQgJmsBuhz/cuv/2SThHx4sOofHH sBEbHHnY4rKzr51jzf7s2diMzjwyEA7OfowSZzAhMcyyRJLoUmgrauMQw//Tvvu5seOJ GViA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IA9DLwdDIWXg6Vm5V2G0ugLwqd09BSX4sLQfHIli23s=; b=vDrDg/cDBdNWBnMD8Laz2tV+OXj0ZSn/dk6UQWJtD169X7CeZZW9GKz2NbaVZyuWpr syz9LOV5wUQ6zEk7I2SmvkYh9aK6zOPvs1dxFx/BCzIPWfLOc3vRWcgP89HBZIS0O13O bGkmlzeHDAQahGZ8p62si6MFmYvpbEu0BWSWBNA3gqd1M7xM4XsPJlwQ5X9vBz3JrCqv 59uoW0olGsu42GSh65W0NP0bHU+WNBm8UrbZcM1yIy1HDzpiYZIR6WLiRqTFu6PfxSNv AN/VHTbv0JldoRBTqxaj1MstPvR2wqES9xT3zB3vekDLskJyQZ93xFn0pONQVZE8uUZO WUxg== X-Gm-Message-State: AFqh2krYGFcQeDzojUdpqvgWmbzYuP79mBGXeSs4nW6rpogmz0K48HIS sl6aXMhFg74/sVpf2OKZc1w= X-Google-Smtp-Source: AMrXdXta7Hd8zcAVfQmcs+vSnZ0MOi/GHh7YduACCE/m4ezh/Ko9nglNv/HHNY8RR7hfs477tlSxCQ== X-Received: by 2002:a05:6402:541a:b0:46c:6ed1:83b0 with SMTP id ev26-20020a056402541a00b0046c6ed183b0mr17377121edb.9.1672092199057; Mon, 26 Dec 2022 14:03:19 -0800 (PST) Received: from penguin.lxd ([87.116.176.120]) by smtp.googlemail.com with ESMTPSA id u1-20020aa7d541000000b0046951b43e84sm5111467edr.55.2022.12.26.14.03.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 14:03:18 -0800 (PST) From: Strahinja Jankovic X-Google-Original-From: Strahinja Jankovic To: Peter Maydell Cc: Beniamino Galvani , Niek Linnenbank , philmd@linaro.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org, Strahinja Jankovic Subject: [PATCH v3 2/7] hw/misc: Allwinner A10 DRAM Controller Emulation Date: Mon, 26 Dec 2022 23:02:58 +0100 Message-Id: <20221226220303.14420-3-strahinja.p.jankovic@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> References: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::536; envelope-from=strahinjapjankovic@gmail.com; helo=mail-ed1-x536.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org During SPL boot several DRAM Controller registers are used. Most important registers are those related to DRAM initialization and calibration, where SPL initiates process and waits until certain bit is set/cleared. This patch adds these registers, initializes reset values from user's guide and updates state of registers as SPL expects it. Signed-off-by: Strahinja Jankovic Reviewed-by: Niek Linnenbank --- hw/arm/Kconfig | 1 + hw/arm/allwinner-a10.c | 7 + hw/misc/Kconfig | 3 + hw/misc/allwinner-a10-dramc.c | 179 ++++++++++++++++++++++++++ hw/misc/meson.build | 1 + include/hw/arm/allwinner-a10.h | 2 + include/hw/misc/allwinner-a10-dramc.h | 68 ++++++++++ 7 files changed, 261 insertions(+) create mode 100644 hw/misc/allwinner-a10-dramc.c create mode 100644 include/hw/misc/allwinner-a10-dramc.h diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 14f52b41af..140f142ae5 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -320,6 +320,7 @@ config ALLWINNER_A10 select ALLWINNER_A10_PIT select ALLWINNER_A10_PIC select ALLWINNER_A10_CCM + select ALLWINNER_A10_DRAMC select ALLWINNER_EMAC select SERIAL select UNIMP diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 86baeeeca2..a5f7a36ac9 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -25,6 +25,7 @@ #include "hw/boards.h" #include "hw/usb/hcd-ohci.h" +#define AW_A10_DRAMC_BASE 0x01c01000 #define AW_A10_MMC0_BASE 0x01c0f000 #define AW_A10_CCM_BASE 0x01c20000 #define AW_A10_PIC_REG_BASE 0x01c20400 @@ -49,6 +50,8 @@ static void aw_a10_init(Object *obj) object_initialize_child(obj, "ccm", &s->ccm, TYPE_AW_A10_CCM); + object_initialize_child(obj, "dramc", &s->dramc, TYPE_AW_A10_DRAMC); + object_initialize_child(obj, "emac", &s->emac, TYPE_AW_EMAC); object_initialize_child(obj, "sata", &s->sata, TYPE_ALLWINNER_AHCI); @@ -110,6 +113,10 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, AW_A10_CCM_BASE); + /* DRAM Control Module */ + sysbus_realize(SYS_BUS_DEVICE(&s->dramc), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 0, AW_A10_DRAMC_BASE); + /* FIXME use qdev NIC properties instead of nd_table[] */ if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index ed07bf4133..052fb54310 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -177,4 +177,7 @@ config LASI config ALLWINNER_A10_CCM bool +config ALLWINNER_A10_DRAMC + bool + source macio/Kconfig diff --git a/hw/misc/allwinner-a10-dramc.c b/hw/misc/allwinner-a10-dramc.c new file mode 100644 index 0000000000..e118b0c2fd --- /dev/null +++ b/hw/misc/allwinner-a10-dramc.c @@ -0,0 +1,179 @@ +/* + * Allwinner A10 DRAM Controller emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 DRAMC, + * by Niek Linnenbank. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/misc/allwinner-a10-dramc.h" + +/* DRAMC register offsets */ +enum { + REG_SDR_CCR = 0x0000, + REG_SDR_ZQCR0 = 0x00a8, + REG_SDR_ZQSR = 0x00b0 +}; + +#define REG_INDEX(offset) (offset / sizeof(uint32_t)) + +/* DRAMC register flags */ +enum { + REG_SDR_CCR_DATA_TRAINING = (1 << 30), + REG_SDR_CCR_DRAM_INIT = (1 << 31), +}; +enum { + REG_SDR_ZQSR_ZCAL = (1 << 31), +}; + +/* DRAMC register reset values */ +enum { + REG_SDR_CCR_RESET = 0x80020000, + REG_SDR_ZQCR0_RESET = 0x07b00000, + REG_SDR_ZQSR_RESET = 0x80000000 +}; + +static uint64_t allwinner_a10_dramc_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwA10DramControllerState *s = AW_A10_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_SDR_CCR: + case REG_SDR_ZQCR0: + case REG_SDR_ZQSR: + break; + case 0x2e4 ... AW_A10_DRAMC_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented read offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + return s->regs[idx]; +} + +static void allwinner_a10_dramc_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwA10DramControllerState *s = AW_A10_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_SDR_CCR: + if (val & REG_SDR_CCR_DRAM_INIT) { + /* Clear DRAM_INIT to indicate process is done. */ + val &= ~REG_SDR_CCR_DRAM_INIT; + } + if (val & REG_SDR_CCR_DATA_TRAINING) { + /* Clear DATA_TRAINING to indicate process is done. */ + val &= ~REG_SDR_CCR_DATA_TRAINING; + } + break; + case REG_SDR_ZQCR0: + /* Set ZCAL in ZQSR to indicate calibration is done. */ + s->regs[REG_INDEX(REG_SDR_ZQSR)] |= REG_SDR_ZQSR_ZCAL; + break; + case 0x2e4 ... AW_A10_DRAMC_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + } + + s->regs[idx] = (uint32_t) val; +} + +static const MemoryRegionOps allwinner_a10_dramc_ops = { + .read = allwinner_a10_dramc_read, + .write = allwinner_a10_dramc_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static void allwinner_a10_dramc_reset_enter(Object *obj, ResetType type) +{ + AwA10DramControllerState *s = AW_A10_DRAMC(obj); + + /* Set default values for registers */ + s->regs[REG_INDEX(REG_SDR_CCR)] = REG_SDR_CCR_RESET; + s->regs[REG_INDEX(REG_SDR_ZQCR0)] = REG_SDR_ZQCR0_RESET; + s->regs[REG_INDEX(REG_SDR_ZQSR)] = REG_SDR_ZQSR_RESET; +} + +static void allwinner_a10_dramc_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + AwA10DramControllerState *s = AW_A10_DRAMC(obj); + + /* Memory mapping */ + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_a10_dramc_ops, s, + TYPE_AW_A10_DRAMC, AW_A10_DRAMC_IOSIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription allwinner_a10_dramc_vmstate = { + .name = "allwinner-a10-dramc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AwA10DramControllerState, + AW_A10_DRAMC_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_a10_dramc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = allwinner_a10_dramc_reset_enter; + dc->vmsd = &allwinner_a10_dramc_vmstate; +} + +static const TypeInfo allwinner_a10_dramc_info = { + .name = TYPE_AW_A10_DRAMC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = allwinner_a10_dramc_init, + .instance_size = sizeof(AwA10DramControllerState), + .class_init = allwinner_a10_dramc_class_init, +}; + +static void allwinner_a10_dramc_register(void) +{ + type_register_static(&allwinner_a10_dramc_info); +} + +type_init(allwinner_a10_dramc_register) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index c828dbeb26..9eaa0750b5 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -39,6 +39,7 @@ subdir('macio') softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_CCM', if_true: files('allwinner-a10-ccm.c')) +softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_DRAMC', if_true: files('allwinner-a10-dramc.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-ccu.c')) specific_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-cpucfg.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c')) diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h index 45d0fc2f7e..abe4ff7066 100644 --- a/include/hw/arm/allwinner-a10.h +++ b/include/hw/arm/allwinner-a10.h @@ -13,6 +13,7 @@ #include "hw/usb/hcd-ehci.h" #include "hw/rtc/allwinner-rtc.h" #include "hw/misc/allwinner-a10-ccm.h" +#include "hw/misc/allwinner-a10-dramc.h" #include "target/arm/cpu.h" #include "qom/object.h" @@ -32,6 +33,7 @@ struct AwA10State { ARMCPU cpu; AwA10ClockCtlState ccm; + AwA10DramControllerState dramc; AwA10PITState timer; AwA10PICState intc; AwEmacState emac; diff --git a/include/hw/misc/allwinner-a10-dramc.h b/include/hw/misc/allwinner-a10-dramc.h new file mode 100644 index 0000000000..b61fbecbe7 --- /dev/null +++ b/include/hw/misc/allwinner-a10-dramc.h @@ -0,0 +1,68 @@ +/* + * Allwinner A10 DRAM Controller emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 DRAMC, + * by Niek Linnenbank. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef HW_MISC_ALLWINNER_A10_DRAMC_H +#define HW_MISC_ALLWINNER_A10_DRAMC_H + +#include "qom/object.h" +#include "hw/sysbus.h" +#include "hw/register.h" + +/** + * @name Constants + * @{ + */ + +/** Size of register I/O address space used by DRAMC device */ +#define AW_A10_DRAMC_IOSIZE (0x1000) + +/** Total number of known registers */ +#define AW_A10_DRAMC_REGS_NUM (AW_A10_DRAMC_IOSIZE / sizeof(uint32_t)) + +/** @} */ + +/** + * @name Object model + * @{ + */ + +#define TYPE_AW_A10_DRAMC "allwinner-a10-dramc" +OBJECT_DECLARE_SIMPLE_TYPE(AwA10DramControllerState, AW_A10_DRAMC) + +/** @} */ + +/** + * Allwinner A10 DRAMC object instance state. + */ +struct AwA10DramControllerState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + /** Maps I/O registers in physical memory */ + MemoryRegion iomem; + + /** Array of hardware registers */ + uint32_t regs[AW_A10_DRAMC_REGS_NUM]; +}; + +#endif /* HW_MISC_ALLWINNER_A10_DRAMC_H */ From patchwork Mon Dec 26 22:02:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Strahinja Jankovic X-Patchwork-Id: 1719545 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=BRtrMLgo; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NgsKx1Qrbz23dc for ; Tue, 27 Dec 2022 09:05:41 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9vZI-0004qu-Ib; Mon, 26 Dec 2022 17:03:36 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p9vZ7-0004la-GC; Mon, 26 Dec 2022 17:03:26 -0500 Received: from mail-ed1-x52c.google.com ([2a00:1450:4864:20::52c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9vZ3-0003XF-Oi; Mon, 26 Dec 2022 17:03:25 -0500 Received: by mail-ed1-x52c.google.com with SMTP id b88so9574530edf.6; Mon, 26 Dec 2022 14:03:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=paxbROUaSYSQU+0RHkhMjQEO4a2yYOCZQSaKgOUxJq4=; b=BRtrMLgoUp1lziBJ7c4vT11O1CxzMDjF4LhCXvg5xDHSGUIainexKSDfdT4woipWtw DzZ9ZzhQFknEyOKsXR45O0ADcBJMB9auhePMUc3yYnpk1MWYhInfpeTdu+9uWuT0Rinr zx4z5dqt9+Gghny4KBsXuBeXLPtyPHZQyXcS8IR/jgS6cd72R4zoDdOZOHGK9HAlcdG+ HC/HTurQAC/RAur+/Db7lvxRmkgneIOxuCjyVDbcQ7z6MUYJkQOpPqNVQ+q+R05W/Tni myBOKcafPqsSWvwC9DLv1tNJcXXl5JT4HZBpjzI+qpPqZsCqW6ZQd+lbHqVUnoPQ6Q3f QwDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=paxbROUaSYSQU+0RHkhMjQEO4a2yYOCZQSaKgOUxJq4=; b=vEll2wmR8sNe4aMPqN1IryT10Tug68JjRPHd+h19dkNSa7QYW23HswjQ3hCpmLl3D9 S7ygmTXEzY7yKRNFXmeZi+W27cZAymwJqpyw4MWINDKZH5tsyBJBsvWFwooEJCfDV12m YlRpV4Bkh55KlnSLR25rdU3pCXn3ZfkI8bFN9NOV7RdbOKi5BgRA5SCgYMgv8NFlPNbF JuAljNQh3QT+1c7V1nUyZB/EtUi2/9SXMO9AtOiqtXvvDIutp4Hrh6H0ErhK+MgTy/aE L4L6JAvaHYS3nCURoGBOBsVx9nr3uzI+z3Vu0qqRoyWmnG7vD1HJOw1GW/7qi1w2RCBw SDzA== X-Gm-Message-State: AFqh2kph4Lv2I/6EtbrG0H5bqacoY6oRrxfXl4sGxfXLhXTb+/wVRmF4 eaf0DAGzy9wepmZQ4bIMLqfkBEo7hR5krQ== X-Google-Smtp-Source: AMrXdXt6dGduXjj8TtH8A4fSKHnsRJNu4nvi/nycprRv/3zf61cAdBbGqzy5hg52Z+19XW+vNW7hug== X-Received: by 2002:aa7:cd04:0:b0:46b:cb37:117b with SMTP id b4-20020aa7cd04000000b0046bcb37117bmr14763503edw.39.1672092199986; Mon, 26 Dec 2022 14:03:19 -0800 (PST) Received: from penguin.lxd ([87.116.176.120]) by smtp.googlemail.com with ESMTPSA id u1-20020aa7d541000000b0046951b43e84sm5111467edr.55.2022.12.26.14.03.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 14:03:19 -0800 (PST) From: Strahinja Jankovic X-Google-Original-From: Strahinja Jankovic To: Peter Maydell Cc: Beniamino Galvani , Niek Linnenbank , philmd@linaro.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org, Strahinja Jankovic Subject: [PATCH v3 3/7] {hw/i2c,docs/system/arm}: Allwinner TWI/I2C Emulation Date: Mon, 26 Dec 2022 23:02:59 +0100 Message-Id: <20221226220303.14420-4-strahinja.p.jankovic@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> References: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::52c; envelope-from=strahinjapjankovic@gmail.com; helo=mail-ed1-x52c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, WEIRD_QUOTING=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch implements Allwinner TWI/I2C controller emulation. Only master-mode functionality is implemented. The SPL boot for Cubieboard expects AXP209 PMIC on TWI0/I2C0 bus, so this is first part enabling the TWI/I2C bus operation. Since both Allwinner A10 and H3 use the same module, it is added for both boards. Docs are also updated for Cubieboard and Orangepi-PC board to indicate I2C availability. Signed-off-by: Strahinja Jankovic Reviewed-by: Niek Linnenbank --- docs/system/arm/cubieboard.rst | 1 + docs/system/arm/orangepi.rst | 1 + hw/arm/Kconfig | 2 + hw/arm/allwinner-a10.c | 8 + hw/arm/allwinner-h3.c | 11 +- hw/i2c/Kconfig | 4 + hw/i2c/allwinner-i2c.c | 459 +++++++++++++++++++++++++++++++++ hw/i2c/meson.build | 1 + hw/i2c/trace-events | 5 + include/hw/arm/allwinner-a10.h | 2 + include/hw/arm/allwinner-h3.h | 3 + include/hw/i2c/allwinner-i2c.h | 55 ++++ 12 files changed, 551 insertions(+), 1 deletion(-) create mode 100644 hw/i2c/allwinner-i2c.c create mode 100644 include/hw/i2c/allwinner-i2c.h diff --git a/docs/system/arm/cubieboard.rst b/docs/system/arm/cubieboard.rst index 344ff8cef9..8d485f5435 100644 --- a/docs/system/arm/cubieboard.rst +++ b/docs/system/arm/cubieboard.rst @@ -14,3 +14,4 @@ Emulated devices: - SDHCI - USB controller - SATA controller +- TWI (I2C) controller diff --git a/docs/system/arm/orangepi.rst b/docs/system/arm/orangepi.rst index 83c7445197..e5973600a1 100644 --- a/docs/system/arm/orangepi.rst +++ b/docs/system/arm/orangepi.rst @@ -25,6 +25,7 @@ The Orange Pi PC machine supports the following devices: * Clock Control Unit * System Control module * Security Identifier device + * TWI (I2C) Limitations """"""""""" diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 140f142ae5..eefe1fd134 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -322,6 +322,7 @@ config ALLWINNER_A10 select ALLWINNER_A10_CCM select ALLWINNER_A10_DRAMC select ALLWINNER_EMAC + select ALLWINNER_I2C select SERIAL select UNIMP @@ -329,6 +330,7 @@ config ALLWINNER_H3 bool select ALLWINNER_A10_PIT select ALLWINNER_SUN8I_EMAC + select ALLWINNER_I2C select SERIAL select ARM_TIMER select ARM_GIC diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index a5f7a36ac9..17e439777e 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -36,6 +36,7 @@ #define AW_A10_OHCI_BASE 0x01c14400 #define AW_A10_SATA_BASE 0x01c18000 #define AW_A10_RTC_BASE 0x01c20d00 +#define AW_A10_I2C0_BASE 0x01c2ac00 static void aw_a10_init(Object *obj) { @@ -56,6 +57,8 @@ static void aw_a10_init(Object *obj) object_initialize_child(obj, "sata", &s->sata, TYPE_ALLWINNER_AHCI); + object_initialize_child(obj, "i2c0", &s->i2c0, TYPE_AW_I2C); + if (machine_usb(current_machine)) { int i; @@ -176,6 +179,11 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) /* RTC */ sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->rtc), 0, AW_A10_RTC_BASE, 10); + + /* I2C */ + sysbus_realize(SYS_BUS_DEVICE(&s->i2c0), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c0), 0, AW_A10_I2C0_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0, qdev_get_gpio_in(dev, 7)); } static void aw_a10_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 308ed15552..bfce3c8d92 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -53,6 +53,7 @@ const hwaddr allwinner_h3_memmap[] = { [AW_H3_DEV_UART1] = 0x01c28400, [AW_H3_DEV_UART2] = 0x01c28800, [AW_H3_DEV_UART3] = 0x01c28c00, + [AW_H3_DEV_TWI0] = 0x01c2ac00, [AW_H3_DEV_EMAC] = 0x01c30000, [AW_H3_DEV_DRAMCOM] = 0x01c62000, [AW_H3_DEV_DRAMCTL] = 0x01c63000, @@ -106,7 +107,6 @@ struct AwH3Unimplemented { { "uart1", 0x01c28400, 1 * KiB }, { "uart2", 0x01c28800, 1 * KiB }, { "uart3", 0x01c28c00, 1 * KiB }, - { "twi0", 0x01c2ac00, 1 * KiB }, { "twi1", 0x01c2b000, 1 * KiB }, { "twi2", 0x01c2b400, 1 * KiB }, { "scr", 0x01c2c400, 1 * KiB }, @@ -150,6 +150,7 @@ enum { AW_H3_GIC_SPI_UART1 = 1, AW_H3_GIC_SPI_UART2 = 2, AW_H3_GIC_SPI_UART3 = 3, + AW_H3_GIC_SPI_TWI0 = 6, AW_H3_GIC_SPI_TIMER0 = 18, AW_H3_GIC_SPI_TIMER1 = 19, AW_H3_GIC_SPI_MMC0 = 60, @@ -225,6 +226,8 @@ static void allwinner_h3_init(Object *obj) "ram-size"); object_initialize_child(obj, "rtc", &s->rtc, TYPE_AW_RTC_SUN6I); + + object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C); } static void allwinner_h3_realize(DeviceState *dev, Error **errp) @@ -423,6 +426,12 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, s->memmap[AW_H3_DEV_RTC]); + /* I2C */ + sysbus_realize(SYS_BUS_DEVICE(&s->i2c0), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c0), 0, s->memmap[AW_H3_DEV_TWI0]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0, + qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TWI0)); + /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(unimplemented); i++) { create_unimplemented_device(unimplemented[i].device_name, diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 9bb8870517..f8ec461be3 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -34,6 +34,10 @@ config MPC_I2C bool select I2C +config ALLWINNER_I2C + bool + select I2C + config PCA954X bool select I2C diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c new file mode 100644 index 0000000000..a435965836 --- /dev/null +++ b/hw/i2c/allwinner-i2c.c @@ -0,0 +1,459 @@ +/* + * Allwinner I2C Bus Serial Interface Emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from IMX I2C controller, + * by Jean-Christophe DUBOIS . + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * SPDX-License-Identifier: MIT + */ + +#include "qemu/osdep.h" +#include "hw/i2c/allwinner-i2c.h" +#include "hw/irq.h" +#include "migration/vmstate.h" +#include "hw/i2c/i2c.h" +#include "qemu/log.h" +#include "trace.h" +#include "qemu/module.h" + +/* Allwinner I2C memory map */ +#define TWI_ADDR_REG 0x00 /* slave address register */ +#define TWI_XADDR_REG 0x04 /* extended slave address register */ +#define TWI_DATA_REG 0x08 /* data register */ +#define TWI_CNTR_REG 0x0c /* control register */ +#define TWI_STAT_REG 0x10 /* status register */ +#define TWI_CCR_REG 0x14 /* clock control register */ +#define TWI_SRST_REG 0x18 /* software reset register */ +#define TWI_EFR_REG 0x1c /* enhance feature register */ +#define TWI_LCR_REG 0x20 /* line control register */ + +/* Used only in slave mode, do not set */ +#define TWI_ADDR_RESET 0 +#define TWI_XADDR_RESET 0 + +/* Data register */ +#define TWI_DATA_MASK 0xFF +#define TWI_DATA_RESET 0 + +/* Control register */ +#define TWI_CNTR_INT_EN (1 << 7) +#define TWI_CNTR_BUS_EN (1 << 6) +#define TWI_CNTR_M_STA (1 << 5) +#define TWI_CNTR_M_STP (1 << 4) +#define TWI_CNTR_INT_FLAG (1 << 3) +#define TWI_CNTR_A_ACK (1 << 2) +#define TWI_CNTR_MASK 0xFC +#define TWI_CNTR_RESET 0 + +/* Status register */ +#define TWI_STAT_MASK 0xF8 +#define TWI_STAT_RESET 0xF8 + +/* Clock register */ +#define TWI_CCR_CLK_M_MASK 0x78 +#define TWI_CCR_CLK_N_MASK 0x07 +#define TWI_CCR_MASK 0x7F +#define TWI_CCR_RESET 0 + +/* Soft reset */ +#define TWI_SRST_MASK 0x01 +#define TWI_SRST_RESET 0 + +/* Enhance feature */ +#define TWI_EFR_MASK 0x03 +#define TWI_EFR_RESET 0 + +/* Line control */ +#define TWI_LCR_SCL_STATE (1 << 5) +#define TWI_LCR_SDA_STATE (1 << 4) +#define TWI_LCR_SCL_CTL (1 << 3) +#define TWI_LCR_SCL_CTL_EN (1 << 2) +#define TWI_LCR_SDA_CTL (1 << 1) +#define TWI_LCR_SDA_CTL_EN (1 << 0) +#define TWI_LCR_MASK 0x3F +#define TWI_LCR_RESET 0x3A + +/* Status value in STAT register is shifted by 3 bits */ +#define TWI_STAT_SHIFT 3 +#define STAT_FROM_STA(x) ((x) << TWI_STAT_SHIFT) +#define STAT_TO_STA(x) ((x) >> TWI_STAT_SHIFT) + +enum { + STAT_BUS_ERROR = 0, + /* Master mode */ + STAT_M_STA_TX, + STAT_M_RSTA_TX, + STAT_M_ADDR_WR_ACK, + STAT_M_ADDR_WR_NACK, + STAT_M_DATA_TX_ACK, + STAT_M_DATA_TX_NACK, + STAT_M_ARB_LOST, + STAT_M_ADDR_RD_ACK, + STAT_M_ADDR_RD_NACK, + STAT_M_DATA_RX_ACK, + STAT_M_DATA_RX_NACK, + /* Slave mode */ + STAT_S_ADDR_WR_ACK, + STAT_S_ARB_LOST_AW_ACK, + STAT_S_GCA_ACK, + STAT_S_ARB_LOST_GCA_ACK, + STAT_S_DATA_RX_SA_ACK, + STAT_S_DATA_RX_SA_NACK, + STAT_S_DATA_RX_GCA_ACK, + STAT_S_DATA_RX_GCA_NACK, + STAT_S_STP_RSTA, + STAT_S_ADDR_RD_ACK, + STAT_S_ARB_LOST_AR_ACK, + STAT_S_DATA_TX_ACK, + STAT_S_DATA_TX_NACK, + STAT_S_LB_TX_ACK, + /* Master mode, 10-bit */ + STAT_M_2ND_ADDR_WR_ACK, + STAT_M_2ND_ADDR_WR_NACK, + /* Idle */ + STAT_IDLE = 0x1f +} TWI_STAT_STA; + +static const char *allwinner_i2c_get_regname(unsigned offset) +{ + switch (offset) { + case TWI_ADDR_REG: + return "ADDR"; + case TWI_XADDR_REG: + return "XADDR"; + case TWI_DATA_REG: + return "DATA"; + case TWI_CNTR_REG: + return "CNTR"; + case TWI_STAT_REG: + return "STAT"; + case TWI_CCR_REG: + return "CCR"; + case TWI_SRST_REG: + return "SRST"; + case TWI_EFR_REG: + return "EFR"; + case TWI_LCR_REG: + return "LCR"; + default: + return "[?]"; + } +} + +static inline bool allwinner_i2c_is_reset(AWI2CState *s) +{ + return s->srst & TWI_SRST_MASK; +} + +static inline bool allwinner_i2c_bus_is_enabled(AWI2CState *s) +{ + return s->cntr & TWI_CNTR_BUS_EN; +} + +static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s) +{ + return s->cntr & TWI_CNTR_INT_EN; +} + +static void allwinner_i2c_reset_hold(Object *obj) +{ + AWI2CState *s = AW_I2C(obj); + + if (STAT_TO_STA(s->stat) != STAT_IDLE) { + i2c_end_transfer(s->bus); + } + + s->addr = TWI_ADDR_RESET; + s->xaddr = TWI_XADDR_RESET; + s->data = TWI_DATA_RESET; + s->cntr = TWI_CNTR_RESET; + s->stat = TWI_STAT_RESET; + s->ccr = TWI_CCR_RESET; + s->srst = TWI_SRST_RESET; + s->efr = TWI_EFR_RESET; + s->lcr = TWI_LCR_RESET; +} + +static inline void allwinner_i2c_raise_interrupt(AWI2CState *s) +{ + /* + * Raise an interrupt if the device is not reset and it is configured + * to generate some interrupts. + */ + if (!allwinner_i2c_is_reset(s) && allwinner_i2c_bus_is_enabled(s)) { + if (STAT_TO_STA(s->stat) != STAT_IDLE) { + s->cntr |= TWI_CNTR_INT_FLAG; + if (allwinner_i2c_interrupt_is_enabled(s)) { + qemu_irq_raise(s->irq); + } + } + } +} + +static uint64_t allwinner_i2c_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint16_t value; + AWI2CState *s = AW_I2C(opaque); + + switch (offset) { + case TWI_ADDR_REG: + value = s->addr; + break; + case TWI_XADDR_REG: + value = s->xaddr; + break; + case TWI_DATA_REG: + if ((STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) || + (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) || + (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK)) { + /* Get the next byte */ + s->data = i2c_recv(s->bus); + + if (s->cntr & TWI_CNTR_A_ACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); + } else { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); + } + allwinner_i2c_raise_interrupt(s); + } + value = s->data; + break; + case TWI_CNTR_REG: + value = s->cntr; + break; + case TWI_STAT_REG: + value = s->stat; + /* + * If polling when reading then change state to indicate data + * is available + */ + if (STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) { + if (s->cntr & TWI_CNTR_A_ACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); + } else { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); + } + allwinner_i2c_raise_interrupt(s); + } + break; + case TWI_CCR_REG: + value = s->ccr; + break; + case TWI_SRST_REG: + value = s->srst; + break; + case TWI_EFR_REG: + value = s->efr; + break; + case TWI_LCR_REG: + value = s->lcr; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); + value = 0; + break; + } + + trace_allwinner_i2c_read(allwinner_i2c_get_regname(offset), offset, value); + + return (uint64_t)value; +} + +static void allwinner_i2c_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + AWI2CState *s = AW_I2C(opaque); + + value &= 0xff; + + trace_allwinner_i2c_write(allwinner_i2c_get_regname(offset), offset, value); + + switch (offset) { + case TWI_ADDR_REG: + s->addr = (uint8_t)value; + break; + case TWI_XADDR_REG: + s->xaddr = (uint8_t)value; + break; + case TWI_DATA_REG: + /* If the device is in reset or not enabled, nothing to do */ + if (allwinner_i2c_is_reset(s) || (!allwinner_i2c_bus_is_enabled(s))) { + break; + } + + s->data = value & TWI_DATA_MASK; + + switch (STAT_TO_STA(s->stat)) { + case STAT_M_STA_TX: + case STAT_M_RSTA_TX: + /* Send address */ + if (i2c_start_transfer(s->bus, extract32(s->data, 1, 7), + extract32(s->data, 0, 1))) { + /* If non zero is returned, the address is not valid */ + s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_NACK); + } else { + /* Determine if read of write */ + if (extract32(s->data, 0, 1)) { + s->stat = STAT_FROM_STA(STAT_M_ADDR_RD_ACK); + } else { + s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_ACK); + } + allwinner_i2c_raise_interrupt(s); + } + break; + case STAT_M_ADDR_WR_ACK: + case STAT_M_DATA_TX_ACK: + if (i2c_send(s->bus, s->data)) { + /* If the target return non zero then end the transfer */ + s->stat = STAT_FROM_STA(STAT_M_DATA_TX_NACK); + i2c_end_transfer(s->bus); + } else { + s->stat = STAT_FROM_STA(STAT_M_DATA_TX_ACK); + allwinner_i2c_raise_interrupt(s); + } + break; + default: + break; + } + break; + case TWI_CNTR_REG: + if (!allwinner_i2c_is_reset(s)) { + /* Do something only if not in software reset */ + s->cntr = value & TWI_CNTR_MASK; + + /* Check if start condition should be sent */ + if (s->cntr & TWI_CNTR_M_STA) { + /* Update status */ + if (STAT_TO_STA(s->stat) == STAT_IDLE) { + /* Send start condition */ + s->stat = STAT_FROM_STA(STAT_M_STA_TX); + } else { + /* Send repeated start condition */ + s->stat = STAT_FROM_STA(STAT_M_RSTA_TX); + } + /* Clear start condition */ + s->cntr &= ~TWI_CNTR_M_STA; + } + if (s->cntr & TWI_CNTR_M_STP) { + /* Update status */ + i2c_end_transfer(s->bus); + s->stat = STAT_FROM_STA(STAT_IDLE); + s->cntr &= ~TWI_CNTR_M_STP; + } + if ((s->cntr & TWI_CNTR_INT_FLAG) == 0) { + /* Interrupt flag cleared */ + qemu_irq_lower(s->irq); + } + if ((s->cntr & TWI_CNTR_A_ACK) == 0) { + if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); + } + } else { + if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); + } + } + allwinner_i2c_raise_interrupt(s); + + } + break; + case TWI_CCR_REG: + s->ccr = value & TWI_CCR_MASK; + break; + case TWI_SRST_REG: + if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) { + /* Perform reset */ + allwinner_i2c_reset_hold(OBJECT(s)); + } + s->srst = value & TWI_SRST_MASK; + break; + case TWI_EFR_REG: + s->efr = value & TWI_EFR_MASK; + break; + case TWI_LCR_REG: + s->lcr = value & TWI_LCR_MASK; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); + break; + } +} + +static const MemoryRegionOps allwinner_i2c_ops = { + .read = allwinner_i2c_read, + .write = allwinner_i2c_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription allwinner_i2c_vmstate = { + .name = TYPE_AW_I2C, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(addr, AWI2CState), + VMSTATE_UINT8(xaddr, AWI2CState), + VMSTATE_UINT8(data, AWI2CState), + VMSTATE_UINT8(cntr, AWI2CState), + VMSTATE_UINT8(ccr, AWI2CState), + VMSTATE_UINT8(srst, AWI2CState), + VMSTATE_UINT8(efr, AWI2CState), + VMSTATE_UINT8(lcr, AWI2CState), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_i2c_realize(DeviceState *dev, Error **errp) +{ + AWI2CState *s = AW_I2C(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_i2c_ops, s, + TYPE_AW_I2C, AW_I2C_MEM_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + s->bus = i2c_init_bus(dev, "i2c"); +} + +static void allwinner_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = allwinner_i2c_reset_hold; + dc->vmsd = &allwinner_i2c_vmstate; + dc->realize = allwinner_i2c_realize; + dc->desc = "Allwinner I2C Controller"; +} + +static const TypeInfo allwinner_i2c_type_info = { + .name = TYPE_AW_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AWI2CState), + .class_init = allwinner_i2c_class_init, +}; + +static void allwinner_i2c_register_types(void) +{ + type_register_static(&allwinner_i2c_type_info); +} + +type_init(allwinner_i2c_register_types) diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index d3df273251..7de7f2f540 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -8,6 +8,7 @@ i2c_ss.add(when: 'CONFIG_BITBANG_I2C', if_true: files('bitbang_i2c.c')) i2c_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_i2c.c')) i2c_ss.add(when: 'CONFIG_IMX_I2C', if_true: files('imx_i2c.c')) i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2c.c')) +i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c')) i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c')) i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c')) i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c')) diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index af181d43ee..52dbd53a23 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -8,6 +8,11 @@ i2c_send_async(uint8_t address, uint8_t data) "send_async(addr:0x%02x) data:0x%0 i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x" i2c_ack(void) "" +# allwinner_i2c.c + +allwinner_i2c_read(const char* reg_name, uint64_t offset, uint64_t value) "read %s [0x%" PRIx64 "]: -> 0x%" PRIx64 +allwinner_i2c_write(const char* reg_name, uint64_t offset, uint64_t value) "write %s [0x%" PRIx64 "]: <- 0x%" PRIx64 + # aspeed_i2c.c aspeed_i2c_bus_cmd(uint32_t cmd, const char *cmd_flags, uint32_t count, uint32_t intr_status) "handling cmd=0x%x %s count=%d intr=0x%x" diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h index abe4ff7066..763935fca9 100644 --- a/include/hw/arm/allwinner-a10.h +++ b/include/hw/arm/allwinner-a10.h @@ -14,6 +14,7 @@ #include "hw/rtc/allwinner-rtc.h" #include "hw/misc/allwinner-a10-ccm.h" #include "hw/misc/allwinner-a10-dramc.h" +#include "hw/i2c/allwinner-i2c.h" #include "target/arm/cpu.h" #include "qom/object.h" @@ -39,6 +40,7 @@ struct AwA10State { AwEmacState emac; AllwinnerAHCIState sata; AwSdHostState mmc0; + AWI2CState i2c0; AwRtcState rtc; MemoryRegion sram_a; EHCISysBusState ehci[AW_A10_NUM_USB]; diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h index 63025fb27c..1d7ce20589 100644 --- a/include/hw/arm/allwinner-h3.h +++ b/include/hw/arm/allwinner-h3.h @@ -47,6 +47,7 @@ #include "hw/sd/allwinner-sdhost.h" #include "hw/net/allwinner-sun8i-emac.h" #include "hw/rtc/allwinner-rtc.h" +#include "hw/i2c/allwinner-i2c.h" #include "target/arm/cpu.h" #include "sysemu/block-backend.h" @@ -82,6 +83,7 @@ enum { AW_H3_DEV_UART2, AW_H3_DEV_UART3, AW_H3_DEV_EMAC, + AW_H3_DEV_TWI0, AW_H3_DEV_DRAMCOM, AW_H3_DEV_DRAMCTL, AW_H3_DEV_DRAMPHY, @@ -130,6 +132,7 @@ struct AwH3State { AwH3SysCtrlState sysctrl; AwSidState sid; AwSdHostState mmc0; + AWI2CState i2c0; AwSun8iEmacState emac; AwRtcState rtc; GICState gic; diff --git a/include/hw/i2c/allwinner-i2c.h b/include/hw/i2c/allwinner-i2c.h new file mode 100644 index 0000000000..4f378b86ba --- /dev/null +++ b/include/hw/i2c/allwinner-i2c.h @@ -0,0 +1,55 @@ +/* + * Allwinner I2C Bus Serial Interface registers definition + * + * Copyright (C) 2022 Strahinja Jankovic. + * + * This file is derived from IMX I2C controller, + * by Jean-Christophe DUBOIS . + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#ifndef ALLWINNER_I2C_H +#define ALLWINNER_I2C_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_AW_I2C "allwinner.i2c" +OBJECT_DECLARE_SIMPLE_TYPE(AWI2CState, AW_I2C) + +#define AW_I2C_MEM_SIZE 0x24 + +struct AWI2CState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + I2CBus *bus; + qemu_irq irq; + + uint8_t addr; + uint8_t xaddr; + uint8_t data; + uint8_t cntr; + uint8_t stat; + uint8_t ccr; + uint8_t srst; + uint8_t efr; + uint8_t lcr; +}; + +#endif /* ALLWINNER_I2C_H */ From patchwork Mon Dec 26 22:03:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Strahinja Jankovic X-Patchwork-Id: 1719541 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=D8bdWx/m; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NgsKG0tFyz23dD for ; Tue, 27 Dec 2022 09:05:06 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9vZL-0004wj-0S; Mon, 26 Dec 2022 17:03:39 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p9vZ6-0004lS-TP; Mon, 26 Dec 2022 17:03:25 -0500 Received: from mail-ed1-x532.google.com ([2a00:1450:4864:20::532]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9vZ4-0003XX-K8; Mon, 26 Dec 2022 17:03:24 -0500 Received: by mail-ed1-x532.google.com with SMTP id i9so16855591edj.4; Mon, 26 Dec 2022 14:03:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=aKnc58k0ZanDuaW5DMWuEx42gXkp9LxDYyM8CKqt4s8=; b=D8bdWx/mYebXIxzKIdxPUWVgZUWj2xiC8ITP1pjyacotjUqPVDsIurPI/VhylP8kwz C+qXQFdfkwW/s2f/+zp3MMB7zHXuTzcVUP/ns+J7gHHTQ+lgcVpSs+qqqvPCCgM9Vusb xWCMLkHgpiMzLBSKluyosjDiiSJqSfYxHY/cAzJ+8KDtQjDyLc/rdTH+7y4CjCJi7KQb DzxYilsoJjuWDPPPSGCRKfn9LbPeSBZ1qTXSyibYIaxQtNvUQMA+xMD2C6FG1ZSrmecf 0P5aeoNcN4jauZToH1ZpvrAzo2JoNnJAxX0KeGyBXvlr8Ed+LV87hn4ZG5c1BjfRGcXi 7Zow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=aKnc58k0ZanDuaW5DMWuEx42gXkp9LxDYyM8CKqt4s8=; b=wwtXyQb3lZPSz5nVOOcDpY/wv40Pe2gpVelDDzlG1Q6EV8ioOd6aXI0MJjZHPyeWLy N281ZsHxJrzgXTJ1zVHrQzGLuy/kevTCS+aF9HW7nTjF1IYmEgRkGMmMm3WMmRfetKN0 otZBHUl5h8SjUiKWJ6bRMIBPBdVdPYtEfwwgVzueAiq4b2WosOB23Mf7DnS3EVNPtjye B1mKcMuKS0qAkrsw+eWJgKlcapqFQXhBQ85hPPRRjTHaK4Iwm69qWfF8FqqvsqHFhjWe NFIJT/OTte9y4wpFhQJKZuJx6dsPvRDNLWktPh2QdPeLo+s+qFZ5GpuD0Z9BmXXrukpo AuAw== X-Gm-Message-State: AFqh2krRlPoCVongokztj5cppqfi8s81OaQcugKjDLdrKXSOD+rl+C9E IuBYeanA/oCYnUlCq4fDwSqf7Vzje5b0XQ== X-Google-Smtp-Source: AMrXdXtZSc+qiWGxVyCmJ8YCXtI9lku8514UzKoNSqdVvAopM12Zyfk3QtsNHRg2F2Alfq6KZNyCpw== X-Received: by 2002:a05:6402:1f09:b0:478:8375:5dd5 with SMTP id b9-20020a0564021f0900b0047883755dd5mr16250531edb.24.1672092200937; Mon, 26 Dec 2022 14:03:20 -0800 (PST) Received: from penguin.lxd ([87.116.176.120]) by smtp.googlemail.com with ESMTPSA id u1-20020aa7d541000000b0046951b43e84sm5111467edr.55.2022.12.26.14.03.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 14:03:20 -0800 (PST) From: Strahinja Jankovic X-Google-Original-From: Strahinja Jankovic To: Peter Maydell Cc: Beniamino Galvani , Niek Linnenbank , philmd@linaro.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org, Strahinja Jankovic Subject: [PATCH v3 4/7] hw/misc: AXP209 PMU Emulation Date: Mon, 26 Dec 2022 23:03:00 +0100 Message-Id: <20221226220303.14420-5-strahinja.p.jankovic@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> References: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::532; envelope-from=strahinjapjankovic@gmail.com; helo=mail-ed1-x532.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds minimal support for AXP-209 PMU. Most important is chip ID since U-Boot SPL expects version 0x1. Besides the chip ID register, reset values for two more registers used by A10 U-Boot SPL are covered. Signed-off-by: Strahinja Jankovic --- MAINTAINERS | 2 + hw/misc/Kconfig | 4 + hw/misc/axp209.c | 238 +++++++++++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 5 + 5 files changed, 250 insertions(+) create mode 100644 hw/misc/axp209.c diff --git a/MAINTAINERS b/MAINTAINERS index b270eb8e5b..354da68249 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -576,12 +576,14 @@ ARM Machines Allwinner-a10 M: Beniamino Galvani M: Peter Maydell +R: Strahinja Jankovic L: qemu-arm@nongnu.org S: Odd Fixes F: hw/*/allwinner* F: include/hw/*/allwinner* F: hw/arm/cubieboard.c F: docs/system/arm/cubieboard.rst +F: hw/misc/axp209.c Allwinner-h3 M: Niek Linnenbank diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 052fb54310..eaeddca277 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -180,4 +180,8 @@ config ALLWINNER_A10_CCM config ALLWINNER_A10_DRAMC bool +config AXP209_PMU + bool + depends on I2C + source macio/Kconfig diff --git a/hw/misc/axp209.c b/hw/misc/axp209.c new file mode 100644 index 0000000000..2908ed99a6 --- /dev/null +++ b/hw/misc/axp209.c @@ -0,0 +1,238 @@ +/* + * AXP-209 PMU Emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "trace.h" +#include "hw/i2c/i2c.h" +#include "migration/vmstate.h" + +#define TYPE_AXP209_PMU "axp209_pmu" + +#define AXP209(obj) \ + OBJECT_CHECK(AXP209I2CState, (obj), TYPE_AXP209_PMU) + +/* registers */ +enum { + REG_POWER_STATUS = 0x0u, + REG_OPERATING_MODE, + REG_OTG_VBUS_STATUS, + REG_CHIP_VERSION, + REG_DATA_CACHE_0, + REG_DATA_CACHE_1, + REG_DATA_CACHE_2, + REG_DATA_CACHE_3, + REG_DATA_CACHE_4, + REG_DATA_CACHE_5, + REG_DATA_CACHE_6, + REG_DATA_CACHE_7, + REG_DATA_CACHE_8, + REG_DATA_CACHE_9, + REG_DATA_CACHE_A, + REG_DATA_CACHE_B, + REG_POWER_OUTPUT_CTRL = 0x12u, + REG_DC_DC2_OUT_V_CTRL = 0x23u, + REG_DC_DC2_DVS_CTRL = 0x25u, + REG_DC_DC3_OUT_V_CTRL = 0x27u, + REG_LDO2_4_OUT_V_CTRL, + REG_LDO3_OUT_V_CTRL, + REG_VBUS_CH_MGMT = 0x30u, + REG_SHUTDOWN_V_CTRL, + REG_SHUTDOWN_CTRL, + REG_CHARGE_CTRL_1, + REG_CHARGE_CTRL_2, + REG_SPARE_CHARGE_CTRL, + REG_PEK_KEY_CTRL, + REG_DC_DC_FREQ_SET, + REG_CHR_TEMP_TH_SET, + REG_CHR_HIGH_TEMP_TH_CTRL, + REG_IPSOUT_WARN_L1, + REG_IPSOUT_WARN_L2, + REG_DISCHR_TEMP_TH_SET, + REG_DISCHR_HIGH_TEMP_TH_CTRL, + REG_IRQ_BANK_1_CTRL = 0x40u, + REG_IRQ_BANK_2_CTRL, + REG_IRQ_BANK_3_CTRL, + REG_IRQ_BANK_4_CTRL, + REG_IRQ_BANK_5_CTRL, + REG_IRQ_BANK_1_STAT = 0x48u, + REG_IRQ_BANK_2_STAT, + REG_IRQ_BANK_3_STAT, + REG_IRQ_BANK_4_STAT, + REG_IRQ_BANK_5_STAT, + REG_ADC_ACIN_V_H = 0x56u, + REG_ADC_ACIN_V_L, + REG_ADC_ACIN_CURR_H, + REG_ADC_ACIN_CURR_L, + REG_ADC_VBUS_V_H, + REG_ADC_VBUS_V_L, + REG_ADC_VBUS_CURR_H, + REG_ADC_VBUS_CURR_L, + REG_ADC_INT_TEMP_H, + REG_ADC_INT_TEMP_L, + REG_ADC_TEMP_SENS_V_H = 0x62u, + REG_ADC_TEMP_SENS_V_L, + REG_ADC_BAT_V_H = 0x78u, + REG_ADC_BAT_V_L, + REG_ADC_BAT_DISCHR_CURR_H, + REG_ADC_BAT_DISCHR_CURR_L, + REG_ADC_BAT_CHR_CURR_H, + REG_ADC_BAT_CHR_CURR_L, + REG_ADC_IPSOUT_V_H, + REG_ADC_IPSOUT_V_L, + REG_DC_DC_MOD_SEL = 0x80u, + REG_ADC_EN_1, + REG_ADC_EN_2, + REG_ADC_SR_CTRL, + REG_ADC_IN_RANGE, + REG_GPIO1_ADC_IRQ_RISING_TH, + REG_GPIO1_ADC_IRQ_FALLING_TH, + REG_TIMER_CTRL = 0x8au, + REG_VBUS_CTRL_MON_SRP, + REG_OVER_TEMP_SHUTDOWN = 0x8fu, + REG_GPIO0_FEAT_SET, + REG_GPIO_OUT_HIGH_SET, + REG_GPIO1_FEAT_SET, + REG_GPIO2_FEAT_SET, + REG_GPIO_SIG_STATE_SET_MON, + REG_GPIO3_SET, + REG_COULOMB_CNTR_CTRL = 0xb8u, + REG_POWER_MEAS_RES, + NR_REGS +}; + +#define AXP209_CHIP_VERSION_ID (0x01) +#define AXP209_DC_DC2_OUT_V_CTRL_RESET (0x16) +#define AXP209_IRQ_BANK_1_CTRL_RESET (0xd8) + +/* A simple I2C slave which returns values of ID or CNT register. */ +typedef struct AXP209I2CState { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + uint8_t regs[NR_REGS]; /* peripheral registers */ + uint8_t ptr; /* current register index */ + uint8_t count; /* counter used for tx/rx */ +} AXP209I2CState; + +/* Reset all counters and load ID register */ +static void axp209_reset_enter(Object *obj, ResetType type) +{ + AXP209I2CState *s = AXP209(obj); + + memset(s->regs, 0, NR_REGS); + s->ptr = 0; + s->count = 0; + s->regs[REG_CHIP_VERSION] = AXP209_CHIP_VERSION_ID; + s->regs[REG_DC_DC2_OUT_V_CTRL] = AXP209_DC_DC2_OUT_V_CTRL_RESET; + s->regs[REG_IRQ_BANK_1_CTRL] = AXP209_IRQ_BANK_1_CTRL_RESET; +} + +/* Handle events from master. */ +static int axp209_event(I2CSlave *i2c, enum i2c_event event) +{ + AXP209I2CState *s = AXP209(i2c); + + s->count = 0; + + return 0; +} + +/* Called when master requests read */ +static uint8_t axp209_rx(I2CSlave *i2c) +{ + AXP209I2CState *s = AXP209(i2c); + uint8_t ret = 0xff; + + if (s->ptr < NR_REGS) { + ret = s->regs[s->ptr++]; + } + + trace_axp209_rx(s->ptr - 1, ret); + + return ret; +} + +/* + * Called when master sends write. + * Update ptr with byte 0, then perform write with second byte. + */ +static int axp209_tx(I2CSlave *i2c, uint8_t data) +{ + AXP209I2CState *s = AXP209(i2c); + + if (s->count == 0) { + /* Store register address */ + s->ptr = data; + s->count++; + trace_axp209_select(data); + } else { + trace_axp209_tx(s->ptr, data); + if (s->ptr == REG_DC_DC2_OUT_V_CTRL) { + s->regs[s->ptr++] = data; + } + } + + return 0; +} + +static const VMStateDescription vmstate_axp209 = { + .name = TYPE_AXP209_PMU, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(regs, AXP209I2CState, NR_REGS), + VMSTATE_UINT8(count, AXP209I2CState), + VMSTATE_UINT8(ptr, AXP209I2CState), + VMSTATE_END_OF_LIST() + } +}; + +static void axp209_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + + rc->phases.enter = axp209_reset_enter; + dc->vmsd = &vmstate_axp209; + isc->event = axp209_event; + isc->recv = axp209_rx; + isc->send = axp209_tx; +} + +static const TypeInfo axp209_info = { + .name = TYPE_AXP209_PMU, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(AXP209I2CState), + .class_init = axp209_class_init +}; + +static void axp209_register_devices(void) +{ + type_register_static(&axp209_info); +} + +type_init(axp209_register_devices); diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 9eaa0750b5..448e14b531 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -45,6 +45,7 @@ specific_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-cpucfg.c' softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-sysctrl.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c')) +softmmu_ss.add(when: 'CONFIG_AXP209_PMU', if_true: files('axp209.c')) softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c')) softmmu_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c')) softmmu_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index c18bc0605e..c47876a902 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -23,6 +23,11 @@ allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" avr_power_read(uint8_t value) "power_reduc read value:%u" avr_power_write(uint8_t value) "power_reduc write value:%u" +# axp209.c +axp209_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 " : 0x%" PRIx8 +axp209_select(uint8_t reg) "Accessing reg 0x%" PRIx8 +axp209_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8 + # eccmemctl.c ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x" ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x" From patchwork Mon Dec 26 22:03:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Strahinja Jankovic X-Patchwork-Id: 1719542 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=bk88Xr9f; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NgsKR5dFFz23dc for ; Tue, 27 Dec 2022 09:05:15 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9vZH-0004pW-Qc; Mon, 26 Dec 2022 17:03:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p9vZ7-0004lY-5z; Mon, 26 Dec 2022 17:03:25 -0500 Received: from mail-ed1-x52a.google.com ([2a00:1450:4864:20::52a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9vZ5-0003Xk-M9; Mon, 26 Dec 2022 17:03:24 -0500 Received: by mail-ed1-x52a.google.com with SMTP id s5so16834605edc.12; Mon, 26 Dec 2022 14:03:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TYI62dQf9gn0f4gFAtfVXUEo9pYy6Fucsvct1OnfuTc=; b=bk88Xr9fTVl9PQX5obcmZzFU9vnDki9yIH/ycPwhg9JtaDy/pu47pPLVMQGlX4cZVM R0cuSRiYF85+xEatKACoM60C2VrgFtdOsBnAjS8e4lcJdn4+1G+RZbDN6OW/hblAPZMU brwtA2V9d/flXcEt2E3RrUfnpRMY16KOguHkl1u401NtEcYRYaRmliKWnV6Duh7NE+hm uquqNLNmVSxAaNQSZ0sZgAapN4LnXpkPI8ycsI7LqYJRQMoaH1OAJSCktQa0D76pGEVU ChtWU/Yrehhj8e541RKMCbM187WvJ14CkpxO0QRu3K3acnSIyHuRYgwVVvACy6C1T4r9 GAVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TYI62dQf9gn0f4gFAtfVXUEo9pYy6Fucsvct1OnfuTc=; b=Nj8QJ+srNLTynXRXuwONAy4zINK4nai9rsaZkYMMmcCMpLnaJeAOYsFZ9Ezuto6VmX pcNXDYhwtgGa+megybizaBX4PpDqgGM54lpG2tiH8U+vRx9P6gAR63sETrb3FzF4QvRx eQeejzE2Yv59RedI8wciVlO1Awb1jiTE6g2RyqnIz8RX76W8DhJCfeDVErzcHUcrpJiJ /18wefYe8JLl8CH+n38FIQ+j5eHKLIGkj4N5aUXsNvbMnJmqjmQq6S2YVZs6K8lLBqSE g+LtKD99L6EHxJZJjAm+sFv0HpSaWK8SgpEc1qD3f+pSz7v0NI8fQJtyeg0swXI0Aikq O7Hw== X-Gm-Message-State: AFqh2kq0/l9oA9OXMjTlKGtdzcR/B5GzGwPCzNZaBKFNGTYkrwjvxeYg tyv+g6jNWjFXqQDCPhM6gqw= X-Google-Smtp-Source: AMrXdXvtePPlzvqgHuO4XUVQoacAZlP0x/QpGldp3qNIoSxgQ1BI1jxJMos3Fq30xDqrvvGjpOwI/w== X-Received: by 2002:a05:6402:1217:b0:461:e5d1:73c5 with SMTP id c23-20020a056402121700b00461e5d173c5mr14762064edw.32.1672092201825; Mon, 26 Dec 2022 14:03:21 -0800 (PST) Received: from penguin.lxd ([87.116.176.120]) by smtp.googlemail.com with ESMTPSA id u1-20020aa7d541000000b0046951b43e84sm5111467edr.55.2022.12.26.14.03.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 14:03:21 -0800 (PST) From: Strahinja Jankovic X-Google-Original-From: Strahinja Jankovic To: Peter Maydell Cc: Beniamino Galvani , Niek Linnenbank , philmd@linaro.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org, Strahinja Jankovic Subject: [PATCH v3 5/7] hw/arm: Add AXP209 to Cubieboard Date: Mon, 26 Dec 2022 23:03:01 +0100 Message-Id: <20221226220303.14420-6-strahinja.p.jankovic@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> References: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::52a; envelope-from=strahinjapjankovic@gmail.com; helo=mail-ed1-x52a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org SPL Boot for Cubieboard expects AXP209 connected to I2C0 bus. Signed-off-by: Strahinja Jankovic Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/Kconfig | 1 + hw/arm/cubieboard.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index eefe1fd134..da6741f112 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -323,6 +323,7 @@ config ALLWINNER_A10 select ALLWINNER_A10_DRAMC select ALLWINNER_EMAC select ALLWINNER_I2C + select AXP209_PMU select SERIAL select UNIMP diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 5e3372a3c7..dca257620d 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -20,6 +20,7 @@ #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-a10.h" +#include "hw/i2c/i2c.h" static struct arm_boot_info cubieboard_binfo = { .loader_start = AW_A10_SDRAM_BASE, @@ -34,6 +35,7 @@ static void cubieboard_init(MachineState *machine) BlockBackend *blk; BusState *bus; DeviceState *carddev; + I2CBus *i2c; /* BIOS is not supported by this board */ if (machine->firmware) { @@ -80,6 +82,10 @@ static void cubieboard_init(MachineState *machine) exit(1); } + /* Connect AXP 209 */ + i2c = I2C_BUS(qdev_get_child_bus(DEVICE(&a10->i2c0), "i2c")); + i2c_slave_create_simple(i2c, "axp209_pmu", 0x34); + /* Retrieve SD bus */ di = drive_get(IF_SD, 0, 0); blk = di ? blk_by_legacy_dinfo(di) : NULL; From patchwork Mon Dec 26 22:03:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Strahinja Jankovic X-Patchwork-Id: 1719539 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=VADlUb1W; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NgsJH4wtgz23dx for ; Tue, 27 Dec 2022 09:04:15 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9vZK-0004wJ-E6; Mon, 26 Dec 2022 17:03:38 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p9vZ8-0004lf-7y; Mon, 26 Dec 2022 17:03:26 -0500 Received: from mail-ed1-x52d.google.com ([2a00:1450:4864:20::52d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9vZ6-0003YU-7b; Mon, 26 Dec 2022 17:03:26 -0500 Received: by mail-ed1-x52d.google.com with SMTP id z11so988748ede.1; Mon, 26 Dec 2022 14:03:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=y+PRXmPQugGuVep+60kB3IBMZ7HJS9Hw2ql27KTSsVU=; b=VADlUb1WWEdPeZK8/MvxUsFKKX8w3s9YU6aEOYpw7CNhjiL5OMlsbB+vLKZs0Ke8ut I0KV/5h0CjDgXkMos+ZGxEtjlsEXOJCOus/fi6BICEHD+k9zMHeOMS5CQEwY5XrbWXRl lz88yi/F6lbgjH+/eGskHUHCNk6l6nbP7RDXT7u/s3ibl20pQ0CDmz/2WcSmIuoAY6qd Be45wlIN+UbWn0f8lm7NDLwdhCA+iuCir+eYuvBY1JJYHR+hNsujdp6Hvyo/j+4l4PEd cT+7PI7JAyUVXsbB1iTA6QlT5jgdmppKIa3//T+v/wv5nW8lG+QUEcAICzMPruowQ8sq 36RQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=y+PRXmPQugGuVep+60kB3IBMZ7HJS9Hw2ql27KTSsVU=; b=i9mF/KI3fswy9W0P0ZT29tG4GyNxdme1vIHAYRjj4HYoSamJxi0ydOX3iqBK9X0rA9 SKO3p6SVB1rVdRvhF9iCTvSLZzPi6zu7XRehzOm8zg540SvIq9bEXVr2HzHw/4+/5h96 3GZfcWpXMgCb5ZrLMM/Bz0J2xBIx/SvMFOJdb0uPJaAcdmEHYtgRSLHzkX5OKFUcELMa hnegk57udAU9eZubLcYpJ74YZrUwPFgJpkAA3tkgZGlEPJWAuQfAXGuTh+vLuJEXKrs5 gHhH7I3bayR0zbKLxQx4Y4aEO2lR8T3X6n+hneyhzr9qAVWE8KDtC/BXYMVvvTHu/a3L D5Dw== X-Gm-Message-State: AFqh2ko3f61HnNE0bXha64iNHfSJluEHBNN00NdneDXyNGp7vwlU64YH yDqNI78Te1a5FeKXObhnX2w= X-Google-Smtp-Source: AMrXdXuI2w/zn6NwL/Czz+tlQm4BhimTuMjKK2MGhEKb95hJKnhIHJyPJcouwQXE6w8ARO3TX3aGnw== X-Received: by 2002:a05:6402:2b89:b0:46c:aa8b:da5c with SMTP id fj9-20020a0564022b8900b0046caa8bda5cmr16092680edb.33.1672092202553; Mon, 26 Dec 2022 14:03:22 -0800 (PST) Received: from penguin.lxd ([87.116.176.120]) by smtp.googlemail.com with ESMTPSA id u1-20020aa7d541000000b0046951b43e84sm5111467edr.55.2022.12.26.14.03.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 14:03:22 -0800 (PST) From: Strahinja Jankovic X-Google-Original-From: Strahinja Jankovic To: Peter Maydell Cc: Beniamino Galvani , Niek Linnenbank , philmd@linaro.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org, Strahinja Jankovic Subject: [PATCH v3 6/7] hw/arm: Allwinner A10 enable SPL load from MMC Date: Mon, 26 Dec 2022 23:03:02 +0100 Message-Id: <20221226220303.14420-7-strahinja.p.jankovic@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> References: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::52d; envelope-from=strahinjapjankovic@gmail.com; helo=mail-ed1-x52d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch enables copying of SPL from MMC if `-kernel` parameter is not passed when starting QEMU. SPL is copied to SRAM_A. The approach is reused from Allwinner H3 implementation. Tested with Armbian and custom Yocto image. Signed-off-by: Strahinja Jankovic Reviewed-by: Niek Linnenbank --- hw/arm/allwinner-a10.c | 18 ++++++++++++++++++ hw/arm/cubieboard.c | 5 +++++ include/hw/arm/allwinner-a10.h | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 17e439777e..dc1966ff7a 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -24,7 +24,9 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/usb/hcd-ohci.h" +#include "hw/loader.h" +#define AW_A10_SRAM_A_BASE 0x00000000 #define AW_A10_DRAMC_BASE 0x01c01000 #define AW_A10_MMC0_BASE 0x01c0f000 #define AW_A10_CCM_BASE 0x01c20000 @@ -38,6 +40,22 @@ #define AW_A10_RTC_BASE 0x01c20d00 #define AW_A10_I2C0_BASE 0x01c2ac00 +void allwinner_a10_bootrom_setup(AwA10State *s, BlockBackend *blk) +{ + const int64_t rom_size = 32 * KiB; + g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size); + + if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) { + error_setg(&error_fatal, "%s: failed to read BlockBackend data", + __func__); + return; + } + + rom_add_blob("allwinner-a10.bootrom", buffer, rom_size, + rom_size, AW_A10_SRAM_A_BASE, + NULL, NULL, NULL, NULL, false); +} + static void aw_a10_init(Object *obj) { AwA10State *s = AW_A10(obj); diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index dca257620d..71a7df1508 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -99,6 +99,11 @@ static void cubieboard_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, machine->ram); + /* Load target kernel or start using BootROM */ + if (!machine->kernel_filename && blk && blk_is_available(blk)) { + /* Use Boot ROM to copy data from SD card to SRAM */ + allwinner_a10_bootrom_setup(a10, blk); + } /* TODO create and connect IDE devices for ide_drive_get() */ cubieboard_binfo.ram_size = machine->ram_size; diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h index 763935fca9..e2e27e616a 100644 --- a/include/hw/arm/allwinner-a10.h +++ b/include/hw/arm/allwinner-a10.h @@ -15,6 +15,7 @@ #include "hw/misc/allwinner-a10-ccm.h" #include "hw/misc/allwinner-a10-dramc.h" #include "hw/i2c/allwinner-i2c.h" +#include "sysemu/block-backend.h" #include "target/arm/cpu.h" #include "qom/object.h" @@ -47,4 +48,24 @@ struct AwA10State { OHCISysBusState ohci[AW_A10_NUM_USB]; }; +/** + * Emulate Boot ROM firmware setup functionality. + * + * A real Allwinner A10 SoC contains a Boot ROM + * which is the first code that runs right after + * the SoC is powered on. The Boot ROM is responsible + * for loading user code (e.g. a bootloader) from any + * of the supported external devices and writing the + * downloaded code to internal SRAM. After loading the SoC + * begins executing the code written to SRAM. + * + * This function emulates the Boot ROM by copying 32 KiB + * of data at offset 8 KiB from the given block device and writes it to + * the start of the first internal SRAM memory. + * + * @s: Allwinner A10 state object pointer + * @blk: Block backend device object pointer + */ +void allwinner_a10_bootrom_setup(AwA10State *s, BlockBackend *blk); + #endif From patchwork Mon Dec 26 22:03:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Strahinja Jankovic X-Patchwork-Id: 1719537 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=dYwpNCzv; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NgsJF5t3tz23f2 for ; Tue, 27 Dec 2022 09:04:12 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9vZJ-0004uL-VJ; Mon, 26 Dec 2022 17:03:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p9vZ8-0004lh-LY; Mon, 26 Dec 2022 17:03:26 -0500 Received: from mail-ed1-x52b.google.com ([2a00:1450:4864:20::52b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9vZ6-0003Yh-TT; Mon, 26 Dec 2022 17:03:26 -0500 Received: by mail-ed1-x52b.google.com with SMTP id s5so16834668edc.12; Mon, 26 Dec 2022 14:03:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JWN1aEv28Joh2/ZLVeS7ANU8mdC3qcchN8nXt3z+4VY=; b=dYwpNCzvVKZCI8Xm3ii4afLZlEeS5envIDmcaeKPnfrnSPqcNRLf9ob/CGNpKUmWh5 wR18qWwV/7baUdvwXjFfIUkH50wGDJqU7OY/LGXNZtkDF6CoVPYZ0FB4RXGk7VBD+Xch 0psIW/pfT0LGIW1tR4tPLr0pRQVbuY/UMlW+1ZK3T0/PljXi48XpDzxg9no68RZonzJY PtU/jR7Q+fg9DRjLHroA9i9+Z2ZxaQb6G4dkd4TKJQRd3K0yhw0vRpSNSLmO5aByryA4 8v/Kd1qEBzR+ncesJp6P86GZyLiTrNzuCc+vMu0A52ijiO9mNg1HtGXjAJLFGSDFU0GG Uq8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JWN1aEv28Joh2/ZLVeS7ANU8mdC3qcchN8nXt3z+4VY=; b=CV53wX6CK/6GORSx6P+uviUfkceTpMpEcSb1P3FbE3Vl8jNUynF8aH05m+AtgxRdns CwLsJIzh20du9LllIe8m6MhT2jEBKXe5ib7XqFO3aOQCyH4muh1PagShv5tUVvQLQ/Do zweFF0BGDLs1h/ZhFB+uPgpHT39wY1hr3WnOglrDbPb61gJyIrVFVD+/6FOmH6UIIQtv si2eG6X3Vrl9Hu4+BYXinAf+iQfu24DbYjoEHucpYDQEbhIDtFBWe0GZwfNvFpSecgrf a2wl/GSOwMwq3qcRh04fgBzkbh6WM5KUGvJpiw87wat+xFyRSxRBUYrN9SH1FBErzZX+ f9TA== X-Gm-Message-State: AFqh2konTFkR1kypZW8qyZiXy6p2CO2PqjICYN1h1sdRNGu2keZyGPVP DFw34G0m99pMM+WUEJG7LtzEP9FnnkMp7Q== X-Google-Smtp-Source: AMrXdXuVFrlCz2Bti4L3Jmmp4N0S5utQz0/MmvbhNn/1roA7q65107Ikxgcauj9iJGgT7q46h4kdDg== X-Received: by 2002:a05:6402:13c4:b0:46a:be66:c0e2 with SMTP id a4-20020a05640213c400b0046abe66c0e2mr16955326edx.28.1672092203329; Mon, 26 Dec 2022 14:03:23 -0800 (PST) Received: from penguin.lxd ([87.116.176.120]) by smtp.googlemail.com with ESMTPSA id u1-20020aa7d541000000b0046951b43e84sm5111467edr.55.2022.12.26.14.03.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 14:03:23 -0800 (PST) From: Strahinja Jankovic X-Google-Original-From: Strahinja Jankovic To: Peter Maydell Cc: Beniamino Galvani , Niek Linnenbank , philmd@linaro.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org, Strahinja Jankovic Subject: [PATCH v3 7/7] tests/avocado: Add SD boot test to Cubieboard Date: Mon, 26 Dec 2022 23:03:03 +0100 Message-Id: <20221226220303.14420-8-strahinja.p.jankovic@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> References: <20221226220303.14420-1-strahinja.p.jankovic@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::52b; envelope-from=strahinjapjankovic@gmail.com; helo=mail-ed1-x52b.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Cubieboard now can boot directly from SD card, without the need to pass `-kernel` parameter. Update Avocado tests to cover this functionality. Signed-off-by: Strahinja Jankovic Reviewed-by: Niek Linnenbank Tested-by: Niek Linnenbank --- tests/avocado/boot_linux_console.py | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index ec07c64291..8c1d981586 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -620,6 +620,53 @@ def test_arm_cubieboard_sata(self): 'sda') # cubieboard's reboot is not functioning; omit reboot test. + @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited') + def test_arm_cubieboard_openwrt_22_03_2(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:cubieboard + :avocado: tags=device:sd + """ + + # This test download a 7.5 MiB compressed image and expand it + # to 126 MiB. + image_url = ('https://downloads.openwrt.org/releases/22.03.2/targets/' + 'sunxi/cortexa8/openwrt-22.03.2-sunxi-cortexa8-' + 'cubietech_a10-cubieboard-ext4-sdcard.img.gz') + image_hash = ('94b5ecbfbc0b3b56276e5146b899eafa' + '2ac5dc2d08733d6705af9f144f39f554') + image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + image_path = archive.extract(image_path_gz, self.workdir) + image_pow2ceil_expand(image_path) + + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw', + '-nic', 'user', + '-no-reboot') + self.vm.launch() + + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'usbcore.nousb ' + 'noreboot') + + self.wait_for_console_pattern('U-Boot SPL') + + interrupt_interactive_console_until_pattern( + self, 'Hit any key to stop autoboot:', '=>') + exec_command_and_wait_for_pattern(self, "setenv extraargs '" + + kernel_command_line + "'", '=>') + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...'); + + self.wait_for_console_pattern( + 'Please press Enter to activate this console.') + + exec_command_and_wait_for_pattern(self, ' ', 'root@') + + exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo', + 'Allwinner sun4i/sun5i') + # cubieboard's reboot is not functioning; omit reboot test. + @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') def test_arm_quanta_gsj(self): """