From nobody Tue Apr 15 15:36:20 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488220925129631.2165313576181; Mon, 27 Feb 2017 10:42:05 -0800 (PST) Received: from localhost ([::1]:55704 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ciQFF-0000Oe-OS for importer@patchew.org; Mon, 27 Feb 2017 13:42:01 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52257) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ciPfl-0002SF-3Z for qemu-devel@nongnu.org; Mon, 27 Feb 2017 13:05:23 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ciPfg-0001wd-O7 for qemu-devel@nongnu.org; Mon, 27 Feb 2017 13:05:21 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:48681) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ciPfg-0001uO-Aw for qemu-devel@nongnu.org; Mon, 27 Feb 2017 13:05:16 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1ciPff-0002Sz-J5 for qemu-devel@nongnu.org; Mon, 27 Feb 2017 18:05:15 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Date: Mon, 27 Feb 2017 18:04:58 +0000 Message-Id: <1488218699-31035-30-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488218699-31035-1-git-send-email-peter.maydell@linaro.org> References: <1488218699-31035-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PULL 29/30] hw/arm/exynos: Fix Linux kernel division by zero for PLLs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Krzysztof Kozlowski Without any clock controller, the Linux kernel was hitting division by zero during boot or with clk_summary: [ 0.000000] [] (unwind_backtrace) from [] (show_stac= k+0x10/0x14) [ 0.000000] [] (show_stack) from [] (dump_stack+0x88= /0x9c) [ 0.000000] [] (dump_stack) from [] (Ldiv0+0x8/0x10) [ 0.000000] [] (Ldiv0) from [] (samsung_pll45xx_reca= lc_rate+0x58/0x74) [ 0.000000] [] (samsung_pll45xx_recalc_rate) from []= (clk_register+0x39c/0x63c) [ 0.000000] [] (clk_register) from [] (samsung_clk_r= egister_pll+0x2e0/0x3d4) [ 0.000000] [] (samsung_clk_register_pll) from [] (e= xynos4_clk_init+0x1b0/0x5e4) [ 0.000000] [] (exynos4_clk_init) from [] (of_clk_in= it+0x17c/0x210) [ 0.000000] [] (of_clk_init) from [] (time_init+0x24= /0x2c) [ 0.000000] [] (time_init) from [] (start_kernel+0x2= 4c/0x38c) [ 0.000000] [] (start_kernel) from [<4020807c>] (0x4020807c) Provide stub for clock controller returning reset values for PLLs. Signed-off-by: Krzysztof Kozlowski Message-id: 20170226200142.31169-1-krzk@kernel.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/misc/Makefile.objs | 2 +- hw/arm/exynos4210.c | 6 ++ hw/misc/exynos4210_clk.c | 164 +++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 hw/misc/exynos4210_clk.c diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 57a4406..c8b4893 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -26,7 +26,7 @@ obj-$(CONFIG_IVSHMEM) +=3D ivshmem.o obj-$(CONFIG_REALVIEW) +=3D arm_sysctl.o obj-$(CONFIG_NSERIES) +=3D cbus.o obj-$(CONFIG_ECCMEMCTL) +=3D eccmemctl.o -obj-$(CONFIG_EXYNOS4) +=3D exynos4210_pmu.o +obj-$(CONFIG_EXYNOS4) +=3D exynos4210_pmu.o exynos4210_clk.o obj-$(CONFIG_IMX) +=3D imx_ccm.o obj-$(CONFIG_IMX) +=3D imx31_ccm.o obj-$(CONFIG_IMX) +=3D imx25_ccm.o diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index be3c96d..a0ecbe8 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/boards.h" #include "sysemu/sysemu.h" @@ -74,6 +75,9 @@ /* PMU SFR base address */ #define EXYNOS4210_PMU_BASE_ADDR 0x10020000 =20 +/* Clock controller SFR base address */ +#define EXYNOS4210_CLK_BASE_ADDR 0x10030000 + /* Display controllers (FIMD) */ #define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 =20 @@ -297,6 +301,8 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_m= em, */ sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL); =20 + sysbus_create_simple("exynos4210.clk", EXYNOS4210_CLK_BASE_ADDR, NULL); + /* PWM */ sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR, s->irq_table[exynos4210_get_irq(22, 0)], diff --git a/hw/misc/exynos4210_clk.c b/hw/misc/exynos4210_clk.c new file mode 100644 index 0000000..81862c0 --- /dev/null +++ b/hw/misc/exynos4210_clk.c @@ -0,0 +1,164 @@ +/* + * Exynos4210 Clock Controller Emulation + * + * Copyright (c) 2017 Krzysztof Kozlowski + * + * 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 WI= THOUT + * 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 "hw/sysbus.h" +#include "qemu/log.h" + +#define TYPE_EXYNOS4210_CLK "exynos4210.clk" +#define EXYNOS4210_CLK(obj) \ + OBJECT_CHECK(Exynos4210ClkState, (obj), TYPE_EXYNOS4210_CLK) + +#define CLK_PLL_LOCKED BIT(29) + +#define EXYNOS4210_CLK_REGS_MEM_SIZE 0x15104 + +typedef struct Exynos4210Reg { + const char *name; /* for debug only */ + uint32_t offset; + uint32_t reset_value; +} Exynos4210Reg; + +/* Clock controller register base: 0x10030000 */ +static const Exynos4210Reg exynos4210_clk_regs[] =3D { + {"EPLL_LOCK", 0xc010, 0x00000fff}, + {"VPLL_LOCK", 0xc020, 0x00000fff}, + {"EPLL_CON0", 0xc110, 0x00300301 | CLK_PLL_LOCKED}, + {"EPLL_CON1", 0xc114, 0x00000000}, + {"VPLL_CON0", 0xc120, 0x00240201 | CLK_PLL_LOCKED}, + {"VPLL_CON1", 0xc124, 0x66010464}, + {"APLL_LOCK", 0x14000, 0x00000fff}, + {"MPLL_LOCK", 0x14004, 0x00000fff}, + {"APLL_CON0", 0x14100, 0x00c80601 | CLK_PLL_LOCKED}, + {"APLL_CON1", 0x14104, 0x0000001c}, + {"MPLL_CON0", 0x14108, 0x00c80601 | CLK_PLL_LOCKED}, + {"MPLL_CON1", 0x1410c, 0x0000001c}, +}; + +#define EXYNOS4210_REGS_NUM ARRAY_SIZE(exynos4210_clk_regs) + +typedef struct Exynos4210ClkState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + uint32_t reg[EXYNOS4210_REGS_NUM]; +} Exynos4210ClkState; + +static uint64_t exynos4210_clk_read(void *opaque, hwaddr offset, + unsigned size) +{ + const Exynos4210ClkState *s =3D (Exynos4210ClkState *)opaque; + const Exynos4210Reg *regs =3D exynos4210_clk_regs; + unsigned int i; + + for (i =3D 0; i < EXYNOS4210_REGS_NUM; i++) { + if (regs->offset =3D=3D offset) { + return s->reg[i]; + } + regs++; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; +} + +static void exynos4210_clk_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + Exynos4210ClkState *s =3D (Exynos4210ClkState *)opaque; + const Exynos4210Reg *regs =3D exynos4210_clk_regs; + unsigned int i; + + for (i =3D 0; i < EXYNOS4210_REGS_NUM; i++) { + if (regs->offset =3D=3D offset) { + s->reg[i] =3D val; + return; + } + regs++; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n", + __func__, (uint32_t)offset); +} + +static const MemoryRegionOps exynos4210_clk_ops =3D { + .read =3D exynos4210_clk_read, + .write =3D exynos4210_clk_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + .unaligned =3D false + } +}; + +static void exynos4210_clk_reset(DeviceState *dev) +{ + Exynos4210ClkState *s =3D EXYNOS4210_CLK(dev); + unsigned int i; + + /* Set default values for registers */ + for (i =3D 0; i < EXYNOS4210_REGS_NUM; i++) { + s->reg[i] =3D exynos4210_clk_regs[i].reset_value; + } +} + +static void exynos4210_clk_init(Object *obj) +{ + Exynos4210ClkState *s =3D EXYNOS4210_CLK(obj); + SysBusDevice *dev =3D SYS_BUS_DEVICE(obj); + + /* memory mapping */ + memory_region_init_io(&s->iomem, obj, &exynos4210_clk_ops, s, + TYPE_EXYNOS4210_CLK, EXYNOS4210_CLK_REGS_MEM_SIZ= E); + sysbus_init_mmio(dev, &s->iomem); +} + +static const VMStateDescription exynos4210_clk_vmstate =3D { + .name =3D TYPE_EXYNOS4210_CLK, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32_ARRAY(reg, Exynos4210ClkState, EXYNOS4210_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +static void exynos4210_clk_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->reset =3D exynos4210_clk_reset; + dc->vmsd =3D &exynos4210_clk_vmstate; +} + +static const TypeInfo exynos4210_clk_info =3D { + .name =3D TYPE_EXYNOS4210_CLK, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(Exynos4210ClkState), + .instance_init =3D exynos4210_clk_init, + .class_init =3D exynos4210_clk_class_init, +}; + +static void exynos4210_clk_register(void) +{ + qemu_log_mask(LOG_GUEST_ERROR, "Clock init\n"); + type_register_static(&exynos4210_clk_info); +} + +type_init(exynos4210_clk_register) --=20 2.7.4