From patchwork Sat Oct 10 13:57:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303207 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 40D8AC433E7 for ; Sat, 10 Oct 2020 13:58:42 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DA41622283 for ; Sat, 10 Oct 2020 13:58:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="PCdz6zyp" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DA41622283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:51742 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFOS-0003Es-Vf for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 09:58:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40604) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMz-0000wR-7T; Sat, 10 Oct 2020 09:57:09 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43436) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMv-0004IJ-Pj; Sat, 10 Oct 2020 09:57:08 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 713A4C60159; Sat, 10 Oct 2020 13:57:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338222; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=47VbYAct+c9hftOWPp/AO6VMc8Ptj3zoGkrDEH1t/nk=; b=PCdz6zypiqyl3oQEdzb13Qd3tW/SiAMtiwLD/9vEvzURXA9/bcqZB6uxL//zqIlEMWrKuK ap9AI2gA1wmsEAMMHVivwEjcEyVb80E4tPNhxAz4Y0/WhHYdn0Z5RjiAZNvTjakAe3eAJx TE7gDSeR4XxdW/e4D1EPWdchR8WuB/afYzrz6u9k0wm5CetgGc5d3KmYtG+nUVHLhGVe4v NSHhOSUDY9+V7DedkRV6NFI/G+q7KAnoS0ztouQmpfouDF6Mp2kgXDb6B+kOIjBj4Ep+hd 7e+D9Z4e74eHjaMnqVdHFEvxvXv1clGLlB3oK9LbRSnJzzciDBhmD/nLHbiImw== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 01/15] hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro Date: Sat, 10 Oct 2020 15:57:45 +0200 Message-Id: <20201010135759.437903-2-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=47VbYAct+c9hftOWPp/AO6VMc8Ptj3zoGkrDEH1t/nk=; b=IXxYOfNIwtoXcwdehyh1YFHmnbhRtZx9WdjoKBHHX6mwB3/UkSTWcw2yT/mvjUcvfCMQXV OH3SjqNyXzRz7f32b4jYMyzjLdOt8gNgcQFaj3lMsdY9T6mLgbyBVCONmbfwmwxOj0aqtl dzBwkm6y31ZOyuX4kYAMm5cpENtgPoC/afvduG5eJ8dIJd61z7+gP0HTt8fxXciUbr5CyE dlwo/JRDaYV7k4xxSNT4u31YlBtZOuhX4DWzbeeAtsIY70gx8Z2t+pU6XGq6PoFpzA0Im1 Uf3u79DMIRSZiF3PRxfZl0Lxfd7ykHNs06Q+Je8jewq/G/zkmGZj5m0gXKhrxA== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338223; a=rsa-sha256; cv=none; b=Plwbxddqj3Yd0vMelljlNlLGt1EK24nCYE+U7KZYC4BONqLXvqEfEpaATlwerZbVLdb6zAewSXnbi8eUyIX0K8lWkS9U/+Xpq2eiAwlAnDIX7H65Ki6qjK02RBbH7ryThyuCjZOrKLPyeDWPbJhwNbEQ1aAiH7qBOvfx1zdMoFijfJMkOHiZUJB0hmecUVCgpBj+Gqr7VXFdb5U8HeltAS3DMUqbee/Q37HodKnCFcX1DXKW6aHwM4NNeyRrSpCVonl1rmk27MZYNGMNFyxWA/0GSABqjk2/3TPn4vW5hhV/s6OURHhOJ77uPCUYSXow9mvraWRrSE/bXH2Pu1B2Xg== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Peter Maydell , Luc Michel , =?utf-8?q?Ph?= =?utf-8?q?ilippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Damien Hedde Signed-off-by: Luc Michel --- include/hw/clock.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/hw/clock.h b/include/hw/clock.h index d357594df9..c93e6113cd 100644 --- a/include/hw/clock.h +++ b/include/hw/clock.h @@ -79,10 +79,15 @@ struct Clock { extern const VMStateDescription vmstate_clock; #define VMSTATE_CLOCK(field, state) \ VMSTATE_CLOCK_V(field, state, 0) #define VMSTATE_CLOCK_V(field, state, version) \ VMSTATE_STRUCT_POINTER_V(field, state, version, vmstate_clock, Clock) +#define VMSTATE_ARRAY_CLOCK(field, state, num) \ + VMSTATE_ARRAY_CLOCK_V(field, state, num, 0) +#define VMSTATE_ARRAY_CLOCK_V(field, state, num, version) \ + VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(field, state, num, version, \ + vmstate_clock, Clock) /** * clock_setup_canonical_path: * @clk: clock * From patchwork Sat Oct 10 13:57:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 271614 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 11C98C433DF for ; Sat, 10 Oct 2020 13:58:59 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A778722283 for ; Sat, 10 Oct 2020 13:58:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="DzlKUovN" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A778722283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:52466 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFOi-0003XU-Bg for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 09:58:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40606) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMz-0000wd-Dc; Sat, 10 Oct 2020 09:57:09 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43438) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMv-0004IH-QJ; Sat, 10 Oct 2020 09:57:09 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 46240C6015A; Sat, 10 Oct 2020 13:57:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XaCzO636ACRdji0tNZeGIPhvB1Q/Jymj/673A6eSpG4=; b=DzlKUovNJ5upMw/LDjR8KxykvnTAgZNYZhEu+paT2Aaev3zPvOxga6ndKdbMMLTesb94Q/ AVwu6B/lQS7Il7HjmykrnFadQsYheK5yMzUTezC7O8eThKuGZwLsGYJnJeV5Njfpv78r/T tyAkITgRAiksELr7lWbervFa4a9o9GaIthlrqN8GXZ10NKEn2thr1z21lpHP2riPAKFnh6 2nmVaU/IBl5OrtqdFvWJ/lEfIwgYUIfKUXk156x08w1CggXmLSbpNKeAi8kkTCt9/aDW6T F1Cus+lAhXi07oa98XqBIab5corqcC4NJnKiebr7sm4rCbCTkKWxHAYiFs5VJQ== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 02/15] hw/core/clock: trace clock values in Hz instead of ns Date: Sat, 10 Oct 2020 15:57:46 +0200 Message-Id: <20201010135759.437903-3-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XaCzO636ACRdji0tNZeGIPhvB1Q/Jymj/673A6eSpG4=; b=BYquxj+hzg6zZJAQR61dKxt9jYRXv/VR1IN4VbExaNT9ZkhDul/8jBSauOpo5pOk1OJVDr eyrL68xMYTd+T4MjaAnzO8sAbgfKfgWdU/qNNTn4zX38xPUT4+5wlKvI9KGCnbgqEz+pr7 ybnsi3Gd5987wy+qfwt2S2qY0ynpCNneT8AgHVPJeIlPoIpVY0G3hEDFAZKLZgiFBlydTN rwQ9grYwNTNWkStPLmXJlYZ0zWOeMODgJDZ3tRQpDEBIpUWxCB60zgn9YVwXM5dTGOfMr0 fCmKZECbXTQRzfP5KDerE+qtGtJQnxmK5l1s4YmMP/4EFcNoaueN+1dPNOtSvg== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338223; a=rsa-sha256; cv=none; b=MjMfdUO3I+EwfJh3VsJhcl5X4XAxgyrYjs3Rheiw6/KfvqI6Pyld/tULgUQUKB1gzSv+RmhU4gb0ft7SEdP9NFtMBokcsd1L946Y4OQvCteZBTRrTKJYnY0eFLFD4NB+B0yuMDxfcSj4L0+b1mHNyLFTUWypXurNATv/5XnfvLcPN1A9SJyWmoVTIZVteq95AtScgl3Z8gwD4QHEWE/c92xhs9B5LqTkMyUfh0M5sUOafUC0UpBJQ2mVbH/evdv+TAEs31vf0r/KHUJkTkZ4tXAg7u33aj/uNgP9Y7g5Q/PjRW190/j5gaGhSYvtfoRINCfLFPOx8+fjWpJEqwMNIg== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Peter Maydell , Luc Michel , =?utf-8?q?Ph?= =?utf-8?q?ilippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The nanosecond unit greatly limits the dynamic range we can display in clock value traces, for values in the order of 1GHz and more. The internal representation can go way beyond this value and it is quite common for today's clocks to be within those ranges. For example, a frequency between 500MHz+ and 1GHz will be displayed as 1ns. Beyond 1GHz, it will show up as 0ns. Replace nanosecond periods traces with frequencies in the Hz unit to have more dynamic range in the trace output. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Damien Hedde Signed-off-by: Luc Michel Tested-by: Philippe Mathieu-Daudé --- hw/core/clock.c | 6 +++--- hw/core/trace-events | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/core/clock.c b/hw/core/clock.c index 7066282f7b..81184734e0 100644 --- a/hw/core/clock.c +++ b/hw/core/clock.c @@ -37,12 +37,12 @@ void clock_clear_callback(Clock *clk) bool clock_set(Clock *clk, uint64_t period) { if (clk->period == period) { return false; } - trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period), - CLOCK_PERIOD_TO_NS(period)); + trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period), + CLOCK_PERIOD_TO_HZ(period)); clk->period = period; return true; } @@ -52,11 +52,11 @@ static void clock_propagate_period(Clock *clk, bool call_callbacks) QLIST_FOREACH(child, &clk->children, sibling) { if (child->period != clk->period) { child->period = clk->period; trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk), - CLOCK_PERIOD_TO_NS(clk->period), + CLOCK_PERIOD_TO_HZ(clk->period), call_callbacks); if (call_callbacks && child->callback) { child->callback(child->callback_opaque); } clock_propagate_period(child, call_callbacks); diff --git a/hw/core/trace-events b/hw/core/trace-events index 1ac60ede6b..360ddeb2c8 100644 --- a/hw/core/trace-events +++ b/hw/core/trace-events @@ -29,8 +29,8 @@ resettable_phase_exit_end(void *obj, const char *objtype, unsigned count) "obj=% resettable_transitional_function(void *obj, const char *objtype) "obj=%p(%s)" # clock.c clock_set_source(const char *clk, const char *src) "'%s', src='%s'" clock_disconnect(const char *clk) "'%s'" -clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64 +clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', %"PRIu64"Hz->%"PRIu64"Hz" clock_propagate(const char *clk) "'%s'" -clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d" +clock_update(const char *clk, const char *src, uint64_t hz, int cb) "'%s', src='%s', val=%"PRIu64"Hz cb=%d" From patchwork Sat Oct 10 13:57:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303206 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E3B6C433DF for ; Sat, 10 Oct 2020 14:01:23 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C679A22283 for ; Sat, 10 Oct 2020 14:01:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="fbDpXJEa" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C679A22283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:59908 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFR3-0006i0-KS for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:01:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40602) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMz-0000wP-2y; Sat, 10 Oct 2020 09:57:09 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43456) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMv-0004IK-PC; Sat, 10 Oct 2020 09:57:08 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 572F7C603C2; Sat, 10 Oct 2020 13:57:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FersAzpN8NHvPMLGj5VpCSEmZb4JFczHhL1rgLAgDho=; b=fbDpXJEaqsIJf21JdAi/NkwOsOHF1TIapGntPI/IE5Tg4nMOskbhx0EVcLEcA6QZq1v0CF X9hqQ7hsLtb7KFwdbuighswrdip3JfguXgKp2bckTgsHN8lTR5DV7TN+pDDGEMpHalIPtT afZlGvD+zTYqVA1ygpt7CDZy6CQoHS/5OfVCJXgZhM8has7hpSr7HKvdiC3ACXhmu7YAkt 9/FBm50pXwk5RV12MEm1WvXbYW95NQvqmA8PMmGIWTmiaRNAukSI/1TVAqvk+Smk4bQKev Vg0F50AtNzRAFCExGcir74Vjnt8bDrRSfD6nB6kl47QTyFnOlvfM5QELc9K0Ew== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 03/15] hw/core/clock: add the clock_new helper function Date: Sat, 10 Oct 2020 15:57:47 +0200 Message-Id: <20201010135759.437903-4-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FersAzpN8NHvPMLGj5VpCSEmZb4JFczHhL1rgLAgDho=; b=bMKG5cC8WrjVdMI99aUtYoS9y4v9+7v96DyivHHc2HZt4wXeXsiIGeU6QgNyVWJw4S0oRu T4olhkWf+DxoJQ8CYYdCDCl1N0rJ756bOnRch2wkX15XY8QDUgor86HyqVNHRuNIYAsvfv d07XjlqQdcPhzDwsMbm+0OHYulv5u30KJXD7+06Oqv+9zsGCGiUvcE8d19pECPv9ll6KF4 VWgBDZA3M8nQSS2Jpe2oyF13XG6xP8JRuT4uat0GemijM+lNV4uWbe3LTNidg/u0cdgiCb VCHQoMxq1U1Qik5/0J36eqtBF/mlJmJDW7XD7258v5pk/HJsihn+AoRxu9kjxQ== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338223; a=rsa-sha256; cv=none; b=QUBy2ev2EDljhCMO8Sisys0aEvOuzndf7Z2T4PYtBW4OzntOWGHQscp/q9X/37wKdyMtzmSt27DGUvYuh115CEIjzCttq7hs4Ex26EpDwBAzTxPZkHoAxwCmDKAazv79TPsdRVfXgKIBNZtYaiqV9+M35ss3pX75V6nTINgxHD10zX0MItGHS/PAAIZXvLskSXn2dFC6KLRTK/ABOryRaRMg2NX0ennymbtlG/sN05C2qJV9I/1W655a7ZSPYU1bzlO/V8C5MZwqR9MZ8hLN82AXAJfzZQTGKvP9D2ftCvKeFRNT5yvFMng8w5BWekKGahhSQlyTmt4LsPXcMqgBpA== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Peter Maydell , Luc Michel , =?utf-8?q?Ph?= =?utf-8?q?ilippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This function creates a clock and parents it to another object with a given name. It calls clock_setup_canonical_path before returning the new clock. This function is useful to create clocks in devices when one doesn't want to expose it at the qdev level (as an input or an output). Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- include/hw/clock.h | 13 +++++++++++++ hw/core/clock.c | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/hw/clock.h b/include/hw/clock.h index c93e6113cd..81bcf3e505 100644 --- a/include/hw/clock.h +++ b/include/hw/clock.h @@ -93,10 +93,23 @@ extern const VMStateDescription vmstate_clock; * * compute the canonical path of the clock (used by log messages) */ void clock_setup_canonical_path(Clock *clk); +/** + * clock_new: + * @parent: the clock parent + * @name: the clock object name + * + * Helper function to create a new clock and parent it to @parent. There is no + * need to call clock_setup_canonical_path on the returned clock as it is done + * by this function. + * + * @return the newly created clock + */ +Clock *clock_new(Object *parent, const char *name); + /** * clock_set_callback: * @clk: the clock to register the callback into * @cb: the callback function * @opaque: the argument to the callback diff --git a/hw/core/clock.c b/hw/core/clock.c index 81184734e0..8c6af223e7 100644 --- a/hw/core/clock.c +++ b/hw/core/clock.c @@ -21,10 +21,25 @@ void clock_setup_canonical_path(Clock *clk) { g_free(clk->canonical_path); clk->canonical_path = object_get_canonical_path(OBJECT(clk)); } +Clock *clock_new(Object *parent, const char *name) +{ + Object *obj; + Clock *clk; + + obj = object_new(TYPE_CLOCK); + object_property_add_child(parent, name, obj); + object_unref(obj); + + clk = CLOCK(obj); + clock_setup_canonical_path(clk); + + return clk; +} + void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque) { clk->callback = cb; clk->callback_opaque = opaque; } From patchwork Sat Oct 10 13:57:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303208 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 048D3C433E7 for ; Sat, 10 Oct 2020 13:58:20 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6478322284 for ; Sat, 10 Oct 2020 13:58:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="HMGpABo5" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6478322284 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:50472 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFO6-0002hd-Ft for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 09:58:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40576) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMx-0000wC-Ua; Sat, 10 Oct 2020 09:57:07 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43476) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMv-0004IL-Ov; Sat, 10 Oct 2020 09:57:07 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 73493C603C3; Sat, 10 Oct 2020 13:57:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9ytL1MgY7atcQnOFYVbyvTI9rupTIt9JujlNK/ak1Y4=; b=HMGpABo5vO/RgT/gxQSOLj/JIiXd+iiSudGYOuJt9l/lPdigScpn1G4SzzPOijf2WmllcZ vT+IUpvap7WcvuAc/MxSJVbG53Gj5I4m2Lk4zYVbi5GS/8htA5twYhzk7aXigzFISCr39s 3/9rkoG6tW3QLrPIFxVAHVWqFZV7EVWFJzZ+B1XwGUv0czyJYhB8EEbNbLORfa/08itEAQ DAZSGG3vkLfZTd3A9EStKpVNE6oEmkG4vbxoAEQyoxEqfnjz3L/7+gFKOMXyVrCVB69bPO BJZSdXVisGN2OSDAtKuOlbb2RWs3dQbcSyTajGL05s9POKim/NkySD6LxVKw0w== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 04/15] hw/arm/raspi: fix CPRMAN base address Date: Sat, 10 Oct 2020 15:57:48 +0200 Message-Id: <20201010135759.437903-5-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9ytL1MgY7atcQnOFYVbyvTI9rupTIt9JujlNK/ak1Y4=; b=Xm1biEHWyaHyJQfPXv5f9QPVqwIy595+MHsM2vE5O65CdHNxX0ZRcTRBiT1iiV59GBDnGT w7eboM3nTfXvqnz43B4vCCXeSC6hYWMacILQOaHgBv+TjSQANwXs15V8rhgmO/akhXou5R 4mxJ91o0e/wu0Z47I9oktqu71TkU+qHU0uUZihze8V1ClkE9BL/A8+EDrVs4EqZo8Oe+2t fvpyPiPSEFElAqlIAsd9Hm/OeZTVImYzh4u/xG1m/FEhwu9i8gzQe7BEyCfkBK5L5TJVZY yfTG2clEKbyKgW8fMFDILVPlz9JvUe/xPYFtSes22KgqkYwcL/C10qEZUzW+RA== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338223; a=rsa-sha256; cv=none; b=W3Jwk6gL8rIjXjrujXwJDigLhmUGylV95EQtaStRJtL0RIfYJRpF9VDYS6SX1/MSxWRABo9VoC9jEqPylWe4nQVkEICK8bIpD0OBHfw6uEAEcM8umsj66pnfZae8FlXTpTFp+wW/wpfFXgwXvSO2bBk66EclA9RqXpscYQEScuMExjJCZ2UL28/TWhZfnQvP+kH5k0NjyiIZM8oqdb/7ijGolU2h9AawGWJt/xHrq8kP0op7F+Y1B4X0AWOhRJETUJb9IBDn6luvwulrIes8GZn14OZJ21n8pBtUdpoas+4r+wRsaA3jJDG+H/d7ato56tgRdgKLdhTQ9JUkXBKOmg== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The CPRMAN (clock controller) was mapped at the watchdog/power manager address. It was also split into two unimplemented peripherals (CM and A2W) but this is really the same one, as shown by this extract of the Raspberry Pi 3 Linux device tree: watchdog@7e100000 { compatible = "brcm,bcm2835-pm\0brcm,bcm2835-pm-wdt"; [...] reg = <0x7e100000 0x114 0x7e00a000 0x24>; [...] }; [...] cprman@7e101000 { compatible = "brcm,bcm2835-cprman"; [...] reg = <0x7e101000 0x2000>; [...] }; Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/arm/bcm2835_peripherals.h | 2 +- include/hw/arm/raspi_platform.h | 5 ++--- hw/arm/bcm2835_peripherals.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index c9ac941a82..6aa94184eb 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -45,12 +45,12 @@ struct BCM2835PeripheralState { BCM2835SystemTimerState systmr; BCM2835MphiState mphi; UnimplementedDeviceState txp; UnimplementedDeviceState armtmr; + UnimplementedDeviceState powermgt; UnimplementedDeviceState cprman; - UnimplementedDeviceState a2w; PL011State uart0; BCM2835AuxState aux; BCM2835FBState fb; BCM2835DMAState dma; BCM2835ICState ic; diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h index c7f50b260f..e0e6c8ce94 100644 --- a/include/hw/arm/raspi_platform.h +++ b/include/hw/arm/raspi_platform.h @@ -43,13 +43,12 @@ #define ARMCTRL_OFFSET (ARM_OFFSET + 0x000) #define ARMCTRL_IC_OFFSET (ARM_OFFSET + 0x200) /* Interrupt controller */ #define ARMCTRL_TIMER0_1_OFFSET (ARM_OFFSET + 0x400) /* Timer 0 and 1 (SP804) */ #define ARMCTRL_0_SBM_OFFSET (ARM_OFFSET + 0x800) /* User 0 (ARM) Semaphores * Doorbells & Mailboxes */ -#define CPRMAN_OFFSET 0x100000 /* Power Management, Watchdog */ -#define CM_OFFSET 0x101000 /* Clock Management */ -#define A2W_OFFSET 0x102000 /* Reset controller */ +#define PM_OFFSET 0x100000 /* Power Management */ +#define CPRMAN_OFFSET 0x101000 /* Clock Management */ #define AVS_OFFSET 0x103000 /* Audio Video Standard */ #define RNG_OFFSET 0x104000 #define GPIO_OFFSET 0x200000 #define UART0_OFFSET 0x201000 /* PL011 */ #define MMCI0_OFFSET 0x202000 /* Legacy MMC */ diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 15c5c72e46..10e9f501d2 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -343,12 +343,12 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_USB)); create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000); create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40); - create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000); - create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000); + create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114); + create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000); create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100); create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100); create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20); create_unimp(s, &s->bscsl, "bcm2835-spis", BSC_SL_OFFSET, 0x100); create_unimp(s, &s->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20); From patchwork Sat Oct 10 13:57:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 271613 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A86AC433E7 for ; Sat, 10 Oct 2020 14:01:26 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1F9B322283 for ; Sat, 10 Oct 2020 14:01:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="Qs6SB+jM" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1F9B322283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:60216 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFR7-0006tv-5S for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:01:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40638) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN2-000123-4H; Sat, 10 Oct 2020 09:57:12 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43608) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMz-0004JP-8F; Sat, 10 Oct 2020 09:57:11 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 93FC2C603D7; Sat, 10 Oct 2020 13:57:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HZVj10AFujvPZeDEOYBlWPdrZCZDe5HuOmVNdOSGfsA=; b=Qs6SB+jMt98w3YXw84L6r8myh/3WRj3mzgY/1Vf91XzJIdb11GpdNixjfBKRs3gCVSX9yE KfL2BSsvQjDSzYeqDRjvNjbkLCCYQPgdls8yUwm9c8ZZoQJY8gF4vQZsbpolcxX2nL+ESZ eMWvMut9R8Hhr0xzTwpCw6T965cWAYPbxE3V/Lff4c+s/dR5wS8N0ui+s1WDvknix+3DBc V+aXV3gv5yc/pzEnSk/34EdBeU/QUv2kdttW/1UUsONZ8LKaNeoxMmo0Y7gZere8ijffdJ aMmcupcbP8Ap0rtDpf0CUgrzY2J4SQWPuVuaIrglInzMxjO+15sZqo3ek5PL3Q== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 05/15] hw/arm/raspi: add a skeleton implementation of the CPRMAN Date: Sat, 10 Oct 2020 15:57:49 +0200 Message-Id: <20201010135759.437903-6-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338223; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HZVj10AFujvPZeDEOYBlWPdrZCZDe5HuOmVNdOSGfsA=; b=Wt/zLQXSqc9tSYmkcsmH7a1RV7VbmsM/daNO2aZ4/fnH+t3VmhyFWLltbQIIIuOLcm0YoP 6THrEuJMhYSWdb/FikyXNlYeXiBaiUci6qI68xmHJQKOLnqBH44mwYMaUi/fCYEUm7EwS3 lklc7pTVeqhx0eEVq2GWyNhAPQhTaLtZVY/HUbcnRXXmkfhow59Vy7elgCw4jg85ZNmboz Qd/XOmHteyZ3KJCCs5oFR4IiE7TdNmNKJCEU9afSdnydlyq1PNiYHcQIMArQNnlNGFPAmq YCh64q0Bc9d0zIa4McuepAmT4EKNRJpgpbFRYBxL0L00SlJwB6m7Y8lZnE7NZQ== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338223; a=rsa-sha256; cv=none; b=ar7u1xJgl3dPDD+1IwbNgKgOtsvlufP0MFq2S6w5tFuQizx5S/YpZm2CNfuRqw21OnvZv6yexoRQp3KCEuTdlaF0IsDJ0OKBQAfSmyod+2Giab1y/hsVuZ0eZs25BSDnHnMPCT+NAcQpx8geepbZH7XQLdgwVxwANzKHoYhZhQAHTWVg/hfLgK6i5VnBAnXO6eGVeaTFCpaF8sGD2Q/EHNvp+QWFr/+rozbzlhNOtldH8oJMluN1vldgu6Nxr1tILhQystKFxCASZ4q6pSb96z2C0W3UFWfCUWCe/ukTElpJ5RBK6c0z6HIJr80E2Uhyvy2yhGoVkcnOu6fb5mGzIA== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The BCM2835 CPRMAN is the clock manager of the SoC. It is composed of a main oscillator, and several sub-components (PLLs, multiplexers, ...) to generate the BCM2835 clock tree. This commit adds a skeleton of the CPRMAN, with a dummy register read/write implementation. It embeds the main oscillator (xosc) from which all the clocks will be derived. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/arm/bcm2835_peripherals.h | 3 +- include/hw/misc/bcm2835_cprman.h | 37 +++++ include/hw/misc/bcm2835_cprman_internals.h | 24 +++ hw/arm/bcm2835_peripherals.c | 11 +- hw/misc/bcm2835_cprman.c | 163 +++++++++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 5 + 7 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 include/hw/misc/bcm2835_cprman.h create mode 100644 include/hw/misc/bcm2835_cprman_internals.h create mode 100644 hw/misc/bcm2835_cprman.c diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index 6aa94184eb..479e2346e8 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -21,10 +21,11 @@ #include "hw/misc/bcm2835_property.h" #include "hw/misc/bcm2835_rng.h" #include "hw/misc/bcm2835_mbox.h" #include "hw/misc/bcm2835_mphi.h" #include "hw/misc/bcm2835_thermal.h" +#include "hw/misc/bcm2835_cprman.h" #include "hw/sd/sdhci.h" #include "hw/sd/bcm2835_sdhost.h" #include "hw/gpio/bcm2835_gpio.h" #include "hw/timer/bcm2835_systmr.h" #include "hw/usb/hcd-dwc2.h" @@ -46,11 +47,11 @@ struct BCM2835PeripheralState { BCM2835SystemTimerState systmr; BCM2835MphiState mphi; UnimplementedDeviceState txp; UnimplementedDeviceState armtmr; UnimplementedDeviceState powermgt; - UnimplementedDeviceState cprman; + BCM2835CprmanState cprman; PL011State uart0; BCM2835AuxState aux; BCM2835FBState fb; BCM2835DMAState dma; BCM2835ICState ic; diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h new file mode 100644 index 0000000000..8ae2d4d17c --- /dev/null +++ b/include/hw/misc/bcm2835_cprman.h @@ -0,0 +1,37 @@ +/* + * BCM2835 CPRMAN clock manager + * + * Copyright (c) 2020 Luc Michel + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MISC_CPRMAN_H +#define HW_MISC_CPRMAN_H + +#include "hw/sysbus.h" +#include "hw/qdev-clock.h" + +#define TYPE_BCM2835_CPRMAN "bcm2835-cprman" + +typedef struct BCM2835CprmanState BCM2835CprmanState; + +DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN, + TYPE_BCM2835_CPRMAN) + +#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t)) + +struct BCM2835CprmanState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t regs[CPRMAN_NUM_REGS]; + uint32_t xosc_freq; + + Clock *xosc; +}; + +#endif diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h new file mode 100644 index 0000000000..8fcc6d1d09 --- /dev/null +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -0,0 +1,24 @@ +/* + * BCM2835 CPRMAN clock manager + * + * Copyright (c) 2020 Luc Michel + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MISC_CPRMAN_INTERNALS_H +#define HW_MISC_CPRMAN_INTERNALS_H + +#include "hw/registerfields.h" +#include "hw/misc/bcm2835_cprman.h" + +/* Register map */ + +/* + * This field is common to all registers. Each register write value must match + * the CPRMAN_PASSWORD magic value in its 8 MSB. + */ +FIELD(CPRMAN, PASSWORD, 24, 8) +#define CPRMAN_PASSWORD 0x5a + +#endif diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 10e9f501d2..9d6190042d 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -119,10 +119,13 @@ static void bcm2835_peripherals_init(Object *obj) object_initialize_child(obj, "mphi", &s->mphi, TYPE_BCM2835_MPHI); /* DWC2 */ object_initialize_child(obj, "dwc2", &s->dwc2, TYPE_DWC2_USB); + /* CPRMAN clock manager */ + object_initialize_child(obj, "cprman", &s->cprman, TYPE_BCM2835_CPRMAN); + object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr", OBJECT(&s->gpu_bus_mr)); } static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) @@ -158,10 +161,17 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) /* Interrupt Controller */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->ic), errp)) { return; } + /* CPRMAN clock manager */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cprman), errp)) { + return; + } + memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0)); + memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0)); sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); /* Sys Timer */ @@ -344,11 +354,10 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_USB)); create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000); create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40); create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114); - create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000); create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100); create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100); create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20); create_unimp(s, &s->bscsl, "bcm2835-spis", BSC_SL_OFFSET, 0x100); create_unimp(s, &s->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20); diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c new file mode 100644 index 0000000000..57ab9910b5 --- /dev/null +++ b/hw/misc/bcm2835_cprman.c @@ -0,0 +1,163 @@ +/* + * BCM2835 CPRMAN clock manager + * + * Copyright (c) 2020 Luc Michel + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* + * This peripheral is roughly divided into 3 main parts: + * - the PLLs + * - the PLL channels + * - the clock muxes + * + * A main oscillator (xosc) feeds all the PLLs. Each PLLs has one or more + * channels. Those channel are then connected to the clock muxes. Each mux has + * multiples sources (usually the xosc, some of the PLL channels and some "test + * debug" clocks). A mux is configured to select a given source through its + * control register. Each mux has one output clock that also goes out of the + * CPRMAN. This output clock usually connects to another peripheral in the SoC + * (so a given mux is dedicated to a peripheral). + * + * At each level (PLL, channel and mux), the clock can be altered through + * dividers (and multipliers in case of the PLLs), and can be disabled (in this + * case, the next levels see no clock). + * + * This can be sum-up as follows (this is an example and not the actual BCM2835 + * clock tree): + * + * /-->[PLL]-|->[PLL channel]--... [mux]--> to peripherals + * | |->[PLL channel] muxes takes [mux] + * | \->[PLL channel] inputs from [mux] + * | some channels [mux] + * [xosc]---|-->[PLL]-|->[PLL channel] and other srcs [mux] + * | \->[PLL channel] ...-->[mux] + * | [mux] + * \-->[PLL]--->[PLL channel] [mux] + * + * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock + * tree configuration. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/misc/bcm2835_cprman.h" +#include "hw/misc/bcm2835_cprman_internals.h" +#include "trace.h" + +/* CPRMAN "top level" model */ + +static uint64_t cprman_read(void *opaque, hwaddr offset, + unsigned size) +{ + BCM2835CprmanState *s = CPRMAN(opaque); + uint64_t r = 0; + size_t idx = offset / sizeof(uint32_t); + + switch (idx) { + default: + r = s->regs[idx]; + } + + trace_bcm2835_cprman_read(offset, r); + return r; +} + +static void cprman_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + BCM2835CprmanState *s = CPRMAN(opaque); + size_t idx = offset / sizeof(uint32_t); + + if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) { + trace_bcm2835_cprman_write_invalid_magic(offset, value); + return; + } + + value &= ~R_CPRMAN_PASSWORD_MASK; + + trace_bcm2835_cprman_write(offset, value); + s->regs[idx] = value; + +} + +static const MemoryRegionOps cprman_ops = { + .read = cprman_read, + .write = cprman_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + /* + * Although this hasn't been checked against real hardware, nor the + * information can be found in a datasheet, it seems reasonable because + * of the "PASSWORD" magic value found in every registers. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, + .impl = { + .max_access_size = 4, + }, +}; + +static void cprman_reset(DeviceState *dev) +{ + BCM2835CprmanState *s = CPRMAN(dev); + + memset(s->regs, 0, sizeof(s->regs)); + + clock_update_hz(s->xosc, s->xosc_freq); +} + +static void cprman_init(Object *obj) +{ + BCM2835CprmanState *s = CPRMAN(obj); + + s->xosc = clock_new(obj, "xosc"); + + memory_region_init_io(&s->iomem, obj, &cprman_ops, + s, "bcm2835-cprman", 0x2000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); +} + +static const VMStateDescription cprman_vmstate = { + .name = TYPE_BCM2835_CPRMAN, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS), + VMSTATE_END_OF_LIST() + } +}; + +static Property cprman_properties[] = { + DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000), + DEFINE_PROP_END_OF_LIST() +}; + +static void cprman_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = cprman_reset; + dc->vmsd = &cprman_vmstate; + device_class_set_props(dc, cprman_properties); +} + +static const TypeInfo cprman_info = { + .name = TYPE_BCM2835_CPRMAN, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835CprmanState), + .class_init = cprman_class_init, + .instance_init = cprman_init, +}; + +static void cprman_register_types(void) +{ + type_register_static(&cprman_info); +} + +type_init(cprman_register_types); diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 793d45b1dc..c94cf70e82 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -71,10 +71,11 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( 'bcm2835_mbox.c', 'bcm2835_mphi.c', 'bcm2835_property.c', 'bcm2835_rng.c', 'bcm2835_thermal.c', + 'bcm2835_cprman.c', )) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c')) softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 6054f9adf3..d718a2b177 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -224,5 +224,10 @@ grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx6 grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx64" data:0x%08x" # pca9552.c pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]" pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, unsigned current_state) "%s GPIO id:%u status: %u -> %u" + +# bcm2835_cprman.c +bcm2835_cprman_read(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64 +bcm2835_cprman_write(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64 +bcm2835_cprman_write_invalid_magic(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64 From patchwork Sat Oct 10 13:57:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303205 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CFC7C433DF for ; Sat, 10 Oct 2020 14:01:59 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C887822283 for ; Sat, 10 Oct 2020 14:01:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="Sa+9zNwq" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C887822283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:33036 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFRd-0007KI-TX for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:01:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40640) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN2-00012p-ES; Sat, 10 Oct 2020 09:57:12 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43610) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFMz-0004JN-GP; Sat, 10 Oct 2020 09:57:12 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 11E12C603D8; Sat, 10 Oct 2020 13:57:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XLwlDIyHFc0C8pkaVLGy6Y49SxN2cz8QpoPh2p0BZHI=; b=Sa+9zNwq5AHs8KvvOTGjIMRQPpu6MQeea1U/F6pnI0DIFI8UOuswlAVtGRwZUFhUjgh950 v7Rm184hj7156i0d9861FjJZhyzDCdT+PQO/zUCZGRKZOjvoW8jfQIYICzgq9muaLwVuzI BzyfE+qLwUDAnl6jwUbYycYDmTj48V+a2OCP0Lgb8w9qO0VVlVrlylgCSQQrkH9vESAf7G T61i0I+rOSU50gPlHdq3qRF0UslYwZ2wtThoxBbWwHaxOg7nDaUUFKcyVTXUYjvSTrQKvX nUyvtTCkXxyFekdUBiQqmmrbRHzJK42uEZ4X17nkpyrYfYnNZniDwM1fMIB9JA== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 06/15] hw/misc/bcm2835_cprman: add a PLL skeleton implementation Date: Sat, 10 Oct 2020 15:57:50 +0200 Message-Id: <20201010135759.437903-7-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XLwlDIyHFc0C8pkaVLGy6Y49SxN2cz8QpoPh2p0BZHI=; b=iiVFNJPshsfhotyQHl5Yt6KRsl5YdI2tPUDP5V99dnSGTV7gx9sOjYC+sC5hKLJXQEFVqD lPDEdaJ4V/kHu2sMnVQxKWPpE7J7AcOwR7aZ8Gf3d9Ekz03HuZjepKBJ4tqGT5EUvQyZ++ 8Ma4RYcEnC1fsjMcS482rLLFJlVKDdsLLJMIqpul888cnRpnu4airZjCb5smvZNxFxw67D dotN9cHtAE2NRLKh0JJQIevOAqJRMVLwtbWDPDY4A/NZs/wgFy3BSrsua3s7lfmxkTyZjf bYW+W8fQ2EexB79UBc9CP36DVsrWY59FbzgrUmXoLEnqlFbRL8uJFjpnwH4ilA== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338224; a=rsa-sha256; cv=none; b=gp2usRPS3GzReqkAnFhWy6ogHC64BxVoZRtY4QlfNRm7ADJIlkBHXNOqjdOxlKkIgry2okezlSN5Lv+9W+hnK/4nZ7tdhwpwC4oHonjC3IHOnTkmxh01+LMGAIlxqGuCtaP/0HVrW1LptFVufNiXzdAS/e89Nu/LTpvu8m6Y/flylpOEsbOx0d+72XBIN+avvjm18RbNTGJFmuTnQeOw+zvKLMBl/sOg8VuIfMRCBYMIlFDlFQZ0l/kPJHB1l+5eEHI4eirPRHEUU/7LajvwEetPQgrNBrBR0BsVMs94S3WTZoE4yb0o6HQgkMO6pzyxYsy0524CKs9p4QJ3k0QtTA== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" There are 5 PLLs in the CPRMAN, namely PLL A, C, D, H and B. All of them take the xosc clock as input and produce a new clock. This commit adds a skeleton implementation for the PLLs as sub-devices of the CPRMAN. The PLLs are instantiated and connected internally to the main oscillator. Each PLL has 6 registers : CM, A2W_CTRL, A2W_ANA[0,1,2,3], A2W_FRAC. A write to any of them triggers a call to the (not yet implemented) pll_update function. If the main oscillator changes frequency, an update is also triggered. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/misc/bcm2835_cprman.h | 29 +++++ include/hw/misc/bcm2835_cprman_internals.h | 144 +++++++++++++++++++++ hw/misc/bcm2835_cprman.c | 108 ++++++++++++++++ 3 files changed, 281 insertions(+) diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index 8ae2d4d17c..5c442e6ff9 100644 --- a/include/hw/misc/bcm2835_cprman.h +++ b/include/hw/misc/bcm2835_cprman.h @@ -19,17 +19,46 @@ typedef struct BCM2835CprmanState BCM2835CprmanState; DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN, TYPE_BCM2835_CPRMAN) #define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t)) +typedef enum CprmanPll { + CPRMAN_PLLA = 0, + CPRMAN_PLLC, + CPRMAN_PLLD, + CPRMAN_PLLH, + CPRMAN_PLLB, + + CPRMAN_NUM_PLL +} CprmanPll; + +typedef struct CprmanPllState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + CprmanPll id; + + uint32_t *reg_cm; + uint32_t *reg_a2w_ctrl; + uint32_t *reg_a2w_ana; /* ANA[0] .. ANA[3] */ + uint32_t prediv_mask; /* prediv bit in ana[1] */ + uint32_t *reg_a2w_frac; + + Clock *xosc_in; + Clock *out; +} CprmanPllState; + struct BCM2835CprmanState { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ MemoryRegion iomem; + CprmanPllState plls[CPRMAN_NUM_PLL]; + uint32_t regs[CPRMAN_NUM_REGS]; uint32_t xosc_freq; Clock *xosc; }; diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index 8fcc6d1d09..340ad623bb 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -10,15 +10,159 @@ #define HW_MISC_CPRMAN_INTERNALS_H #include "hw/registerfields.h" #include "hw/misc/bcm2835_cprman.h" +#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll" + +DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL, + TYPE_CPRMAN_PLL) + /* Register map */ +/* PLLs */ +REG32(CM_PLLA, 0x104) + FIELD(CM_PLLA, LOADDSI0, 0, 1) + FIELD(CM_PLLA, HOLDDSI0, 1, 1) + FIELD(CM_PLLA, LOADCCP2, 2, 1) + FIELD(CM_PLLA, HOLDCCP2, 3, 1) + FIELD(CM_PLLA, LOADCORE, 4, 1) + FIELD(CM_PLLA, HOLDCORE, 5, 1) + FIELD(CM_PLLA, LOADPER, 6, 1) + FIELD(CM_PLLA, HOLDPER, 7, 1) + FIELD(CM_PLLx, ANARST, 8, 1) +REG32(CM_PLLC, 0x108) + FIELD(CM_PLLC, LOADCORE0, 0, 1) + FIELD(CM_PLLC, HOLDCORE0, 1, 1) + FIELD(CM_PLLC, LOADCORE1, 2, 1) + FIELD(CM_PLLC, HOLDCORE1, 3, 1) + FIELD(CM_PLLC, LOADCORE2, 4, 1) + FIELD(CM_PLLC, HOLDCORE2, 5, 1) + FIELD(CM_PLLC, LOADPER, 6, 1) + FIELD(CM_PLLC, HOLDPER, 7, 1) +REG32(CM_PLLD, 0x10c) + FIELD(CM_PLLD, LOADDSI0, 0, 1) + FIELD(CM_PLLD, HOLDDSI0, 1, 1) + FIELD(CM_PLLD, LOADDSI1, 2, 1) + FIELD(CM_PLLD, HOLDDSI1, 3, 1) + FIELD(CM_PLLD, LOADCORE, 4, 1) + FIELD(CM_PLLD, HOLDCORE, 5, 1) + FIELD(CM_PLLD, LOADPER, 6, 1) + FIELD(CM_PLLD, HOLDPER, 7, 1) +REG32(CM_PLLH, 0x110) + FIELD(CM_PLLH, LOADPIX, 0, 1) + FIELD(CM_PLLH, LOADAUX, 1, 1) + FIELD(CM_PLLH, LOADRCAL, 2, 1) +REG32(CM_PLLB, 0x170) + FIELD(CM_PLLB, LOADARM, 0, 1) + FIELD(CM_PLLB, HOLDARM, 1, 1) + +REG32(A2W_PLLA_CTRL, 0x1100) + FIELD(A2W_PLLx_CTRL, NDIV, 0, 10) + FIELD(A2W_PLLx_CTRL, PDIV, 12, 3) + FIELD(A2W_PLLx_CTRL, PWRDN, 16, 1) + FIELD(A2W_PLLx_CTRL, PRST_DISABLE, 17, 1) +REG32(A2W_PLLC_CTRL, 0x1120) +REG32(A2W_PLLD_CTRL, 0x1140) +REG32(A2W_PLLH_CTRL, 0x1160) +REG32(A2W_PLLB_CTRL, 0x11e0) + +REG32(A2W_PLLA_ANA0, 0x1010) +REG32(A2W_PLLA_ANA1, 0x1014) + FIELD(A2W_PLLx_ANA1, FB_PREDIV, 14, 1) +REG32(A2W_PLLA_ANA2, 0x1018) +REG32(A2W_PLLA_ANA3, 0x101c) + +REG32(A2W_PLLC_ANA0, 0x1030) +REG32(A2W_PLLC_ANA1, 0x1034) +REG32(A2W_PLLC_ANA2, 0x1038) +REG32(A2W_PLLC_ANA3, 0x103c) + +REG32(A2W_PLLD_ANA0, 0x1050) +REG32(A2W_PLLD_ANA1, 0x1054) +REG32(A2W_PLLD_ANA2, 0x1058) +REG32(A2W_PLLD_ANA3, 0x105c) + +REG32(A2W_PLLH_ANA0, 0x1070) +REG32(A2W_PLLH_ANA1, 0x1074) + FIELD(A2W_PLLH_ANA1, FB_PREDIV, 11, 1) +REG32(A2W_PLLH_ANA2, 0x1078) +REG32(A2W_PLLH_ANA3, 0x107c) + +REG32(A2W_PLLB_ANA0, 0x10f0) +REG32(A2W_PLLB_ANA1, 0x10f4) +REG32(A2W_PLLB_ANA2, 0x10f8) +REG32(A2W_PLLB_ANA3, 0x10fc) + +REG32(A2W_PLLA_FRAC, 0x1200) + FIELD(A2W_PLLx_FRAC, FRAC, 0, 20) +REG32(A2W_PLLC_FRAC, 0x1220) +REG32(A2W_PLLD_FRAC, 0x1240) +REG32(A2W_PLLH_FRAC, 0x1260) +REG32(A2W_PLLB_FRAC, 0x12e0) + /* * This field is common to all registers. Each register write value must match * the CPRMAN_PASSWORD magic value in its 8 MSB. */ FIELD(CPRMAN, PASSWORD, 24, 8) #define CPRMAN_PASSWORD 0x5a +/* PLL init info */ +typedef struct PLLInitInfo { + const char *name; + size_t cm_offset; + size_t a2w_ctrl_offset; + size_t a2w_ana_offset; + uint32_t prediv_mask; /* Prediv bit in ana[1] */ + size_t a2w_frac_offset; +} PLLInitInfo; + +#define FILL_PLL_INIT_INFO(pll_) \ + .cm_offset = R_CM_ ## pll_, \ + .a2w_ctrl_offset = R_A2W_ ## pll_ ## _CTRL, \ + .a2w_ana_offset = R_A2W_ ## pll_ ## _ANA0, \ + .a2w_frac_offset = R_A2W_ ## pll_ ## _FRAC + +static const PLLInitInfo PLL_INIT_INFO[] = { + [CPRMAN_PLLA] = { + .name = "plla", + .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, + FILL_PLL_INIT_INFO(PLLA), + }, + [CPRMAN_PLLC] = { + .name = "pllc", + .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, + FILL_PLL_INIT_INFO(PLLC), + }, + [CPRMAN_PLLD] = { + .name = "plld", + .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, + FILL_PLL_INIT_INFO(PLLD), + }, + [CPRMAN_PLLH] = { + .name = "pllh", + .prediv_mask = R_A2W_PLLH_ANA1_FB_PREDIV_MASK, + FILL_PLL_INIT_INFO(PLLH), + }, + [CPRMAN_PLLB] = { + .name = "pllb", + .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, + FILL_PLL_INIT_INFO(PLLB), + }, +}; + +#undef FILL_PLL_CHANNEL_INIT_INFO + +static inline void set_pll_init_info(BCM2835CprmanState *s, + CprmanPllState *pll, + CprmanPll id) +{ + pll->id = id; + pll->reg_cm = &s->regs[PLL_INIT_INFO[id].cm_offset]; + pll->reg_a2w_ctrl = &s->regs[PLL_INIT_INFO[id].a2w_ctrl_offset]; + pll->reg_a2w_ana = &s->regs[PLL_INIT_INFO[id].a2w_ana_offset]; + pll->prediv_mask = PLL_INIT_INFO[id].prediv_mask; + pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset]; +} + #endif diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 57ab9910b5..b86f5901b8 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -46,10 +46,56 @@ #include "hw/qdev-properties.h" #include "hw/misc/bcm2835_cprman.h" #include "hw/misc/bcm2835_cprman_internals.h" #include "trace.h" +/* PLL */ + +static void pll_update(CprmanPllState *pll) +{ + clock_update(pll->out, 0); +} + +static void pll_xosc_update(void *opaque) +{ + pll_update(CPRMAN_PLL(opaque)); +} + +static void pll_init(Object *obj) +{ + CprmanPllState *s = CPRMAN_PLL(obj); + + s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s); + s->out = qdev_init_clock_out(DEVICE(s), "out"); +} + +static const VMStateDescription pll_vmstate = { + .name = TYPE_CPRMAN_PLL, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_CLOCK(xosc_in, CprmanPllState), + VMSTATE_END_OF_LIST() + } +}; + +static void pll_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &pll_vmstate; +} + +static const TypeInfo cprman_pll_info = { + .name = TYPE_CPRMAN_PLL, + .parent = TYPE_DEVICE, + .instance_size = sizeof(CprmanPllState), + .class_init = pll_class_init, + .instance_init = pll_init, +}; + + /* CPRMAN "top level" model */ static uint64_t cprman_read(void *opaque, hwaddr offset, unsigned size) { @@ -64,10 +110,19 @@ static uint64_t cprman_read(void *opaque, hwaddr offset, trace_bcm2835_cprman_read(offset, r); return r; } +#define CASE_PLL_REGS(pll_) \ + case R_CM_ ## pll_: \ + case R_A2W_ ## pll_ ## _CTRL: \ + case R_A2W_ ## pll_ ## _ANA0: \ + case R_A2W_ ## pll_ ## _ANA1: \ + case R_A2W_ ## pll_ ## _ANA2: \ + case R_A2W_ ## pll_ ## _ANA3: \ + case R_A2W_ ## pll_ ## _FRAC + static void cprman_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { BCM2835CprmanState *s = CPRMAN(opaque); size_t idx = offset / sizeof(uint32_t); @@ -80,12 +135,35 @@ static void cprman_write(void *opaque, hwaddr offset, value &= ~R_CPRMAN_PASSWORD_MASK; trace_bcm2835_cprman_write(offset, value); s->regs[idx] = value; + switch (idx) { + CASE_PLL_REGS(PLLA) : + pll_update(&s->plls[CPRMAN_PLLA]); + break; + + CASE_PLL_REGS(PLLC) : + pll_update(&s->plls[CPRMAN_PLLC]); + break; + + CASE_PLL_REGS(PLLD) : + pll_update(&s->plls[CPRMAN_PLLD]); + break; + + CASE_PLL_REGS(PLLH) : + pll_update(&s->plls[CPRMAN_PLLH]); + break; + + CASE_PLL_REGS(PLLB) : + pll_update(&s->plls[CPRMAN_PLLB]); + break; + } } +#undef CASE_PLL_REGS + static const MemoryRegionOps cprman_ops = { .read = cprman_read, .write = cprman_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { @@ -104,27 +182,55 @@ static const MemoryRegionOps cprman_ops = { }; static void cprman_reset(DeviceState *dev) { BCM2835CprmanState *s = CPRMAN(dev); + size_t i; memset(s->regs, 0, sizeof(s->regs)); + for (i = 0; i < CPRMAN_NUM_PLL; i++) { + device_cold_reset(DEVICE(&s->plls[i])); + } + clock_update_hz(s->xosc, s->xosc_freq); } static void cprman_init(Object *obj) { BCM2835CprmanState *s = CPRMAN(obj); + size_t i; + + for (i = 0; i < CPRMAN_NUM_PLL; i++) { + object_initialize_child(obj, PLL_INIT_INFO[i].name, + &s->plls[i], TYPE_CPRMAN_PLL); + set_pll_init_info(s, &s->plls[i], i); + } s->xosc = clock_new(obj, "xosc"); memory_region_init_io(&s->iomem, obj, &cprman_ops, s, "bcm2835-cprman", 0x2000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); } +static void cprman_realize(DeviceState *dev, Error **errp) +{ + BCM2835CprmanState *s = CPRMAN(dev); + size_t i; + + for (i = 0; i < CPRMAN_NUM_PLL; i++) { + CprmanPllState *pll = &s->plls[i]; + + clock_set_source(pll->xosc_in, s->xosc); + + if (!qdev_realize(DEVICE(pll), NULL, errp)) { + return; + } + } +} + static const VMStateDescription cprman_vmstate = { .name = TYPE_BCM2835_CPRMAN, .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { @@ -140,10 +246,11 @@ static Property cprman_properties[] = { static void cprman_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = cprman_realize; dc->reset = cprman_reset; dc->vmsd = &cprman_vmstate; device_class_set_props(dc, cprman_properties); } @@ -156,8 +263,9 @@ static const TypeInfo cprman_info = { }; static void cprman_register_types(void) { type_register_static(&cprman_info); + type_register_static(&cprman_pll_info); } type_init(cprman_register_types); From patchwork Sat Oct 10 13:57:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 271612 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 41955C433DF for ; Sat, 10 Oct 2020 14:02:07 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D1B4F22283 for ; Sat, 10 Oct 2020 14:02:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="BhTGexII" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D1B4F22283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:33662 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFRl-0007aE-Tm for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:02:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40666) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN3-00016q-RT; Sat, 10 Oct 2020 09:57:13 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43612) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN0-0004Jy-K9; Sat, 10 Oct 2020 09:57:13 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 3922DC603D9; Sat, 10 Oct 2020 13:57:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6Tw5rebm56xIRl4Y6xn4/weNTQ41I+JOywwnSzbgJS4=; b=BhTGexIIs/0iGhxgH+MatA/U9FJ+hPA31H0s/0/D/gcplMpxCSDR/n/C3tf7fl0PGjfkcy iLZb6q1ayoeKZ1IDHuFZH6W9WXebcNFZiVWGRh9po58Ktd84ox6vo3H5BTZFsEPE0fJcYy UjPHknK1ahLXY9WqjWQSuRL+P/6YBo7KXUf38PYINwSifkW/TkP+yb/II+NkrdrxuC/rBs Vjaxa4j5ekGH8d89SDLMmfGEe749o4nl4Ho8oUF8kJCLE9AGlFCUsXaN+3hvIrW1Ycq395 wYW8oT0mO9NIED65G7b7wff/youVAcVYxWZs7mi43+YrVqfzJqu/mYuss96PAA== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 07/15] hw/misc/bcm2835_cprman: implement PLLs behaviour Date: Sat, 10 Oct 2020 15:57:51 +0200 Message-Id: <20201010135759.437903-8-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6Tw5rebm56xIRl4Y6xn4/weNTQ41I+JOywwnSzbgJS4=; b=OH1NhXoweXFHfWGRpCLw6O1VWQ2bQLdL6DfNP5J39NN7IYAlJF00msq9SGLw/rALKLSQ6X OGvjHS8O+GGjr9HrzG+Jij3usGD4jQHetA9C/kR/9k8oKQKHl+jOtb0Sv9rwRsl/rhsC4l mjfrrFCv3cWhKR76W+P4DMV1aQL+HfOfLLK4psPcqovnIsGftYUAPkXRkEJkegX/mNKHsJ cujbJPItzxecd7deUyTDLKcdbTgvWOC0mX5SFP7pL4R8bu/W7sUrqKqSVnQR7H12omiTiV ucmTMp/HLSXJw/r27L3zUEWecvX6COFd2l3s48smUvGJ6eC8hQINb+fWVLGmaw== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338224; a=rsa-sha256; cv=none; b=MYfcEpWhX++/a3IXMQvMEWF7hfIS33Y978NWitC0t/7nUOeBWgNSpofSMaE2OA9eF/ZuM83LaRW+3wAK2UQopL7f4BOuq00L5DVg19CKr51B9upDNOwdCxFar5fLaw3Op1ZRG/LU+O4Y4kCM1iBA6dPDQbNHI7+81WeeOo4/xS2hRxlVfHGwhHk0q//QHxsSkApwkMf9oO0ko0vS82v/Xdu0M0qdmQGqYIpO1oYZUYBDTZ7EwNq3fSjSMrY9At5BGuWgbxbcaM34rqeQzZRjp09I0c6+eihPSwCRQozV/S1LhF9+kJoLpM8txUgHvoMvLV4OCd8yLr5x43nuvGIEfA== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The CPRMAN PLLs generate a clock based on a prescaler, a multiplier and a divider. The prescaler doubles the parent (xosc) frequency, then the multiplier/divider are applied. The multiplier has an integer and a fractional part. This commit also implements the CPRMAN CM_LOCK register. This register reports which PLL is currently locked. We consider a PLL has being locked as soon as it is enabled (on real hardware, there is a delay after turning a PLL on, for it to stabilize). Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/misc/bcm2835_cprman_internals.h | 8 +++ hw/misc/bcm2835_cprman.c | 64 +++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index 340ad623bb..7aa46c6e18 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -98,10 +98,18 @@ REG32(A2W_PLLA_FRAC, 0x1200) REG32(A2W_PLLC_FRAC, 0x1220) REG32(A2W_PLLD_FRAC, 0x1240) REG32(A2W_PLLH_FRAC, 0x1260) REG32(A2W_PLLB_FRAC, 0x12e0) +/* misc registers */ +REG32(CM_LOCK, 0x114) + FIELD(CM_LOCK, FLOCKH, 12, 1) + FIELD(CM_LOCK, FLOCKD, 11, 1) + FIELD(CM_LOCK, FLOCKC, 10, 1) + FIELD(CM_LOCK, FLOCKB, 9, 1) + FIELD(CM_LOCK, FLOCKA, 8, 1) + /* * This field is common to all registers. Each register write value must match * the CPRMAN_PASSWORD magic value in its 8 MSB. */ FIELD(CPRMAN, PASSWORD, 24, 8) diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index b86f5901b8..144bcc289d 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -48,13 +48,51 @@ #include "hw/misc/bcm2835_cprman_internals.h" #include "trace.h" /* PLL */ +static bool pll_is_locked(const CprmanPllState *pll) +{ + return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN) + && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST); +} + static void pll_update(CprmanPllState *pll) { - clock_update(pll->out, 0); + uint64_t freq, ndiv, fdiv, pdiv; + + if (!pll_is_locked(pll)) { + clock_update(pll->out, 0); + return; + } + + pdiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PDIV); + + if (!pdiv) { + clock_update(pll->out, 0); + return; + } + + ndiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, NDIV); + fdiv = FIELD_EX32(*pll->reg_a2w_frac, A2W_PLLx_FRAC, FRAC); + + if (pll->reg_a2w_ana[1] & pll->prediv_mask) { + /* The prescaler doubles the parent frequency */ + ndiv *= 2; + fdiv *= 2; + } + + /* + * We have a multiplier with an integer part (ndiv) and a fractional part + * (fdiv), and a divider (pdiv). + */ + freq = clock_get_hz(pll->xosc_in) * + ((ndiv << R_A2W_PLLx_FRAC_FRAC_LENGTH) + fdiv); + freq /= pdiv; + freq >>= R_A2W_PLLx_FRAC_FRAC_LENGTH; + + clock_update_hz(pll->out, freq); } static void pll_xosc_update(void *opaque) { pll_update(CPRMAN_PLL(opaque)); @@ -94,18 +132,42 @@ static const TypeInfo cprman_pll_info = { }; /* CPRMAN "top level" model */ +static uint32_t get_cm_lock(const BCM2835CprmanState *s) +{ + static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = { + [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT, + [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT, + [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT, + [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT, + [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT, + }; + + uint32_t r = 0; + size_t i; + + for (i = 0; i < CPRMAN_NUM_PLL; i++) { + r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i]; + } + + return r; +} + static uint64_t cprman_read(void *opaque, hwaddr offset, unsigned size) { BCM2835CprmanState *s = CPRMAN(opaque); uint64_t r = 0; size_t idx = offset / sizeof(uint32_t); switch (idx) { + case R_CM_LOCK: + r = get_cm_lock(s); + break; + default: r = s->regs[idx]; } trace_bcm2835_cprman_read(offset, r); From patchwork Sat Oct 10 13:57:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 271611 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 09295C433DF for ; Sat, 10 Oct 2020 14:04:45 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7A01F22283 for ; Sat, 10 Oct 2020 14:04:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="EMhBCi/C" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7A01F22283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:42486 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFUJ-0002ro-Lb for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:04:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40670) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN4-00018H-Bi; Sat, 10 Oct 2020 09:57:14 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43614) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN0-0004Jz-Io; Sat, 10 Oct 2020 09:57:13 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 5C6A7C603DA; Sat, 10 Oct 2020 13:57:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NmpeIs/KxZ0nwoVwshfm33d4zNSTn7PVf5VKmIRAe2o=; b=EMhBCi/CuWvYgCyPn22FYgxncqcQrw84UAlEPg0AXQw53RWyv+XRCznI63l1GBydH4T9Qt p4qNQr0DZda8JvKKPD4QgnZYlU8BYEQSlElV5QmRp6/XpTTpqD4qLi8ETWLvblV9UWYD/p ZNZa7sZl3Bla9HnXa+DtNvQOIQSHlSNqAKxJCpljdBdPKSnLRpiitglu8J8NroYOkTK2nv V7J2h0tlqbcCt2pBRkVyKor6fUS4DBG+Yjval0dvOG5VzDNoOzQt3WJXth48GN5vTXONmz A6J/NQhWmiomIeWFdJ4Q7bqhiphFRi/8v5NpaUMH+yAAVBJlndGzvoQ5mJaeDg== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 08/15] hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation Date: Sat, 10 Oct 2020 15:57:52 +0200 Message-Id: <20201010135759.437903-9-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NmpeIs/KxZ0nwoVwshfm33d4zNSTn7PVf5VKmIRAe2o=; b=EDtId9VqGPn4xpe45flHbU49IMwWqYx3XCb5qHFBwZrY6ZPQy83Z2y4Zw3Tk90QkI8d2NY dRfR5sEda3rEdeqPk1ul7VENokaLJEd7kxKoQSzP8WRcpESuTrmHTs6Iq/AaDyoyI5eRlV T6EEOEvQYx+MeDSuYWp0b7nwU0O6Y9xum7ALMXWRFIJ0TiF0EUbYdIEHL8+/O/uh527/DN QAhNGTbHUY+Et3nRiND5ApJ5305n+rxDnD3USfmTUMq6I+zj0s/OPIFpSC+8gZ4eC4u0TG G4hoLnBxiDo0LMeDFAUynCV8QzpsFclmfAFiFQczNy/EJnAXjS4/yYYfOozDUA== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338224; a=rsa-sha256; cv=none; b=ZlWTM9fYUIlCw79trw1bQiKTrscUJHTOhZ7THPY6GBL4STP/Sbj8hjCwV+ST6oIiTpb+/UUCQO0wYKtWAIYisUW+LmkJCzht2nqtOoGOvc2Qun9MFqmyMrw060Eq/lx+JgsvZcEHdqGFzWkaT126RTNB0eL37CyHL+WQyMgsutymEoIkqtaC6/Er0ZrYMsMSSlft4YjK1JZbRjOJaJmyrN5TlLK5kOWbIxdS8P4IGri1gK0hJHx455YeEvT/WGZXjtdQyr/k7N5MBTYcELc1VZ7a9VpMoKAEPtX0eCb6WJZ44QOyV8S3d4PemtD9GYJDO0w2nICtk4NUT9XONlwMHA== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" PLLs are composed of multiple channels. Each channel outputs one clock signal. They are modeled as one device taking the PLL generated clock as input, and outputting a new clock. A channel shares the CM register with its parent PLL, and has its own A2W_CTRL register. A write to the CM register will trigger an update of the PLL and all its channels, while a write to an A2W_CTRL channel register will update the required channel only. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/misc/bcm2835_cprman.h | 44 ++++++ include/hw/misc/bcm2835_cprman_internals.h | 146 +++++++++++++++++++ hw/misc/bcm2835_cprman.c | 155 +++++++++++++++++++-- 3 files changed, 337 insertions(+), 8 deletions(-) diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index 5c442e6ff9..e1a1b33f8b 100644 --- a/include/hw/misc/bcm2835_cprman.h +++ b/include/hw/misc/bcm2835_cprman.h @@ -29,10 +29,35 @@ typedef enum CprmanPll { CPRMAN_PLLB, CPRMAN_NUM_PLL } CprmanPll; +typedef enum CprmanPllChannel { + CPRMAN_PLLA_CHANNEL_DSI0 = 0, + CPRMAN_PLLA_CHANNEL_CORE, + CPRMAN_PLLA_CHANNEL_PER, + CPRMAN_PLLA_CHANNEL_CCP2, + + CPRMAN_PLLC_CHANNEL_CORE2, + CPRMAN_PLLC_CHANNEL_CORE1, + CPRMAN_PLLC_CHANNEL_PER, + CPRMAN_PLLC_CHANNEL_CORE0, + + CPRMAN_PLLD_CHANNEL_DSI0, + CPRMAN_PLLD_CHANNEL_CORE, + CPRMAN_PLLD_CHANNEL_PER, + CPRMAN_PLLD_CHANNEL_DSI1, + + CPRMAN_PLLH_CHANNEL_AUX, + CPRMAN_PLLH_CHANNEL_RCAL, + CPRMAN_PLLH_CHANNEL_PIX, + + CPRMAN_PLLB_CHANNEL_ARM, + + CPRMAN_NUM_PLL_CHANNEL, +} CprmanPllChannel; + typedef struct CprmanPllState { /*< private >*/ DeviceState parent_obj; /*< public >*/ @@ -46,18 +71,37 @@ typedef struct CprmanPllState { Clock *xosc_in; Clock *out; } CprmanPllState; +typedef struct CprmanPllChannelState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + CprmanPllChannel id; + CprmanPll parent; + + uint32_t *reg_cm; + uint32_t hold_mask; + uint32_t load_mask; + uint32_t *reg_a2w_ctrl; + int fixed_divider; + + Clock *pll_in; + Clock *out; +} CprmanPllChannelState; + struct BCM2835CprmanState { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ MemoryRegion iomem; CprmanPllState plls[CPRMAN_NUM_PLL]; + CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL]; uint32_t regs[CPRMAN_NUM_REGS]; uint32_t xosc_freq; Clock *xosc; diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index 7aa46c6e18..7409ddb024 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -11,13 +11,16 @@ #include "hw/registerfields.h" #include "hw/misc/bcm2835_cprman.h" #define TYPE_CPRMAN_PLL "bcm2835-cprman-pll" +#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel" DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL, TYPE_CPRMAN_PLL) +DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL, + TYPE_CPRMAN_PLL_CHANNEL) /* Register map */ /* PLLs */ REG32(CM_PLLA, 0x104) @@ -98,10 +101,35 @@ REG32(A2W_PLLA_FRAC, 0x1200) REG32(A2W_PLLC_FRAC, 0x1220) REG32(A2W_PLLD_FRAC, 0x1240) REG32(A2W_PLLH_FRAC, 0x1260) REG32(A2W_PLLB_FRAC, 0x12e0) +/* PLL channels */ +REG32(A2W_PLLA_DSI0, 0x1300) + FIELD(A2W_PLLx_CHANNELy, DIV, 0, 8) + FIELD(A2W_PLLx_CHANNELy, DISABLE, 8, 1) +REG32(A2W_PLLA_CORE, 0x1400) +REG32(A2W_PLLA_PER, 0x1500) +REG32(A2W_PLLA_CCP2, 0x1600) + +REG32(A2W_PLLC_CORE2, 0x1320) +REG32(A2W_PLLC_CORE1, 0x1420) +REG32(A2W_PLLC_PER, 0x1520) +REG32(A2W_PLLC_CORE0, 0x1620) + +REG32(A2W_PLLD_DSI0, 0x1340) +REG32(A2W_PLLD_CORE, 0x1440) +REG32(A2W_PLLD_PER, 0x1540) +REG32(A2W_PLLD_DSI1, 0x1640) + +REG32(A2W_PLLH_AUX, 0x1360) +REG32(A2W_PLLH_RCAL, 0x1460) +REG32(A2W_PLLH_PIX, 0x1560) +REG32(A2W_PLLH_STS, 0x1660) + +REG32(A2W_PLLB_ARM, 0x13e0) + /* misc registers */ REG32(CM_LOCK, 0x114) FIELD(CM_LOCK, FLOCKH, 12, 1) FIELD(CM_LOCK, FLOCKD, 11, 1) FIELD(CM_LOCK, FLOCKC, 10, 1) @@ -171,6 +199,124 @@ static inline void set_pll_init_info(BCM2835CprmanState *s, pll->reg_a2w_ana = &s->regs[PLL_INIT_INFO[id].a2w_ana_offset]; pll->prediv_mask = PLL_INIT_INFO[id].prediv_mask; pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset]; } + +/* PLL channel init info */ +typedef struct PLLChannelInitInfo { + const char *name; + CprmanPll parent; + size_t cm_offset; + uint32_t cm_hold_mask; + uint32_t cm_load_mask; + size_t a2w_ctrl_offset; + unsigned int fixed_divider; +} PLLChannelInitInfo; + +#define FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_) \ + .parent = CPRMAN_ ## pll_, \ + .cm_offset = R_CM_ ## pll_, \ + .cm_load_mask = R_CM_ ## pll_ ## _ ## LOAD ## channel_ ## _MASK, \ + .a2w_ctrl_offset = R_A2W_ ## pll_ ## _ ## channel_ + +#define FILL_PLL_CHANNEL_INIT_INFO(pll_, channel_) \ + FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \ + .cm_hold_mask = R_CM_ ## pll_ ## _ ## HOLD ## channel_ ## _MASK, \ + .fixed_divider = 1 + +#define FILL_PLL_CHANNEL_INIT_INFO_nohold(pll_, channel_) \ + FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \ + .cm_hold_mask = 0 + +static PLLChannelInitInfo PLL_CHANNEL_INIT_INFO[] = { + [CPRMAN_PLLA_CHANNEL_DSI0] = { + .name = "plla-dsi0", + FILL_PLL_CHANNEL_INIT_INFO(PLLA, DSI0), + }, + [CPRMAN_PLLA_CHANNEL_CORE] = { + .name = "plla-core", + FILL_PLL_CHANNEL_INIT_INFO(PLLA, CORE), + }, + [CPRMAN_PLLA_CHANNEL_PER] = { + .name = "plla-per", + FILL_PLL_CHANNEL_INIT_INFO(PLLA, PER), + }, + [CPRMAN_PLLA_CHANNEL_CCP2] = { + .name = "plla-ccp2", + FILL_PLL_CHANNEL_INIT_INFO(PLLA, CCP2), + }, + + [CPRMAN_PLLC_CHANNEL_CORE2] = { + .name = "pllc-core2", + FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE2), + }, + [CPRMAN_PLLC_CHANNEL_CORE1] = { + .name = "pllc-core1", + FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE1), + }, + [CPRMAN_PLLC_CHANNEL_PER] = { + .name = "pllc-per", + FILL_PLL_CHANNEL_INIT_INFO(PLLC, PER), + }, + [CPRMAN_PLLC_CHANNEL_CORE0] = { + .name = "pllc-core0", + FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE0), + }, + + [CPRMAN_PLLD_CHANNEL_DSI0] = { + .name = "plld-dsi0", + FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI0), + }, + [CPRMAN_PLLD_CHANNEL_CORE] = { + .name = "plld-core", + FILL_PLL_CHANNEL_INIT_INFO(PLLD, CORE), + }, + [CPRMAN_PLLD_CHANNEL_PER] = { + .name = "plld-per", + FILL_PLL_CHANNEL_INIT_INFO(PLLD, PER), + }, + [CPRMAN_PLLD_CHANNEL_DSI1] = { + .name = "plld-dsi1", + FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI1), + }, + + [CPRMAN_PLLH_CHANNEL_AUX] = { + .name = "pllh-aux", + .fixed_divider = 1, + FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, AUX), + }, + [CPRMAN_PLLH_CHANNEL_RCAL] = { + .name = "pllh-rcal", + .fixed_divider = 10, + FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, RCAL), + }, + [CPRMAN_PLLH_CHANNEL_PIX] = { + .name = "pllh-pix", + .fixed_divider = 10, + FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, PIX), + }, + + [CPRMAN_PLLB_CHANNEL_ARM] = { + .name = "pllb-arm", + FILL_PLL_CHANNEL_INIT_INFO(PLLB, ARM), + }, +}; + +#undef FILL_PLL_CHANNEL_INIT_INFO_nohold +#undef FILL_PLL_CHANNEL_INIT_INFO +#undef FILL_PLL_CHANNEL_INIT_INFO_common + +static inline void set_pll_channel_init_info(BCM2835CprmanState *s, + CprmanPllChannelState *channel, + CprmanPllChannel id) +{ + channel->id = id; + channel->parent = PLL_CHANNEL_INIT_INFO[id].parent; + channel->reg_cm = &s->regs[PLL_CHANNEL_INIT_INFO[id].cm_offset]; + channel->hold_mask = PLL_CHANNEL_INIT_INFO[id].cm_hold_mask; + channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask; + channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset]; + channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider; +} + #endif diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 144bcc289d..12fa78181b 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -130,10 +130,73 @@ static const TypeInfo cprman_pll_info = { .class_init = pll_class_init, .instance_init = pll_init, }; +/* PLL channel */ + +static void pll_channel_update(CprmanPllChannelState *channel) +{ + clock_update(channel->out, 0); +} + +/* Update a PLL and all its channels */ +static void pll_update_all_channels(BCM2835CprmanState *s, + CprmanPllState *pll) +{ + size_t i; + + pll_update(pll); + + for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { + CprmanPllChannelState *channel = &s->channels[i]; + if (channel->parent == pll->id) { + pll_channel_update(channel); + } + } +} + +static void pll_channel_pll_in_update(void *opaque) +{ + pll_channel_update(CPRMAN_PLL_CHANNEL(opaque)); +} + +static void pll_channel_init(Object *obj) +{ + CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj); + + s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in", + pll_channel_pll_in_update, s); + s->out = qdev_init_clock_out(DEVICE(s), "out"); +} + +static const VMStateDescription pll_channel_vmstate = { + .name = TYPE_CPRMAN_PLL_CHANNEL, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_CLOCK(pll_in, CprmanPllChannelState), + VMSTATE_END_OF_LIST() + } +}; + +static void pll_channel_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &pll_channel_vmstate; +} + +static const TypeInfo cprman_pll_channel_info = { + .name = TYPE_CPRMAN_PLL_CHANNEL, + .parent = TYPE_DEVICE, + .instance_size = sizeof(CprmanPllChannelState), + .class_init = pll_channel_class_init, + .instance_init = pll_channel_init, +}; + + /* CPRMAN "top level" model */ static uint32_t get_cm_lock(const BCM2835CprmanState *s) { static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = { @@ -172,12 +235,36 @@ static uint64_t cprman_read(void *opaque, hwaddr offset, trace_bcm2835_cprman_read(offset, r); return r; } -#define CASE_PLL_REGS(pll_) \ - case R_CM_ ## pll_: \ +static inline void update_pll_and_channels_from_cm(BCM2835CprmanState *s, + size_t idx) +{ + size_t i; + + for (i = 0; i < CPRMAN_NUM_PLL; i++) { + if (PLL_INIT_INFO[i].cm_offset == idx) { + pll_update_all_channels(s, &s->plls[i]); + return; + } + } +} + +static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx) +{ + size_t i; + + for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { + if (PLL_CHANNEL_INIT_INFO[i].a2w_ctrl_offset == idx) { + pll_channel_update(&s->channels[i]); + return; + } + } +} + +#define CASE_PLL_A2W_REGS(pll_) \ case R_A2W_ ## pll_ ## _CTRL: \ case R_A2W_ ## pll_ ## _ANA0: \ case R_A2W_ ## pll_ ## _ANA1: \ case R_A2W_ ## pll_ ## _ANA2: \ case R_A2W_ ## pll_ ## _ANA3: \ @@ -198,33 +285,61 @@ static void cprman_write(void *opaque, hwaddr offset, trace_bcm2835_cprman_write(offset, value); s->regs[idx] = value; switch (idx) { - CASE_PLL_REGS(PLLA) : + case R_CM_PLLA ... R_CM_PLLH: + case R_CM_PLLB: + /* + * A given CM_PLLx register is shared by both the PLL and the channels + * of this PLL. + */ + update_pll_and_channels_from_cm(s, idx); + break; + + CASE_PLL_A2W_REGS(PLLA) : pll_update(&s->plls[CPRMAN_PLLA]); break; - CASE_PLL_REGS(PLLC) : + CASE_PLL_A2W_REGS(PLLC) : pll_update(&s->plls[CPRMAN_PLLC]); break; - CASE_PLL_REGS(PLLD) : + CASE_PLL_A2W_REGS(PLLD) : pll_update(&s->plls[CPRMAN_PLLD]); break; - CASE_PLL_REGS(PLLH) : + CASE_PLL_A2W_REGS(PLLH) : pll_update(&s->plls[CPRMAN_PLLH]); break; - CASE_PLL_REGS(PLLB) : + CASE_PLL_A2W_REGS(PLLB) : pll_update(&s->plls[CPRMAN_PLLB]); break; + + case R_A2W_PLLA_DSI0: + case R_A2W_PLLA_CORE: + case R_A2W_PLLA_PER: + case R_A2W_PLLA_CCP2: + case R_A2W_PLLC_CORE2: + case R_A2W_PLLC_CORE1: + case R_A2W_PLLC_PER: + case R_A2W_PLLC_CORE0: + case R_A2W_PLLD_DSI0: + case R_A2W_PLLD_CORE: + case R_A2W_PLLD_PER: + case R_A2W_PLLD_DSI1: + case R_A2W_PLLH_AUX: + case R_A2W_PLLH_RCAL: + case R_A2W_PLLH_PIX: + case R_A2W_PLLB_ARM: + update_channel_from_a2w(s, idx); + break; } } -#undef CASE_PLL_REGS +#undef CASE_PLL_A2W_REGS static const MemoryRegionOps cprman_ops = { .read = cprman_read, .write = cprman_write, .endianness = DEVICE_LITTLE_ENDIAN, @@ -252,10 +367,14 @@ static void cprman_reset(DeviceState *dev) for (i = 0; i < CPRMAN_NUM_PLL; i++) { device_cold_reset(DEVICE(&s->plls[i])); } + for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { + device_cold_reset(DEVICE(&s->channels[i])); + } + clock_update_hz(s->xosc, s->xosc_freq); } static void cprman_init(Object *obj) { @@ -266,10 +385,17 @@ static void cprman_init(Object *obj) object_initialize_child(obj, PLL_INIT_INFO[i].name, &s->plls[i], TYPE_CPRMAN_PLL); set_pll_init_info(s, &s->plls[i], i); } + for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { + object_initialize_child(obj, PLL_CHANNEL_INIT_INFO[i].name, + &s->channels[i], + TYPE_CPRMAN_PLL_CHANNEL); + set_pll_channel_init_info(s, &s->channels[i], i); + } + s->xosc = clock_new(obj, "xosc"); memory_region_init_io(&s->iomem, obj, &cprman_ops, s, "bcm2835-cprman", 0x2000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); @@ -287,10 +413,22 @@ static void cprman_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(pll), NULL, errp)) { return; } } + + for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { + CprmanPllChannelState *channel = &s->channels[i]; + CprmanPll parent = PLL_CHANNEL_INIT_INFO[i].parent; + Clock *parent_clk = s->plls[parent].out; + + clock_set_source(channel->pll_in, parent_clk); + + if (!qdev_realize(DEVICE(channel), NULL, errp)) { + return; + } + } } static const VMStateDescription cprman_vmstate = { .name = TYPE_BCM2835_CPRMAN, .version_id = 1, @@ -326,8 +464,9 @@ static const TypeInfo cprman_info = { static void cprman_register_types(void) { type_register_static(&cprman_info); type_register_static(&cprman_pll_info); + type_register_static(&cprman_pll_channel_info); } type_init(cprman_register_types); From patchwork Sat Oct 10 13:57:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 271610 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id ACBABC433DF for ; Sat, 10 Oct 2020 14:06:31 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4733E22283 for ; Sat, 10 Oct 2020 14:06:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="FCXcW2HP" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4733E22283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:49214 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFW2-0005hj-6m for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:06:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40720) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNM-0001uG-IG; Sat, 10 Oct 2020 09:57:32 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43618) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNK-0004K6-Lk; Sat, 10 Oct 2020 09:57:32 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 85E50C603DB; Sat, 10 Oct 2020 13:57:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MOTPkXjvC2zXyPDpTmjJaf2TrTkZXbIsOjedNDmg/rk=; b=FCXcW2HPG1yj2RzwiuY/fAD8oswAAAspJiOBgCOK1E3Y1WiSgMTtYN+XCAA46Ds8WgujGY 3/g2DX2v4GCfLE2HYYFsxoGOD7Rv0kCiuPGWLH8aGX65LX40waKiUBWd20fiDgZuPJLNTJ Cz8+fAIjrAf0hdltxnHXzTKmxCuKNgurbPJg+2SxQ/ZZ2Nu0AxFmZZxh4g/dK/fHraG/xS +9y03q4IXxxgOnORfBDl4kDyI3NwLJHiLUMAf5ZyzAu+hPdWtt1dRRU3Zt4Mk39wf8f+cE E2JgoRKp3ZMVfgB3w0MvCEXQQLoqu97A5RjnswQawUnv/8+l5d6oVEifKqZZ5w== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 09/15] hw/misc/bcm2835_cprman: implement PLL channels behaviour Date: Sat, 10 Oct 2020 15:57:53 +0200 Message-Id: <20201010135759.437903-10-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MOTPkXjvC2zXyPDpTmjJaf2TrTkZXbIsOjedNDmg/rk=; b=LW3r/xN7jAeMaUNNC/Y0ElFKO8hOxRxlTNmQFQyWOBqdsAKZ4ap+7H7/4l5gcKkKMPU9Fj 5DW5D1d8et4m7cgQCC7wp69jkcunw2POwQfDhnT65jxLboR1uSaT6iFu7D36gjJ2Qe3OOL ZCiLKtmASEFBA73wvkqssAbHbk2oZ9hP9ENP71GhsCaQf0WDqfqLs8yrxSrECI8XbsBGXU Zx4DyrdkIZKFtrwbHKLM1LVW4Th/FsAy3xGcL46TFGIt/JJxPiEaNjeSmVDqEyyWpFaThg ALZcDujbNC1x5IfvT3k0FSL3T3duPcv5JgKkyttQcgV9H5bQJW0DeheQm3uB1g== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338224; a=rsa-sha256; cv=none; b=g4DYgU3Ygp4aBc7m86oIDi4xMJ1WjM+Zcm87tdOs5YNpJ7Q1ywjeZTgrhQhGhI02LUZ/3Ew9Q06uzpDuq4Wov/+vfCoGJhc7IvW+lX+N3076/8p7F2TdGrV0YbFByl3isj/oHVqw6BQnuhEBK4ARKj4jLgxso3xy/eydpqUWgTKtT4bhmBnLiRRcZ78QBn2Hs5VyL6FsZcKTXz0i/A9KSPBlzjv23lRniBWQfWzdpQUt/pztQ412fAs3uzPKSnvbaWPCESFLoiLWMc0TYvaafyHhN3/fx0oCcLydjUAoZqBRdanDg/JsRiBWSqvOAhIwV3V7JJHicM2/pSz7knHNTQ== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" A PLL channel is able to further divide the generated PLL frequency. The divider is given in the CTRL_A2W register. Some channels have an additional fixed divider which is always applied to the signal. Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- hw/misc/bcm2835_cprman.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 12fa78181b..71c1d7b9e7 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -132,13 +132,44 @@ static const TypeInfo cprman_pll_info = { }; /* PLL channel */ +static bool pll_channel_is_enabled(CprmanPllChannelState *channel) +{ + /* + * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does + * not set it when enabling the channel, but does clear it when disabling + * it. + */ + return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE) + && !(*channel->reg_cm & channel->hold_mask); +} + static void pll_channel_update(CprmanPllChannelState *channel) { - clock_update(channel->out, 0); + uint64_t freq, div; + + if (!pll_channel_is_enabled(channel)) { + clock_update(channel->out, 0); + return; + } + + div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV); + + if (!div) { + /* + * It seems that when the divider value is 0, it is considered as + * being maximum by the hardware (see the Linux driver). + */ + div = R_A2W_PLLx_CHANNELy_DIV_MASK; + } + + /* Some channels have an additional fixed divider */ + freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider); + + clock_update_hz(channel->out, freq); } /* Update a PLL and all its channels */ static void pll_update_all_channels(BCM2835CprmanState *s, CprmanPllState *pll) From patchwork Sat Oct 10 13:57:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303204 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EF5E4C433DF for ; Sat, 10 Oct 2020 14:04:26 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 450F122283 for ; Sat, 10 Oct 2020 14:04:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="OiPuAydE" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 450F122283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40598 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFU1-00026Y-0f for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:04:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40672) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN5-0001B3-Ad; Sat, 10 Oct 2020 09:57:15 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43616) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFN0-0004K5-Km; Sat, 10 Oct 2020 09:57:14 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 9AF37C603DC; Sat, 10 Oct 2020 13:57:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bzBaQskQbBw7GtRyFMme72qLf5nsioD+4Bpv755k4Go=; b=OiPuAydEsoSpUGQi3WasSEQCIam1RDUqrVo3kJ9X/s7JzR+z9dH7qL1CtYjoFFz9pgOU4D 173guCiLCvK4W3jVRzZmhPwSBzUCwyeVU5T5ow3KQTEHtcvv4WgbzA5J5NJI0GkBp4+J7J 1fZ2w6PZTgMm276jbewZFsGmeEs6qMhYhJKz9Lz/wmNYn7JY2JgSGpa0Z7iRq0BDRZXtvR mozaOrt2ATy/E/QuHIpo4aYtQ5jUdYY5lTNtvOEYAjHMzoJk9Xpgjq4XOfY9D739QOfA7b 4qfIIFSYmBRtxDCz38eFjnIDNKa1TVsBwuxpHHxPTbsF+SmT/9q/QnAEDXPNqg== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 10/15] hw/misc/bcm2835_cprman: add a clock mux skeleton implementation Date: Sat, 10 Oct 2020 15:57:54 +0200 Message-Id: <20201010135759.437903-11-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bzBaQskQbBw7GtRyFMme72qLf5nsioD+4Bpv755k4Go=; b=FIz68IIVbqJo131lG7g4lasQaggy+gyoGuYx9O3sNOG62SbryaeRbWt3zKFtrbodaobB/X OwZgcQW7S+IrsnpGLrDQWLs3DgEZfsR6ZRyX+DwRBhRYc67mb/hyC2iwvbN6M3VjUBB532 YdsmVI3dplW1bdKWObthKuq5YUPkGaq6R2swtBZ9n9ecHoRxhxN2RC9CFtd8Gp4aNC5ft/ w2zxW7Cx4AoCPcNoTpyFCIjcfGz367kqPOtzLNfmp58/EeK6jRPYLIxRDP5mzsFWJYcGEb uuYbLAaC+qhGldXkFyX5o5Ca/ngOXNbc06ZMvU415w3R7OqGoWTTH6OzR+QCDg== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338224; a=rsa-sha256; cv=none; b=SQBZmWESDi4gR2EzCvqL08iRsitQ79RyYY8KlcV2WhIb9ssr4OjEG62m0TDfTsFZLXoJNP1i1KxdUuWif/gscQKB76SUApUY/67KFpDlIoAyQUqShGVjnomI0K1vkB1sNcKHfTKMQC7JX7kciBMD3ifN44Z1T6Mkz0w8Ilrz/PUKzgyAkn/E4+IK+bz4KtTsd/LGXgudLngoJMxMlkx88izn92mA5XGHcfAxusM/qKNJsIbd1NHpcK0/7FKkr4B3CVhaPDA3Adw+zJk8tEAewv46KrPoQH+jSHKy+mFd15hZRawerXVP+nwQQV0LdjDUohM7Y2XK7BNvy/aa37Cpog== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The clock multiplexers are the last clock stage in the CPRMAN. Each mux outputs one clock signal that goes out of the CPRMAN to the SoC peripherals. Each mux has at most 10 sources. The sources 0 to 3 are common to all muxes. They are: 0. ground (no clock signal) 1. the main oscillator (xosc) 2. "test debug 0" clock 3. "test debug 1" clock Test debug 0 and 1 are actual clock muxes that can be used as sources to other muxes (for debug purpose). Sources 4 to 9 are mux specific and can be unpopulated (grounded). Those sources are fed by the PLL channels outputs. One corner case exists for DSI0E and DSI0P muxes. They have their source number 4 connected to an intermediate multiplexer that can select between PLLA-DSI0 and PLLD-DSI0 channel. This multiplexer is called DSI0HSCK and is not a clock mux as such. It is really a simple mux from the hardware point of view (see https://elinux.org/The_Undocumented_Pi). This mux is not implemented in this commit. Note that there is some muxes for which sources are unknown (because of a lack of documentation). For those cases all the sources are connected to ground in this implementation. Each clock mux output is exported by the CPRMAN at the qdev level, adding the suffix '-out' to the mux name to form the output clock name. (E.g. the 'uart' mux sees its output exported as 'uart-out' at the CPRMAN level.) Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/misc/bcm2835_cprman.h | 85 +++++ include/hw/misc/bcm2835_cprman_internals.h | 422 +++++++++++++++++++++ hw/misc/bcm2835_cprman.c | 151 ++++++++ 3 files changed, 658 insertions(+) diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index e1a1b33f8b..0fc8f68845 100644 --- a/include/hw/misc/bcm2835_cprman.h +++ b/include/hw/misc/bcm2835_cprman.h @@ -52,12 +52,73 @@ typedef enum CprmanPllChannel { CPRMAN_PLLH_CHANNEL_PIX, CPRMAN_PLLB_CHANNEL_ARM, CPRMAN_NUM_PLL_CHANNEL, + + /* Special values used when connecting clock sources to clocks */ + CPRMAN_CLOCK_SRC_NORMAL = -1, + CPRMAN_CLOCK_SRC_FORCE_GROUND = -2, + CPRMAN_CLOCK_SRC_DSI0HSCK = -3, } CprmanPllChannel; +typedef enum CprmanClockMux { + CPRMAN_CLOCK_GNRIC, + CPRMAN_CLOCK_VPU, + CPRMAN_CLOCK_SYS, + CPRMAN_CLOCK_PERIA, + CPRMAN_CLOCK_PERII, + CPRMAN_CLOCK_H264, + CPRMAN_CLOCK_ISP, + CPRMAN_CLOCK_V3D, + CPRMAN_CLOCK_CAM0, + CPRMAN_CLOCK_CAM1, + CPRMAN_CLOCK_CCP2, + CPRMAN_CLOCK_DSI0E, + CPRMAN_CLOCK_DSI0P, + CPRMAN_CLOCK_DPI, + CPRMAN_CLOCK_GP0, + CPRMAN_CLOCK_GP1, + CPRMAN_CLOCK_GP2, + CPRMAN_CLOCK_HSM, + CPRMAN_CLOCK_OTP, + CPRMAN_CLOCK_PCM, + CPRMAN_CLOCK_PWM, + CPRMAN_CLOCK_SLIM, + CPRMAN_CLOCK_SMI, + CPRMAN_CLOCK_TEC, + CPRMAN_CLOCK_TD0, + CPRMAN_CLOCK_TD1, + CPRMAN_CLOCK_TSENS, + CPRMAN_CLOCK_TIMER, + CPRMAN_CLOCK_UART, + CPRMAN_CLOCK_VEC, + CPRMAN_CLOCK_PULSE, + CPRMAN_CLOCK_SDC, + CPRMAN_CLOCK_ARM, + CPRMAN_CLOCK_AVEO, + CPRMAN_CLOCK_EMMC, + CPRMAN_CLOCK_EMMC2, + + CPRMAN_NUM_CLOCK_MUX +} CprmanClockMux; + +typedef enum CprmanClockMuxSource { + CPRMAN_CLOCK_SRC_GND = 0, + CPRMAN_CLOCK_SRC_XOSC, + CPRMAN_CLOCK_SRC_TD0, + CPRMAN_CLOCK_SRC_TD1, + CPRMAN_CLOCK_SRC_PLLA, + CPRMAN_CLOCK_SRC_PLLC, + CPRMAN_CLOCK_SRC_PLLD, + CPRMAN_CLOCK_SRC_PLLH, + CPRMAN_CLOCK_SRC_PLLC_CORE1, + CPRMAN_CLOCK_SRC_PLLC_CORE2, + + CPRMAN_NUM_CLOCK_MUX_SRC +} CprmanClockMuxSource; + typedef struct CprmanPllState { /*< private >*/ DeviceState parent_obj; /*< public >*/ @@ -89,22 +150,46 @@ typedef struct CprmanPllChannelState { Clock *pll_in; Clock *out; } CprmanPllChannelState; +typedef struct CprmanClockMuxState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + CprmanClockMux id; + + uint32_t *reg_ctl; + uint32_t *reg_div; + int int_bits; + int frac_bits; + + Clock *srcs[CPRMAN_NUM_CLOCK_MUX_SRC]; + Clock *out; + + /* + * Used by clock srcs update callback to retrieve both the clock and the + * source number. + */ + struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC]; +} CprmanClockMuxState; + struct BCM2835CprmanState { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ MemoryRegion iomem; CprmanPllState plls[CPRMAN_NUM_PLL]; CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL]; + CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX]; uint32_t regs[CPRMAN_NUM_REGS]; uint32_t xosc_freq; Clock *xosc; + Clock *gnd; }; #endif diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index 7409ddb024..0305448bbc 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -12,15 +12,18 @@ #include "hw/registerfields.h" #include "hw/misc/bcm2835_cprman.h" #define TYPE_CPRMAN_PLL "bcm2835-cprman-pll" #define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel" +#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux" DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL, TYPE_CPRMAN_PLL) DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL, TYPE_CPRMAN_PLL_CHANNEL) +DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX, + TYPE_CPRMAN_CLOCK_MUX) /* Register map */ /* PLLs */ REG32(CM_PLLA, 0x104) @@ -126,10 +129,94 @@ REG32(A2W_PLLH_RCAL, 0x1460) REG32(A2W_PLLH_PIX, 0x1560) REG32(A2W_PLLH_STS, 0x1660) REG32(A2W_PLLB_ARM, 0x13e0) +/* Clock muxes */ +REG32(CM_GNRICCTL, 0x000) + FIELD(CM_CLOCKx_CTL, SRC, 0, 4) + FIELD(CM_CLOCKx_CTL, ENABLE, 4, 1) + FIELD(CM_CLOCKx_CTL, KILL, 5, 1) + FIELD(CM_CLOCKx_CTL, GATE, 6, 1) + FIELD(CM_CLOCKx_CTL, BUSY, 7, 1) + FIELD(CM_CLOCKx_CTL, BUSYD, 8, 1) + FIELD(CM_CLOCKx_CTL, MASH, 9, 2) + FIELD(CM_CLOCKx_CTL, FLIP, 11, 1) +REG32(CM_GNRICDIV, 0x004) + FIELD(CM_CLOCKx_DIV, FRAC, 0, 12) +REG32(CM_VPUCTL, 0x008) +REG32(CM_VPUDIV, 0x00c) +REG32(CM_SYSCTL, 0x010) +REG32(CM_SYSDIV, 0x014) +REG32(CM_PERIACTL, 0x018) +REG32(CM_PERIADIV, 0x01c) +REG32(CM_PERIICTL, 0x020) +REG32(CM_PERIIDIV, 0x024) +REG32(CM_H264CTL, 0x028) +REG32(CM_H264DIV, 0x02c) +REG32(CM_ISPCTL, 0x030) +REG32(CM_ISPDIV, 0x034) +REG32(CM_V3DCTL, 0x038) +REG32(CM_V3DDIV, 0x03c) +REG32(CM_CAM0CTL, 0x040) +REG32(CM_CAM0DIV, 0x044) +REG32(CM_CAM1CTL, 0x048) +REG32(CM_CAM1DIV, 0x04c) +REG32(CM_CCP2CTL, 0x050) +REG32(CM_CCP2DIV, 0x054) +REG32(CM_DSI0ECTL, 0x058) +REG32(CM_DSI0EDIV, 0x05c) +REG32(CM_DSI0PCTL, 0x060) +REG32(CM_DSI0PDIV, 0x064) +REG32(CM_DPICTL, 0x068) +REG32(CM_DPIDIV, 0x06c) +REG32(CM_GP0CTL, 0x070) +REG32(CM_GP0DIV, 0x074) +REG32(CM_GP1CTL, 0x078) +REG32(CM_GP1DIV, 0x07c) +REG32(CM_GP2CTL, 0x080) +REG32(CM_GP2DIV, 0x084) +REG32(CM_HSMCTL, 0x088) +REG32(CM_HSMDIV, 0x08c) +REG32(CM_OTPCTL, 0x090) +REG32(CM_OTPDIV, 0x094) +REG32(CM_PCMCTL, 0x098) +REG32(CM_PCMDIV, 0x09c) +REG32(CM_PWMCTL, 0x0a0) +REG32(CM_PWMDIV, 0x0a4) +REG32(CM_SLIMCTL, 0x0a8) +REG32(CM_SLIMDIV, 0x0ac) +REG32(CM_SMICTL, 0x0b0) +REG32(CM_SMIDIV, 0x0b4) +REG32(CM_TCNTCTL, 0x0c0) +REG32(CM_TCNTCNT, 0x0c4) +REG32(CM_TECCTL, 0x0c8) +REG32(CM_TECDIV, 0x0cc) +REG32(CM_TD0CTL, 0x0d0) +REG32(CM_TD0DIV, 0x0d4) +REG32(CM_TD1CTL, 0x0d8) +REG32(CM_TD1DIV, 0x0dc) +REG32(CM_TSENSCTL, 0x0e0) +REG32(CM_TSENSDIV, 0x0e4) +REG32(CM_TIMERCTL, 0x0e8) +REG32(CM_TIMERDIV, 0x0ec) +REG32(CM_UARTCTL, 0x0f0) +REG32(CM_UARTDIV, 0x0f4) +REG32(CM_VECCTL, 0x0f8) +REG32(CM_VECDIV, 0x0fc) +REG32(CM_PULSECTL, 0x190) +REG32(CM_PULSEDIV, 0x194) +REG32(CM_SDCCTL, 0x1a8) +REG32(CM_SDCDIV, 0x1ac) +REG32(CM_ARMCTL, 0x1b0) +REG32(CM_AVEOCTL, 0x1b8) +REG32(CM_AVEODIV, 0x1bc) +REG32(CM_EMMCCTL, 0x1c0) +REG32(CM_EMMCDIV, 0x1c4) +REG32(CM_EMMC2CTL, 0x1d0) +REG32(CM_EMMC2DIV, 0x1d4) + /* misc registers */ REG32(CM_LOCK, 0x114) FIELD(CM_LOCK, FLOCKH, 12, 1) FIELD(CM_LOCK, FLOCKD, 11, 1) FIELD(CM_LOCK, FLOCKC, 10, 1) @@ -317,6 +404,341 @@ static inline void set_pll_channel_init_info(BCM2835CprmanState *s, channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask; channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset]; channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider; } +/* Clock mux init info */ +typedef struct ClockMuxInitInfo { + const char *name; + size_t cm_offset; /* cm_offset[0]->CM_CTL, cm_offset[1]->CM_DIV */ + int int_bits; + int frac_bits; + + CprmanPllChannel src_mapping[CPRMAN_NUM_CLOCK_MUX_SRC]; +} ClockMuxInitInfo; + +/* + * Each clock mux can have up to 10 sources. Sources 0 to 3 are always the + * same (ground, xosc, td0, td1). Sources 4 to 9 are mux specific, and are not + * always populated. The following macros catch all those cases. + */ + +/* Unknown mapping. Connect everything to ground */ +#define SRC_MAPPING_INFO_unknown \ + .src_mapping = { \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* gnd */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* xosc */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 0 */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 1 */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll a */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll d */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll h */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core1 */ \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core2 */ \ + } + +/* Only the oscillator and the two test debug clocks */ +#define SRC_MAPPING_INFO_xosc \ + .src_mapping = { \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + } + +/* All the PLL "core" channels */ +#define SRC_MAPPING_INFO_core \ + .src_mapping = { \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_PLLA_CHANNEL_CORE, \ + CPRMAN_PLLC_CHANNEL_CORE0, \ + CPRMAN_PLLD_CHANNEL_CORE, \ + CPRMAN_PLLH_CHANNEL_AUX, \ + CPRMAN_PLLC_CHANNEL_CORE1, \ + CPRMAN_PLLC_CHANNEL_CORE2, \ + } + +/* All the PLL "per" channels */ +#define SRC_MAPPING_INFO_periph \ + .src_mapping = { \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_PLLA_CHANNEL_PER, \ + CPRMAN_PLLC_CHANNEL_PER, \ + CPRMAN_PLLD_CHANNEL_PER, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + } + +/* + * The DSI0 channels. This one got an intermediate mux between the PLL channels + * and the clock input. + */ +#define SRC_MAPPING_INFO_dsi0 \ + .src_mapping = { \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_DSI0HSCK, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + } + +/* The DSI1 channel */ +#define SRC_MAPPING_INFO_dsi1 \ + .src_mapping = { \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_CLOCK_SRC_NORMAL, \ + CPRMAN_PLLD_CHANNEL_DSI1, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + CPRMAN_CLOCK_SRC_FORCE_GROUND, \ + } + +#define FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_) \ + SRC_MAPPING_INFO_ ## kind_ + +#define FILL_CLOCK_MUX_INIT_INFO(clock_, kind_) \ + .cm_offset = R_CM_ ## clock_ ## CTL, \ + FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_) + +static ClockMuxInitInfo CLOCK_MUX_INIT_INFO[] = { + [CPRMAN_CLOCK_GNRIC] = { + .name = "gnric", + FILL_CLOCK_MUX_INIT_INFO(GNRIC, unknown), + }, + [CPRMAN_CLOCK_VPU] = { + .name = "vpu", + .int_bits = 12, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(VPU, core), + }, + [CPRMAN_CLOCK_SYS] = { + .name = "sys", + FILL_CLOCK_MUX_INIT_INFO(SYS, unknown), + }, + [CPRMAN_CLOCK_PERIA] = { + .name = "peria", + FILL_CLOCK_MUX_INIT_INFO(PERIA, unknown), + }, + [CPRMAN_CLOCK_PERII] = { + .name = "perii", + FILL_CLOCK_MUX_INIT_INFO(PERII, unknown), + }, + [CPRMAN_CLOCK_H264] = { + .name = "h264", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(H264, core), + }, + [CPRMAN_CLOCK_ISP] = { + .name = "isp", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(ISP, core), + }, + [CPRMAN_CLOCK_V3D] = { + .name = "v3d", + FILL_CLOCK_MUX_INIT_INFO(V3D, core), + }, + [CPRMAN_CLOCK_CAM0] = { + .name = "cam0", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(CAM0, periph), + }, + [CPRMAN_CLOCK_CAM1] = { + .name = "cam1", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(CAM1, periph), + }, + [CPRMAN_CLOCK_CCP2] = { + .name = "ccp2", + FILL_CLOCK_MUX_INIT_INFO(CCP2, unknown), + }, + [CPRMAN_CLOCK_DSI0E] = { + .name = "dsi0e", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(DSI0E, dsi0), + }, + [CPRMAN_CLOCK_DSI0P] = { + .name = "dsi0p", + .int_bits = 0, + .frac_bits = 0, + FILL_CLOCK_MUX_INIT_INFO(DSI0P, dsi0), + }, + [CPRMAN_CLOCK_DPI] = { + .name = "dpi", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(DPI, periph), + }, + [CPRMAN_CLOCK_GP0] = { + .name = "gp0", + .int_bits = 12, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(GP0, periph), + }, + [CPRMAN_CLOCK_GP1] = { + .name = "gp1", + .int_bits = 12, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(GP1, periph), + }, + [CPRMAN_CLOCK_GP2] = { + .name = "gp2", + .int_bits = 12, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(GP2, periph), + }, + [CPRMAN_CLOCK_HSM] = { + .name = "hsm", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(HSM, periph), + }, + [CPRMAN_CLOCK_OTP] = { + .name = "otp", + .int_bits = 4, + .frac_bits = 0, + FILL_CLOCK_MUX_INIT_INFO(OTP, xosc), + }, + [CPRMAN_CLOCK_PCM] = { + .name = "pcm", + .int_bits = 12, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(PCM, periph), + }, + [CPRMAN_CLOCK_PWM] = { + .name = "pwm", + .int_bits = 12, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(PWM, periph), + }, + [CPRMAN_CLOCK_SLIM] = { + .name = "slim", + .int_bits = 12, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(SLIM, periph), + }, + [CPRMAN_CLOCK_SMI] = { + .name = "smi", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(SMI, periph), + }, + [CPRMAN_CLOCK_TEC] = { + .name = "tec", + .int_bits = 6, + .frac_bits = 0, + FILL_CLOCK_MUX_INIT_INFO(TEC, xosc), + }, + [CPRMAN_CLOCK_TD0] = { + .name = "td0", + FILL_CLOCK_MUX_INIT_INFO(TD0, unknown), + }, + [CPRMAN_CLOCK_TD1] = { + .name = "td1", + FILL_CLOCK_MUX_INIT_INFO(TD1, unknown), + }, + [CPRMAN_CLOCK_TSENS] = { + .name = "tsens", + .int_bits = 5, + .frac_bits = 0, + FILL_CLOCK_MUX_INIT_INFO(TSENS, xosc), + }, + [CPRMAN_CLOCK_TIMER] = { + .name = "timer", + .int_bits = 6, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(TIMER, xosc), + }, + [CPRMAN_CLOCK_UART] = { + .name = "uart", + .int_bits = 10, + .frac_bits = 12, + FILL_CLOCK_MUX_INIT_INFO(UART, periph), + }, + [CPRMAN_CLOCK_VEC] = { + .name = "vec", + .int_bits = 4, + .frac_bits = 0, + FILL_CLOCK_MUX_INIT_INFO(VEC, periph), + }, + [CPRMAN_CLOCK_PULSE] = { + .name = "pulse", + FILL_CLOCK_MUX_INIT_INFO(PULSE, xosc), + }, + [CPRMAN_CLOCK_SDC] = { + .name = "sdram", + .int_bits = 6, + .frac_bits = 0, + FILL_CLOCK_MUX_INIT_INFO(SDC, core), + }, + [CPRMAN_CLOCK_ARM] = { + .name = "arm", + FILL_CLOCK_MUX_INIT_INFO(ARM, unknown), + }, + [CPRMAN_CLOCK_AVEO] = { + .name = "aveo", + .int_bits = 4, + .frac_bits = 0, + FILL_CLOCK_MUX_INIT_INFO(AVEO, periph), + }, + [CPRMAN_CLOCK_EMMC] = { + .name = "emmc", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(EMMC, periph), + }, + [CPRMAN_CLOCK_EMMC2] = { + .name = "emmc2", + .int_bits = 4, + .frac_bits = 8, + FILL_CLOCK_MUX_INIT_INFO(EMMC2, unknown), + }, +}; + +#undef FILL_CLOCK_MUX_INIT_INFO +#undef FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO +#undef SRC_MAPPING_INFO_dsi1 +#undef SRC_MAPPING_INFO_dsi0 +#undef SRC_MAPPING_INFO_periph +#undef SRC_MAPPING_INFO_core +#undef SRC_MAPPING_INFO_xosc +#undef SRC_MAPPING_INFO_unknown + +static inline void set_clock_mux_init_info(BCM2835CprmanState *s, + CprmanClockMuxState *mux, + CprmanClockMux id) +{ + mux->id = id; + mux->reg_ctl = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset]; + mux->reg_div = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset + 1]; + mux->int_bits = CLOCK_MUX_INIT_INFO[id].int_bits; + mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits; +} + #endif diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 71c1d7b9e7..b22170f3bc 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -36,10 +36,13 @@ * | [mux] * \-->[PLL]--->[PLL channel] [mux] * * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock * tree configuration. + * + * The CPRMAN exposes clock outputs with the name of the clock mux suffixed + * with "-out" (e.g. "uart-out", "h264-out", ...). */ #include "qemu/osdep.h" #include "qemu/log.h" #include "migration/vmstate.h" @@ -224,10 +227,69 @@ static const TypeInfo cprman_pll_channel_info = { .class_init = pll_channel_class_init, .instance_init = pll_channel_init, }; +/* clock mux */ + +static void clock_mux_update(CprmanClockMuxState *mux) +{ + clock_update(mux->out, 0); +} + +static void clock_mux_src_update(void *opaque) +{ + CprmanClockMuxState **backref = opaque; + CprmanClockMuxState *s = *backref; + + clock_mux_update(s); +} + +static void clock_mux_init(Object *obj) +{ + CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj); + size_t i; + + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) { + char *name = g_strdup_printf("srcs[%zu]", i); + s->backref[i] = s; + s->srcs[i] = qdev_init_clock_in(DEVICE(s), name, + clock_mux_src_update, + &s->backref[i]); + g_free(name); + } + + s->out = qdev_init_clock_out(DEVICE(s), "out"); +} + +static const VMStateDescription clock_mux_vmstate = { + .name = TYPE_CPRMAN_CLOCK_MUX, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState, + CPRMAN_NUM_CLOCK_MUX_SRC), + VMSTATE_END_OF_LIST() + } +}; + +static void clock_mux_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &clock_mux_vmstate; +} + +static const TypeInfo cprman_clock_mux_info = { + .name = TYPE_CPRMAN_CLOCK_MUX, + .parent = TYPE_DEVICE, + .instance_size = sizeof(CprmanClockMuxState), + .class_init = clock_mux_class_init, + .instance_init = clock_mux_init, +}; + + /* CPRMAN "top level" model */ static uint32_t get_cm_lock(const BCM2835CprmanState *s) { static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = { @@ -291,10 +353,24 @@ static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx) return; } } } +static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx) +{ + size_t i; + + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { + if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx) || + (CLOCK_MUX_INIT_INFO[i].cm_offset + 4 == idx)) { + /* matches CM_CTL or CM_DIV mux register */ + clock_mux_update(&s->clock_muxes[i]); + return; + } + } +} + #define CASE_PLL_A2W_REGS(pll_) \ case R_A2W_ ## pll_ ## _CTRL: \ case R_A2W_ ## pll_ ## _ANA0: \ case R_A2W_ ## pll_ ## _ANA1: \ case R_A2W_ ## pll_ ## _ANA2: \ @@ -363,10 +439,19 @@ static void cprman_write(void *opaque, hwaddr offset, case R_A2W_PLLH_RCAL: case R_A2W_PLLH_PIX: case R_A2W_PLLB_ARM: update_channel_from_a2w(s, idx); break; + + case R_CM_GNRICCTL ... R_CM_SMIDIV: + case R_CM_TCNTCNT ... R_CM_VECDIV: + case R_CM_PULSECTL ... R_CM_PULSEDIV: + case R_CM_SDCCTL ... R_CM_ARMCTL: + case R_CM_AVEOCTL ... R_CM_EMMCDIV: + case R_CM_EMMC2CTL ... R_CM_EMMC2DIV: + update_mux_from_cm(s, idx); + break; } } #undef CASE_PLL_A2W_REGS @@ -402,10 +487,14 @@ static void cprman_reset(DeviceState *dev) for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { device_cold_reset(DEVICE(&s->channels[i])); } + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { + device_cold_reset(DEVICE(&s->clock_muxes[i])); + } + clock_update_hz(s->xosc, s->xosc_freq); } static void cprman_init(Object *obj) { @@ -423,17 +512,68 @@ static void cprman_init(Object *obj) &s->channels[i], TYPE_CPRMAN_PLL_CHANNEL); set_pll_channel_init_info(s, &s->channels[i], i); } + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { + char *alias; + + object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name, + &s->clock_muxes[i], + TYPE_CPRMAN_CLOCK_MUX); + set_clock_mux_init_info(s, &s->clock_muxes[i], i); + + /* Expose muxes output as CPRMAN outputs */ + alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name); + qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias); + g_free(alias); + } + s->xosc = clock_new(obj, "xosc"); + s->gnd = clock_new(obj, "gnd"); + + clock_set(s->gnd, 0); memory_region_init_io(&s->iomem, obj, &cprman_ops, s, "bcm2835-cprman", 0x2000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); } +static void connect_mux_sources(BCM2835CprmanState *s, + CprmanClockMuxState *mux, + const CprmanPllChannel *clk_mapping) +{ + size_t i; + Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out; + Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out; + + /* For sources from 0 to 3. Source 4 to 9 are mux specific */ + Clock * const CLK_SRC_MAPPING[] = { + [CPRMAN_CLOCK_SRC_GND] = s->gnd, + [CPRMAN_CLOCK_SRC_XOSC] = s->xosc, + [CPRMAN_CLOCK_SRC_TD0] = td0, + [CPRMAN_CLOCK_SRC_TD1] = td1, + }; + + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) { + CprmanPllChannel mapping = clk_mapping[i]; + Clock *src; + + if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) { + src = s->gnd; + } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) { + src = s->gnd; /* TODO */ + } else if (i < CPRMAN_CLOCK_SRC_PLLA) { + src = CLK_SRC_MAPPING[i]; + } else { + src = s->channels[mapping].out; + } + + clock_set_source(mux->srcs[i], src); + } +} + static void cprman_realize(DeviceState *dev, Error **errp) { BCM2835CprmanState *s = CPRMAN(dev); size_t i; @@ -456,10 +596,20 @@ static void cprman_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(channel), NULL, errp)) { return; } } + + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { + CprmanClockMuxState *clock_mux = &s->clock_muxes[i]; + + connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping); + + if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { + return; + } + } } static const VMStateDescription cprman_vmstate = { .name = TYPE_BCM2835_CPRMAN, .version_id = 1, @@ -496,8 +646,9 @@ static const TypeInfo cprman_info = { static void cprman_register_types(void) { type_register_static(&cprman_info); type_register_static(&cprman_pll_info); type_register_static(&cprman_pll_channel_info); + type_register_static(&cprman_clock_mux_info); } type_init(cprman_register_types); From patchwork Sat Oct 10 13:57:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303202 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DBA6FC433DF for ; Sat, 10 Oct 2020 14:07:03 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 743F322284 for ; Sat, 10 Oct 2020 14:07:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="hShqiR5y" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 743F322284 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:50816 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFWY-0006LD-Jv for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:07:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40722) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNM-0001uo-Oj; Sat, 10 Oct 2020 09:57:32 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43620) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNK-0004KF-Qp; Sat, 10 Oct 2020 09:57:32 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id BBC75C6041D; Sat, 10 Oct 2020 13:57:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JOcrHBo1jCCV2hHTLBCYiLIpeFKC44mDRpVy2DOXJo0=; b=hShqiR5yzsRDOUcA98E6fOIbziu3sgLPTblZOUM8hWWdoqlFOItny/5l1fOe71Cgyk1f6e 6IPZCylFSIK8XklqwkYKTVPUuppf9F9XpVpidXtLsmPvE4SOgYjEuCaczflB1lqOhxPdmQ C+6f+ZitOfdtLOz7RRlVttrhHgbkFzTwQ4MNJv2/rybwLBsNuXe9UdmXPbuCHLedpggPdp P7GzpZwXAJqKJftl4Vjhp5SNH57GNiqcIug95cBno5kRbLK6I55n+k37w05uBLvmxZSxUL 4lvPuvq8Etcz8azO9ctN1jRpWOFdgJRL7cLNpqtuD3D7MENd3RhGBxM6ksROww== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 11/15] hw/misc/bcm2835_cprman: implement clock mux behaviour Date: Sat, 10 Oct 2020 15:57:55 +0200 Message-Id: <20201010135759.437903-12-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JOcrHBo1jCCV2hHTLBCYiLIpeFKC44mDRpVy2DOXJo0=; b=QCHVdhXBfms/qj/S3fez9+ThpOCJQPQapD0ype880qal7AmJGPou2f/15dBUXPX98eAoWd YCH+6n048R2sTVA5odp7DPQIk9ENt+7NW23ekw089Zs9qawYA+X4iCC5qU/ZrOhzr95MNJ JXbhUbvjhgw3aEK5kdlFrDnX6zY2G//c6VnaPPSe0wb46oHn6H7twdXafXN/7eTFmUTYKj iRbzCHZZwHmzH21+zgIsOBmUt9olPIsRbGTPJ473Sh2JHGRWChRHQXLKxfAUjmM72sr2nK TnEm1NPX3kvvKjnvmQi29qxpH+KP0/l/KyQ+2dFpsQtVE85QqRNNzZkkjYkZwQ== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338224; a=rsa-sha256; cv=none; b=cDu2GJs5GOTuD76mPJ6uetySPL7obyave0SiuShI3PGB4cKlE+hQtCb87i4a5xBPqqwhoy1NZOcAOrDvuku2nfKFpvgBn3CsSXmkcJcfDMymTXeDhTMwqXzCtWHX16zclUf67VRlOfRX0LQ1CmU50JT33FO1xHLgJGkjTiX77MrUFmJZdPT27rgF/6FRnWiLuznLkoNGduFXGXEWS0Ojb8Rm7YQLbsuL3tGqU329Lu7+3hNol0Jt7TbJfsBQBozu+YKGxsrbPpR/vg60eXrR0eYO8lEZH0ioVg3ZNQCqwSm54pmeVo4ikwzdVYVJHOAYQTA+u47HSoVqTTkr8spK/A== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" A clock mux can be configured to select one of its 10 sources through the CM_CTL register. It also embeds yet another clock divider, composed of an integer part and a fractional part. The number of bits of each part is mux dependent. Tested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- hw/misc/bcm2835_cprman.c | 53 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index b22170f3bc..919a55aa23 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -229,19 +229,70 @@ static const TypeInfo cprman_pll_channel_info = { }; /* clock mux */ +static bool clock_mux_is_enabled(CprmanClockMuxState *mux) +{ + return FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, ENABLE); +} + static void clock_mux_update(CprmanClockMuxState *mux) { - clock_update(mux->out, 0); + uint64_t freq; + uint32_t div, src = FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, SRC); + bool enabled = clock_mux_is_enabled(mux); + + *mux->reg_ctl = FIELD_DP32(*mux->reg_ctl, CM_CLOCKx_CTL, BUSY, enabled); + + if (!enabled) { + clock_update(mux->out, 0); + return; + } + + freq = clock_get_hz(mux->srcs[src]); + + if (mux->int_bits == 0 && mux->frac_bits == 0) { + clock_update_hz(mux->out, freq); + return; + } + + /* + * The divider has an integer and a fractional part. The size of each part + * varies with the muxes (int_bits and frac_bits). Both parts are + * concatenated, with the integer part always starting at bit 12. + * + * 31 12 11 0 + * ------------------------------ + * CM_DIV | | int | frac | | + * ------------------------------ + * <-----> <------> + * int_bits frac_bits + */ + div = extract32(*mux->reg_div, + R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits, + mux->int_bits + mux->frac_bits); + + if (!div) { + clock_update(mux->out, 0); + return; + } + + freq = muldiv64(freq, 1 << mux->frac_bits, div); + + clock_update_hz(mux->out, freq); } static void clock_mux_src_update(void *opaque) { CprmanClockMuxState **backref = opaque; CprmanClockMuxState *s = *backref; + CprmanClockMuxSource src = backref - s->backref; + + if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) { + return; + } clock_mux_update(s); } static void clock_mux_init(Object *obj) From patchwork Sat Oct 10 13:57:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 271609 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CB872C433DF for ; Sat, 10 Oct 2020 14:08:18 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4D51022202 for ; Sat, 10 Oct 2020 14:08:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="CdYFPvUq" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4D51022202 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:56102 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFXl-00005T-Fb for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:08:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40766) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNO-0001yZ-9e; Sat, 10 Oct 2020 09:57:34 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43622) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNK-0004KE-P2; Sat, 10 Oct 2020 09:57:33 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id DC15EC6041E; Sat, 10 Oct 2020 13:57:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1khL5jQgl79Wz4Nvt9T2Nmb7REQ+9nMviU5HHyZMUgY=; b=CdYFPvUqnOQ3LC/lrJ62V9OmfeFrvBfhF34UCcfADeAwmsXybYYNlw3S78YbUm6OujIH88 /IFtncMowOM5Q91AY4Sp6nH0Quy5KMs3UMWW1+25jI3BwKz/8wZUmlCIrpiubMpgLkEO/K DeYeEbYQirtvaNC2AWR4GIlqj47kptx676jmcNmawTpI3Z8UtKZuKfje+CglI071n3ENQ5 N0bLaRg1W1gz1vYwmqkhK9sEaECzsV4xkIh8/FiB79D+CJ2ypUoycvV7sdjteWBPQtnBaI U3tX0/9EqCNM2BCaQqE2InCxmp+YCPJMy3MEi+dtYdNCPQwaWW7Z37ZS556suQ== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 12/15] hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer Date: Sat, 10 Oct 2020 15:57:56 +0200 Message-Id: <20201010135759.437903-13-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338224; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1khL5jQgl79Wz4Nvt9T2Nmb7REQ+9nMviU5HHyZMUgY=; b=YYo8T48iB8aYG2YSgPatcr4NsM8wFKS+yv9TDZ5ogwPenJLivEa5pwvNctPhfEs00czoJf 0va3egF8WSTZD6xQ21oJjeyJCVmdNsTGArhcLjgkmndEPZ+WfXvYymMjegxnKa8QCcqLsC 9S2HIIJQkZOFJVKfn6bOhEp4OGqWDp8BZ8Nfj0vJrtTPhDC/76ihUq2uwGQzNWN9p57Kva Ml31WMXaOOxdF53PJfXF9ZUqJViGKySss76gT4RKhDcVRIb1PazpH2ebHpMZOOj7d8vJ93 FqgufyAw7lLokYt/YM2P6i2bk0osp7tFYLBn/aP3C/Nj6GL8uQU58tHiXR1+HQ== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338224; a=rsa-sha256; cv=none; b=HlcPrta2QfgWpcPSIuOcGv3cJwYEOx9pCYO3bN6WYqlvIduLAkA3FPtk4uO+NhQ6KU+slsdJXCEEC+wNz9gInd51MH4WLp/TI0noMJzsbUNipfKyZf0ulwHzCj1QBqumxMWj6bVbzC/NyPAFc3GEftG0Q3vtuMx03MOcZqi/KgkzxA8Cs8Kmlweh1YKRnI/5JdQ45n8qD+PO3rBvafLCA/quw6LTlYvHWw2QNkX6pkg1VKD9E5HqKnDk3obk39lQsifcmf3cJ9ZiyaRNk1/Ss9Ma2ICwvy4LLwHK/r1AZ1E9PWcFF0rfnWDN8ndSVqz5OYlWJCp2RxOmLY14dTqZiw== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This simple mux sits between the PLL channels and the DSI0E and DSI0P clock muxes. This mux selects between PLLA-DSI0 and PLLD-DSI0 channel and outputs the selected signal to source number 4 of DSI0E/P clock muxes. It is controlled by the cm_dsi0hsck register. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/misc/bcm2835_cprman.h | 15 +++++ include/hw/misc/bcm2835_cprman_internals.h | 6 ++ hw/misc/bcm2835_cprman.c | 74 +++++++++++++++++++++- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index 0fc8f68845..3df4ceedd2 100644 --- a/include/hw/misc/bcm2835_cprman.h +++ b/include/hw/misc/bcm2835_cprman.h @@ -172,20 +172,35 @@ typedef struct CprmanClockMuxState { * source number. */ struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC]; } CprmanClockMuxState; +typedef struct CprmanDsi0HsckMuxState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + CprmanClockMux id; + + uint32_t *reg_cm; + + Clock *plla_in; + Clock *plld_in; + Clock *out; +} CprmanDsi0HsckMuxState; + struct BCM2835CprmanState { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ MemoryRegion iomem; CprmanPllState plls[CPRMAN_NUM_PLL]; CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL]; CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX]; + CprmanDsi0HsckMuxState dsi0hsck_mux; uint32_t regs[CPRMAN_NUM_REGS]; uint32_t xosc_freq; Clock *xosc; diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index 0305448bbc..a6e799075f 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -13,17 +13,20 @@ #include "hw/misc/bcm2835_cprman.h" #define TYPE_CPRMAN_PLL "bcm2835-cprman-pll" #define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel" #define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux" +#define TYPE_CPRMAN_DSI0HSCK_MUX "bcm2835-cprman-dsi0hsck-mux" DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL, TYPE_CPRMAN_PLL) DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL, TYPE_CPRMAN_PLL_CHANNEL) DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX, TYPE_CPRMAN_CLOCK_MUX) +DECLARE_INSTANCE_CHECKER(CprmanDsi0HsckMuxState, CPRMAN_DSI0HSCK_MUX, + TYPE_CPRMAN_DSI0HSCK_MUX) /* Register map */ /* PLLs */ REG32(CM_PLLA, 0x104) @@ -221,10 +224,13 @@ REG32(CM_LOCK, 0x114) FIELD(CM_LOCK, FLOCKD, 11, 1) FIELD(CM_LOCK, FLOCKC, 10, 1) FIELD(CM_LOCK, FLOCKB, 9, 1) FIELD(CM_LOCK, FLOCKA, 8, 1) +REG32(CM_DSI0HSCK, 0x120) + FIELD(CM_DSI0HSCK, SELPLLD, 0, 1) + /* * This field is common to all registers. Each register write value must match * the CPRMAN_PASSWORD magic value in its 8 MSB. */ FIELD(CPRMAN, PASSWORD, 24, 8) diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 919a55aa23..7a7401963d 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -337,10 +337,62 @@ static const TypeInfo cprman_clock_mux_info = { .class_init = clock_mux_class_init, .instance_init = clock_mux_init, }; +/* DSI0HSCK mux */ + +static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s) +{ + bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD); + Clock *src = src_is_plld ? s->plld_in : s->plla_in; + + clock_update(s->out, clock_get(src)); +} + +static void dsi0hsck_mux_in_update(void *opaque) +{ + dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque)); +} + +static void dsi0hsck_mux_init(Object *obj) +{ + CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj); + DeviceState *dev = DEVICE(obj); + + s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s); + s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s); + s->out = qdev_init_clock_out(DEVICE(s), "out"); +} + +static const VMStateDescription dsi0hsck_mux_vmstate = { + .name = TYPE_CPRMAN_DSI0HSCK_MUX, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState), + VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState), + VMSTATE_END_OF_LIST() + } +}; + +static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &dsi0hsck_mux_vmstate; +} + +static const TypeInfo cprman_dsi0hsck_mux_info = { + .name = TYPE_CPRMAN_DSI0HSCK_MUX, + .parent = TYPE_DEVICE, + .instance_size = sizeof(CprmanDsi0HsckMuxState), + .class_init = dsi0hsck_mux_class_init, + .instance_init = dsi0hsck_mux_init, +}; + + /* CPRMAN "top level" model */ static uint32_t get_cm_lock(const BCM2835CprmanState *s) { static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = { @@ -499,10 +551,14 @@ static void cprman_write(void *opaque, hwaddr offset, case R_CM_SDCCTL ... R_CM_ARMCTL: case R_CM_AVEOCTL ... R_CM_EMMCDIV: case R_CM_EMMC2CTL ... R_CM_EMMC2DIV: update_mux_from_cm(s, idx); break; + + case R_CM_DSI0HSCK: + dsi0hsck_mux_update(&s->dsi0hsck_mux); + break; } } #undef CASE_PLL_A2W_REGS @@ -538,10 +594,12 @@ static void cprman_reset(DeviceState *dev) for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { device_cold_reset(DEVICE(&s->channels[i])); } + device_cold_reset(DEVICE(&s->dsi0hsck_mux)); + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { device_cold_reset(DEVICE(&s->clock_muxes[i])); } clock_update_hz(s->xosc, s->xosc_freq); @@ -563,10 +621,14 @@ static void cprman_init(Object *obj) &s->channels[i], TYPE_CPRMAN_PLL_CHANNEL); set_pll_channel_init_info(s, &s->channels[i], i); } + object_initialize_child(obj, "dsi0hsck-mux", + &s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX); + s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK]; + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { char *alias; object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name, &s->clock_muxes[i], @@ -610,11 +672,11 @@ static void connect_mux_sources(BCM2835CprmanState *s, Clock *src; if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) { src = s->gnd; } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) { - src = s->gnd; /* TODO */ + src = s->dsi0hsck_mux.out; } else if (i < CPRMAN_CLOCK_SRC_PLLA) { src = CLK_SRC_MAPPING[i]; } else { src = s->channels[mapping].out; } @@ -648,10 +710,19 @@ static void cprman_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(channel), NULL, errp)) { return; } } + clock_set_source(s->dsi0hsck_mux.plla_in, + s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out); + clock_set_source(s->dsi0hsck_mux.plld_in, + s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out); + + if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) { + return; + } + for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { CprmanClockMuxState *clock_mux = &s->clock_muxes[i]; connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping); @@ -698,8 +769,9 @@ static void cprman_register_types(void) { type_register_static(&cprman_info); type_register_static(&cprman_pll_info); type_register_static(&cprman_pll_channel_info); type_register_static(&cprman_clock_mux_info); + type_register_static(&cprman_dsi0hsck_mux_info); } type_init(cprman_register_types); From patchwork Sat Oct 10 13:57:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303201 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 76986C433E7 for ; Sat, 10 Oct 2020 14:08:58 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 049F622202 for ; Sat, 10 Oct 2020 14:08:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="SRa/8594" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 049F622202 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:57562 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFYP-0000j4-5u for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:08:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40774) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNO-0001zW-JH; Sat, 10 Oct 2020 09:57:34 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43624) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNL-0004KL-0d; Sat, 10 Oct 2020 09:57:34 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 00FDFC6041F; Sat, 10 Oct 2020 13:57:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338225; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OIfAcjkUtNmViKh9QrQYDJov9LZXlGI0tmDZqkLw5dQ=; b=SRa/8594xRbRRw/5GougWN3IwcHCOuSQsNcNE+VGe0/xqYis2MQwjSkn62lNiFY/+xYFLg 8Gc5CFE4bKsNO/3WUGbrk9BQF9H7fYBu63C9gWF2bYMJmk0m0lMnVhVVKFH5rAOZWdgIRd 7WvSQxfUW78M0tciNdjznb9RId37WI01HIhd9QSGFe8KhEno58hB2tllB5Sj66X/eHr50p G+qMI11mVS5I741jiwUobMM+1DCkEfxRdEnvr3wyJaY4hS1lXHZIjXXY/x4A22SRo1gI5L 9kVaXUfwh4ekRNGwPIPeawKC/a8EkLEH6qVSpm+m+5VqtXOtJWRQG+ZMp3+8iw== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 13/15] hw/misc/bcm2835_cprman: add sane reset values to the registers Date: Sat, 10 Oct 2020 15:57:57 +0200 Message-Id: <20201010135759.437903-14-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338225; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OIfAcjkUtNmViKh9QrQYDJov9LZXlGI0tmDZqkLw5dQ=; b=Qm+qQt9dv57VZHjz8IGQguDSUKeXieuRDt2SvSP+CjV0K7kOcezJbpztERfm3Mbc2GAvXb jUfZ6OmDlWmq6pAA83ICsf2+HyhX0sOxIPPkw+vTA2Pt/IoD5rY+TmU73RDGEcLhucURaa IL/pfiBTUqUNXDJWdbo1SSUzlsV/M6iDh5zR0xDHDg62lrtgA+z+QQWd9/7b1XL1zaMjkS 08WYi1YG4E/P/vr4/fI09KT3ZARHg9Aj6sq+skaK0h4wMMQhiTz8cCOcW1onNfXNbMZVhn Z8zbgC/UK7UWzNcT6E6pzYAFxIM3eEsMkFqkPP69zkOiADKif1ebxfjspbb9hA== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338225; a=rsa-sha256; cv=none; b=QEocohdhXl0KyejpfnIFXZhfQhfuQRVoGYBsnPAqck2NNGm5nRUo4/xU307uWB9I/KX9gaoeHjAVm5Kv+keNN1p/G99Dm9Wm4ByPnFjC9YaszNv++XTZ8w+XpU4dNRWa8/eOxhhfl/kyNQ1Ztu0qlYjsG6fKJ2P2uctH5zKB7U4FYxf/3ZPiLTii0Bg50+l44oIIQd0NhZXBwxLJKVp88opoBZ+JU9D0jWUoaKa9G5s8xQ8IvP9Ud1lMs4cYAALsf6w/GxnbwW+WGfqG8TLdxlFlDIb5xKCDRAOeMlcDUBw0zu3BDm0EeBQT9fnA+8dyuFJNY5BJZuidf8ecgsWpKg== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Those reset values have been extracted from a Raspberry Pi 3 model B v1.2, using the 2020-08-20 version of raspios. The dump was done using the debugfs interface of the CPRMAN driver in Linux (under '/sys/kernel/debug/clk'). Each exposed clock tree stage (PLLs, channels and muxes) can be observed by reading the 'regdump' file (e.g. 'plla/regdump'). Those values are set by the Raspberry Pi firmware at boot time (Linux expects them to be set when it boots up). Some stages are not exposed by the Linux driver (e.g. the PLL B). For those, the reset values are unknown and left to 0 which implies a disabled output. Once booted in QEMU, the final clock tree is very similar to the one visible on real hardware. The differences come from some unimplemented devices for which the driver simply disable the corresponding clock. Tested-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/misc/bcm2835_cprman_internals.h | 269 +++++++++++++++++++++ hw/misc/bcm2835_cprman.c | 31 +++ 2 files changed, 300 insertions(+) diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index a6e799075f..339759b307 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -745,6 +745,275 @@ static inline void set_clock_mux_init_info(BCM2835CprmanState *s, mux->reg_div = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset + 1]; mux->int_bits = CLOCK_MUX_INIT_INFO[id].int_bits; mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits; } + +/* + * Object reset info + * Those values have been dumped from a Raspberry Pi 3 Model B v1.2 using the + * clk debugfs interface in Linux. + */ +typedef struct PLLResetInfo { + uint32_t cm; + uint32_t a2w_ctrl; + uint32_t a2w_ana[4]; + uint32_t a2w_frac; +} PLLResetInfo; + +static const PLLResetInfo PLL_RESET_INFO[] = { + [CPRMAN_PLLA] = { + .cm = 0x0000008a, + .a2w_ctrl = 0x0002103a, + .a2w_frac = 0x00098000, + .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 } + }, + + [CPRMAN_PLLC] = { + .cm = 0x00000228, + .a2w_ctrl = 0x0002103e, + .a2w_frac = 0x00080000, + .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 } + }, + + [CPRMAN_PLLD] = { + .cm = 0x0000020a, + .a2w_ctrl = 0x00021034, + .a2w_frac = 0x00015556, + .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 } + }, + + [CPRMAN_PLLH] = { + .cm = 0x00000000, + .a2w_ctrl = 0x0002102d, + .a2w_frac = 0x00000000, + .a2w_ana = { 0x00900000, 0x0000000c, 0x00000000, 0x00000000 } + }, + + [CPRMAN_PLLB] = { + /* unknown */ + .cm = 0x00000000, + .a2w_ctrl = 0x00000000, + .a2w_frac = 0x00000000, + .a2w_ana = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 } + } +}; + +typedef struct PLLChannelResetInfo { + /* + * Even though a PLL channel has a CM register, it shares it with its + * parent PLL. The parent already takes care of the reset value. + */ + uint32_t a2w_ctrl; +} PLLChannelResetInfo; + +static const PLLChannelResetInfo PLL_CHANNEL_RESET_INFO[] = { + [CPRMAN_PLLA_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 }, + [CPRMAN_PLLA_CHANNEL_CORE] = { .a2w_ctrl = 0x00000003 }, + [CPRMAN_PLLA_CHANNEL_PER] = { .a2w_ctrl = 0x00000000 }, /* unknown */ + [CPRMAN_PLLA_CHANNEL_CCP2] = { .a2w_ctrl = 0x00000100 }, + + [CPRMAN_PLLC_CHANNEL_CORE2] = { .a2w_ctrl = 0x00000100 }, + [CPRMAN_PLLC_CHANNEL_CORE1] = { .a2w_ctrl = 0x00000100 }, + [CPRMAN_PLLC_CHANNEL_PER] = { .a2w_ctrl = 0x00000002 }, + [CPRMAN_PLLC_CHANNEL_CORE0] = { .a2w_ctrl = 0x00000002 }, + + [CPRMAN_PLLD_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 }, + [CPRMAN_PLLD_CHANNEL_CORE] = { .a2w_ctrl = 0x00000004 }, + [CPRMAN_PLLD_CHANNEL_PER] = { .a2w_ctrl = 0x00000004 }, + [CPRMAN_PLLD_CHANNEL_DSI1] = { .a2w_ctrl = 0x00000100 }, + + [CPRMAN_PLLH_CHANNEL_AUX] = { .a2w_ctrl = 0x00000004 }, + [CPRMAN_PLLH_CHANNEL_RCAL] = { .a2w_ctrl = 0x00000000 }, + [CPRMAN_PLLH_CHANNEL_PIX] = { .a2w_ctrl = 0x00000000 }, + + [CPRMAN_PLLB_CHANNEL_ARM] = { .a2w_ctrl = 0x00000000 }, /* unknown */ +}; + +typedef struct ClockMuxResetInfo { + uint32_t cm_ctl; + uint32_t cm_div; +} ClockMuxResetInfo; + +static const ClockMuxResetInfo CLOCK_MUX_RESET_INFO[] = { + [CPRMAN_CLOCK_GNRIC] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_VPU] = { + .cm_ctl = 0x00000245, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_SYS] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_PERIA] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_PERII] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_H264] = { + .cm_ctl = 0x00000244, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_ISP] = { + .cm_ctl = 0x00000244, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_V3D] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_CAM0] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_CAM1] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_CCP2] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_DSI0E] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_DSI0P] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_DPI] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_GP0] = { + .cm_ctl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_GP1] = { + .cm_ctl = 0x00000096, + .cm_div = 0x00014000, + }, + + [CPRMAN_CLOCK_GP2] = { + .cm_ctl = 0x00000291, + .cm_div = 0x00249f00, + }, + + [CPRMAN_CLOCK_HSM] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_OTP] = { + .cm_ctl = 0x00000091, + .cm_div = 0x00004000, + }, + + [CPRMAN_CLOCK_PCM] = { + .cm_ctl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_PWM] = { + .cm_ctl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_SLIM] = { + .cm_ctl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_SMI] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_TEC] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_TD0] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_TD1] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_TSENS] = { + .cm_ctl = 0x00000091, + .cm_div = 0x0000a000, + }, + + [CPRMAN_CLOCK_TIMER] = { + .cm_ctl = 0x00000291, + .cm_div = 0x00013333, + }, + + [CPRMAN_CLOCK_UART] = { + .cm_ctl = 0x00000296, + .cm_div = 0x0000a6ab, + }, + + [CPRMAN_CLOCK_VEC] = { + .cm_ctl = 0x00000097, + .cm_div = 0x00002000, + }, + + [CPRMAN_CLOCK_PULSE] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_SDC] = { + .cm_ctl = 0x00004006, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_ARM] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_AVEO] = { + .cm_ctl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_EMMC] = { + .cm_ctl = 0x00000295, + .cm_div = 0x00006000, + }, + + [CPRMAN_CLOCK_EMMC2] = { + .cm_ctl = 0, /* unknown */ + .cm_div = 0 + }, +}; + #endif diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 7a7401963d..7e415a017c 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -51,10 +51,21 @@ #include "hw/misc/bcm2835_cprman_internals.h" #include "trace.h" /* PLL */ +static void pll_reset(DeviceState *dev) +{ + CprmanPllState *s = CPRMAN_PLL(dev); + const PLLResetInfo *info = &PLL_RESET_INFO[s->id]; + + *s->reg_cm = info->cm; + *s->reg_a2w_ctrl = info->a2w_ctrl; + memcpy(s->reg_a2w_ana, info->a2w_ana, sizeof(info->a2w_ana)); + *s->reg_a2w_frac = info->a2w_frac; +} + static bool pll_is_locked(const CprmanPllState *pll) { return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN) && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST); } @@ -121,10 +132,11 @@ static const VMStateDescription pll_vmstate = { static void pll_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = pll_reset; dc->vmsd = &pll_vmstate; } static const TypeInfo cprman_pll_info = { .name = TYPE_CPRMAN_PLL, @@ -135,10 +147,18 @@ static const TypeInfo cprman_pll_info = { }; /* PLL channel */ +static void pll_channel_reset(DeviceState *dev) +{ + CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(dev); + const PLLChannelResetInfo *info = &PLL_CHANNEL_RESET_INFO[s->id]; + + *s->reg_a2w_ctrl = info->a2w_ctrl; +} + static bool pll_channel_is_enabled(CprmanPllChannelState *channel) { /* * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does * not set it when enabling the channel, but does clear it when disabling @@ -215,10 +235,11 @@ static const VMStateDescription pll_channel_vmstate = { static void pll_channel_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = pll_channel_reset; dc->vmsd = &pll_channel_vmstate; } static const TypeInfo cprman_pll_channel_info = { .name = TYPE_CPRMAN_PLL_CHANNEL, @@ -293,10 +314,19 @@ static void clock_mux_src_update(void *opaque) } clock_mux_update(s); } +static void clock_mux_reset(DeviceState *dev) +{ + CprmanClockMuxState *clock = CPRMAN_CLOCK_MUX(dev); + const ClockMuxResetInfo *info = &CLOCK_MUX_RESET_INFO[clock->id]; + + *clock->reg_ctl = info->cm_ctl; + *clock->reg_div = info->cm_div; +} + static void clock_mux_init(Object *obj) { CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj); size_t i; @@ -325,10 +355,11 @@ static const VMStateDescription clock_mux_vmstate = { static void clock_mux_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = clock_mux_reset; dc->vmsd = &clock_mux_vmstate; } static const TypeInfo cprman_clock_mux_info = { .name = TYPE_CPRMAN_CLOCK_MUX, From patchwork Sat Oct 10 13:57:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 303203 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A3841C433DF for ; Sat, 10 Oct 2020 14:05:02 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2A60E22283 for ; Sat, 10 Oct 2020 14:05:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="VyKGCN5Q" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2A60E22283 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:44284 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFUb-0003aF-83 for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:05:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40734) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNN-0001vz-8T; Sat, 10 Oct 2020 09:57:33 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43626) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNL-0004KK-2U; Sat, 10 Oct 2020 09:57:32 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 271ADC60430; Sat, 10 Oct 2020 13:57:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338225; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MO0Muj7yuPd6SWwH9hfY/l2s1zABrTHCErTOwR/d+QM=; b=VyKGCN5QIjRI7lfg0PhLOl/QWGjzATW1evA45KI0zttBsY+wX8+tVXB6HUw7eGHA+ezxJu LRASA7I4JrKTk01ee8UvEI3X8ZkbojiWGIEKDJOgtc8w0meN1t1npHzORFHdM6WQBKaKGk 1zwdTZYs0dZRwXj7G+DTqUTPFe4j1wCgNjJL54oHO5LnOMGX5+bnIra4TxzHad6p2o/hnR nZzDfWx7WBGHS9gzPgH2IgXfhj88ewRVTV0VfmigESOmrbq/yQX4EtEkmTb+LrvLLIeGtD 96Ud+QVb01EUE58ZAwYGtrksGHbK4Gu7OSeNedgdoGiLP902MdBvSgYIRaylxQ== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 14/15] hw/char/pl011: add a clock input Date: Sat, 10 Oct 2020 15:57:58 +0200 Message-Id: <20201010135759.437903-15-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338225; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MO0Muj7yuPd6SWwH9hfY/l2s1zABrTHCErTOwR/d+QM=; b=c4Q/LOVSRYkWzOjsKAksjneVu7kCNqHzBadCdMH4ni7Q5a2mRc1SFB67weVaEGOsAzVtNm c2elRaLO97F3FpE9atIdMQKcqKcXHUiRLjCdhSW5S8qPNTARMIwF+f98ZV7OuJ9MBshC2X Xcp3uYr/BEALZwFomQ6GL248HFJJ2MgJVDOcMTKSn6/T49KGJzd9ky+trEANOYhZCTbIGY nt9NDl5gs/ChEvjKcXJxTgE++S4BA6B5h/AY9x492Z86lfHzGxTcqYmApeqkr/nsWAcoiD QQRDDgKY5Poi5kszAX6Vq359QuI0QX2yBI22SFVinZT96mwNteMUNdLGhiNO3A== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338225; a=rsa-sha256; cv=none; b=RsdEL03PPkV8VqFq0egcQRfhRUVbItmv/zDH1ZdZL8MzDhx1zNCdgV3ZnxSne2GKtHJVsNH0YbH15QyM7EP6YSbEAwSWpknynKeIqXCRJUxvgnogYOBA8t94xdHGvteVtfZcjB21s50wOqkQ8WpZDRijTIGeEgeYUPfwg+gIkINJYxCvQufUEhBz9/qFUEGpePWd2GUVPKY1psBurGL5Q9lY906HPnjq2/zvu1fSc70UyPf/XzTd6x0lr4fF8bqkdeukWrFqRGkEcPcE53P+03sA7Y+9qGDJ2PIjSqIRWu8m7hQtqH5xRyTci1OV/iS4GOMRuK9Mm/kshPdGmnBv2Q== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Add a clock input to the PL011 UART so we can compute the current baud rate and trace it. This is intended for developers who wish to use QEMU to e.g. debug their firmware or to figure out the baud rate configured by an unknown/closed source binary. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- include/hw/char/pl011.h | 1 + hw/char/pl011.c | 45 +++++++++++++++++++++++++++++++++++++++++ hw/char/trace-events | 1 + 3 files changed, 47 insertions(+) diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h index a91ea50e11..33e5e5317b 100644 --- a/include/hw/char/pl011.h +++ b/include/hw/char/pl011.h @@ -47,10 +47,11 @@ struct PL011State { int read_pos; int read_count; int read_trigger; CharBackend chr; qemu_irq irq[6]; + Clock *clk; const unsigned char *id; }; static inline DeviceState *pl011_create(hwaddr addr, qemu_irq irq, diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 13e784f9d9..ede16c781c 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -20,10 +20,11 @@ #include "qemu/osdep.h" #include "hw/char/pl011.h" #include "hw/irq.h" #include "hw/sysbus.h" +#include "hw/qdev-clock.h" #include "migration/vmstate.h" #include "chardev/char-fe.h" #include "qemu/log.h" #include "qemu/module.h" #include "trace.h" @@ -167,10 +168,29 @@ static void pl011_set_read_trigger(PL011State *s) else #endif s->read_trigger = 1; } +static unsigned int pl011_get_baudrate(const PL011State *s) +{ + uint64_t clk; + + if (s->fbrd == 0) { + return 0; + } + + clk = clock_get_hz(s->clk); + return (clk / ((s->ibrd << 6) + s->fbrd)) << 2; +} + +static void pl011_trace_baudrate_change(const PL011State *s) +{ + trace_pl011_baudrate_change(pl011_get_baudrate(s), + clock_get_hz(s->clk), + s->ibrd, s->fbrd); +} + static void pl011_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PL011State *s = (PL011State *)opaque; unsigned char ch; @@ -196,13 +216,15 @@ static void pl011_write(void *opaque, hwaddr offset, case 8: /* UARTUARTILPR */ s->ilpr = value; break; case 9: /* UARTIBRD */ s->ibrd = value; + pl011_trace_baudrate_change(s); break; case 10: /* UARTFBRD */ s->fbrd = value; + pl011_trace_baudrate_change(s); break; case 11: /* UARTLCR_H */ /* Reset the FIFO state on FIFO enable or disable */ if ((s->lcr ^ value) & 0x10) { s->read_count = 0; @@ -284,16 +306,33 @@ static void pl011_event(void *opaque, QEMUChrEvent event) { if (event == CHR_EVENT_BREAK) pl011_put_fifo(opaque, 0x400); } +static void pl011_clock_update(void *opaque) +{ + PL011State *s = PL011(opaque); + + pl011_trace_baudrate_change(s); +} + static const MemoryRegionOps pl011_ops = { .read = pl011_read, .write = pl011_write, .endianness = DEVICE_NATIVE_ENDIAN, }; +static const VMStateDescription vmstate_pl011_clock = { + .name = "pl011/clock", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_CLOCK(clk, PL011State), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_pl011 = { .name = "pl011", .version_id = 2, .minimum_version_id = 2, .fields = (VMStateField[]) { @@ -312,10 +351,14 @@ static const VMStateDescription vmstate_pl011 = { VMSTATE_UINT32(ifl, PL011State), VMSTATE_INT32(read_pos, PL011State), VMSTATE_INT32(read_count, PL011State), VMSTATE_INT32(read_trigger, PL011State), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_pl011_clock, + NULL } }; static Property pl011_properties[] = { DEFINE_PROP_CHR("chardev", PL011State, chr), @@ -332,10 +375,12 @@ static void pl011_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); for (i = 0; i < ARRAY_SIZE(s->irq); i++) { sysbus_init_irq(sbd, &s->irq[i]); } + s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s); + s->read_trigger = 1; s->ifl = 0x12; s->cr = 0x300; s->flags = 0x90; diff --git a/hw/char/trace-events b/hw/char/trace-events index 609df10fed..81026f6612 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -63,10 +63,11 @@ pl011_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" pl011_read_fifo(int read_count) "FIFO read, read_count now %d" pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d" pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d" pl011_put_fifo_full(void) "FIFO now full, RXFF set" +pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")" # cmsdk-apb-uart.c cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_uart_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_uart_reset(void) "CMSDK APB UART: reset" From patchwork Sat Oct 10 13:57:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 271608 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C0847C433DF for ; Sat, 10 Oct 2020 14:10:21 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4124722260 for ; Sat, 10 Oct 2020 14:10:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=lmichel.fr header.i=@lmichel.fr header.b="Sm5K/mex" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4124722260 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=lmichel.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:32898 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRFZk-0002FA-EN for qemu-devel@archiver.kernel.org; Sat, 10 Oct 2020 10:10:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40780) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNP-00020x-2v; Sat, 10 Oct 2020 09:57:35 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:43628) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRFNN-0004L5-CI; Sat, 10 Oct 2020 09:57:34 -0400 Received: from sekoia-pc.home.lmichel.fr (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 4AA9DC60447; Sat, 10 Oct 2020 13:57:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338225; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DcI48tCMxlodkMmJI8399CoSnp6maJFtviK5ZRNd7kI=; b=Sm5K/mexEYr8xWulPXGUjMrLUxAftP4ifXvOWHit+d0b11JHn/Doivgr2pWKfBXLFctL79 OhCE21oOVwfrwi9N4+AvpxUNO8UOTESinpauW7542kRTIqcOiojUPP6kOiq8crGRNk9ctk k9PZXQc7JbciVUhQejtrAb9TnulwUQPegxYyo7k2W2dRGpPODBFwYdd7Wk0Mwr0MsZJHwr 8lBppzjT3vJwEGTCZjiiUNELIIZuLX6gmMsg9cDHxKAg6oFt/ZyN9u9+/gH9oxC1CQVaYb CBC+2wsD0IMkbk7/vBvp4FJjJkwTDus2rn3+EPXXa5279dBg0KCnb+1mK8DvKg== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH v3 15/15] hw/arm/bcm2835_peripherals: connect the UART clock Date: Sat, 10 Oct 2020 15:57:59 +0200 Message-Id: <20201010135759.437903-16-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201010135759.437903-1-luc@lmichel.fr> References: <20201010135759.437903-1-luc@lmichel.fr> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1602338225; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DcI48tCMxlodkMmJI8399CoSnp6maJFtviK5ZRNd7kI=; b=fe72YsBJe7iz6xeZqCwZzrAmfB8JAEM+dOskjC9mTJiWs4yXe5BCTlpo+hJrA1Ah5ZAo+T 867DPsT9Qi+TZUhPH17SeNbgLVs2BXJkZpTFRk2DxcAH6pkpZ8+THAUOGbKuu7ET0OIZE+ u5PbqkEAl7WG4CDIq0gdvVarB9DEgUtRBAHzdkwa+F32rXJ6mQ/3frC972lohOvSZRhvR1 8knOEXwjr5WxQede0zQvJZRW7L48/UiXCpnM09QaX4u5tBoPxPisUKwUWF2lqSTjrhAuLi tzTkPrC/uCPsOsNIfIwnQxNQLBglgRxXLt9CutDljFRBvYDZZoVLkWub+AnKkw== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1602338225; a=rsa-sha256; cv=none; b=UM0+mCKZAd5Z3kNP6q/6exY2SanAwGVOP/X+C2WGBpnWL2eahlx6CuWCArQTYGO9Z1Dt+9XIKeNPHjDMZbJHKGLgWoOPYueOm5eZDVohfQ671+IVcAkl5qe3ce+062RA1GqVZJfHRte72fGZyIW5CHX9AWzanLY4JFt0NuN5jyMZIg1Po8jvI9WuWnKt7WoOCHnh+oAG8twobddC23tO0IQzGZ72rJMSAXkaEJkvZ69oiXdvDpVng2I3d1pKWVxitesPxY63juHlsBoFKCugVbreE2jlDYGV4cwIPl6DLlHRA8J6VCxOQgWzrp9w+2OydrZT6IzgcdMImqutJKSb4A== ARC-Authentication-Results: i=1; pharaoh.lmichel.fr Received-SPF: pass client-ip=149.202.28.74; envelope-from=luc@lmichel.fr; helo=pharaoh.lmichel.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/10 07:32:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] 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, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann , Paul Zimmerman , Niek Linnenbank , qemu-arm@nongnu.org, Havard Skinnemoen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Connect the 'uart-out' clock from the CPRMAN to the PL011 instance. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Luc Michel --- hw/arm/bcm2835_peripherals.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 9d6190042d..d8f28b1ae2 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -167,10 +167,12 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->cprman), errp)) { return; } memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0)); + qdev_connect_clock_in(DEVICE(&s->uart0), "clk", + qdev_get_clock_out(DEVICE(&s->cprman), "uart-out")); memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0)); sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));