From patchwork Fri Sep 25 10:17:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304439 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 7AB8AC4363D for ; Fri, 25 Sep 2020 10:19:19 +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 F088921741 for ; Fri, 25 Sep 2020 10:19: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="jG7Mlc5B" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F088921741 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]:46850 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkow-0002nu-0c for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:19:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42656) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknD-000131-SW; Fri, 25 Sep 2020 06:17:31 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58110) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLkn8-0007QI-Bb; Fri, 25 Sep 2020 06:17:31 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 00207C60F18; Fri, 25 Sep 2020 10:17:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eHG3gOOfzWKUSsScEIEjr33P+R1FlB8vtIzUKO1MkuU=; b=jG7Mlc5BbIrGtqCQe2bSsyUPLWmzT8fZ2eFENXB3MSzQuOSNzfP8r9jXebL2e2R+nC4znA IIDU3IH90XvoIFJtY2EU5CU3B9V+pi9JWqkeiPoti3U0A2rJCsIsPlVUGPhw6FBNay8y9m D6jZRUVAfWK4JxUi3cV1FiX6hwAEQ2JYVQvL106ybXOo5yAbmOijjNZnA5xRfcv8+wugGX aQ29yn/ojH8QY2ZaPrWR8Lld1s2PwSlvpzlxK11zc3+ERbl/D7vrjSDEuZe9+WSzmxvNuZ n2ilotIRXKhc/TK3Ebch/qblCPZo1YTszDNg0/lV+KKHYGsVwWnsOOTFq74vaQ== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 01/14] hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro Date: Fri, 25 Sep 2020 12:17:18 +0200 Message-Id: <20200925101731.2159827-2-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eHG3gOOfzWKUSsScEIEjr33P+R1FlB8vtIzUKO1MkuU=; b=ZDEbLfzepCVtKAYPvw/E5Wd/Dfqo+sfmNjXfjWnRjQUbtrUBn4a5ISHCf+3kE3GT19/sNF R6Tufv32GN5BXpwEO1fIdchuYsyzTBwH2eglrEkCcwevgB5UoNB7C6kpb8aADgSay1kmpP i9P44oayX1yEDUCLAKO6PKhYT3B7uFJbcxEGXuz5kkzJPPxp9zKHsWHpSjmwnK0UU869jF HGmC39sETRAGEPPlcec7D47K5DIslnGa9ZzidmFT9ISQplZ54UwN5CHHIBJkr+9rAzBSB+ MVK7uPeGTlXd5+Vl2ZZvttHcYFYOGiLMGuC+T5PMGxLKJTk+I/fDzJGfIo7eow== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=FJmGm+h++qPtwsov66hcRhRWgMNyEIYmlcTupRvfNvvSUxKu3vjMIxhPuuCJQgJbrfrgujKXP7JCHaah2xg2FyPUz0plkq5Ba6CYppzvsBP0o0d+OMfebOGDr9Rfck2rAreG/Jmj/aDUG+SOaQOytQsWpLk9DNTebt5OWHRak7kXjWZ6ocpnqQa1HFICvPlssPcTa2+x4lBHEusHJJTHkm2HWtogEYfYdRvwCnTAEvsbQiksZxPyBknzQI9dU+V8zmGeofQOWhBaHNWu9LP97YVACcE0rn0OqQoQmj98xUBvfk8nWGRp/UVKmBJEDTWNilf2y39Pcky2gpA24AYg4g== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Damien Hedde --- 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 Fri Sep 25 10:17:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304437 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 C3C73C4363D for ; Fri, 25 Sep 2020 10:21:05 +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 3EDC521D91 for ; Fri, 25 Sep 2020 10:21:05 +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="cJyQHSPw" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3EDC521D91 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]:54300 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkqe-00061k-7o for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:21:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42674) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknF-00014J-2A; Fri, 25 Sep 2020 06:17:36 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58106) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLkn8-0007QK-BA; Fri, 25 Sep 2020 06:17:32 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 073DDC60F1A; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=P5QEx3f68QGQra+kkPmQWR7B9ok9n9lJElCkekR6j6I=; b=cJyQHSPwYc0jPIEc5WYgPEdghMrGnoHcDzlKGtijwg8U2m8ra0U+B2iEjGexwPAmrGmEOT 6wdx0Qt32iC0ZKmRjc+tHhp7scWTEVGE+M8d/DREubzg/SGtzhdvWKFP1pN8uvl57eoX41 Bie68X/6kmcmbw+cLAgcjBEvyng1f9oklGUPiHH9TGISz+IDnQlBz53sz140aGppQoZopq XGXCYWksy4BlZwbrRgS71+7FotIX1E6VsE0400+48W33ep911FdYzeKRXRwn8qoq1wpFko Ho4QOVEIfBU8rPMpWE9FtM7RNSkUzYXn77cWmrAF6+BEdNH+DuM6d38aZ7SQHg== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 02/14] hw/core/clock: trace clock values in Hz instead of ns Date: Fri, 25 Sep 2020 12:17:19 +0200 Message-Id: <20200925101731.2159827-3-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=P5QEx3f68QGQra+kkPmQWR7B9ok9n9lJElCkekR6j6I=; b=f12niBetxYie6Uj4j014WsbRL0aGVpQJS53vKG8obFag71VTm89vjxK5HIYif0RjjKQimI caXeKnaV1Tqv2XgeFT9XU79NJ3R1EyhQFV23VR99bzfrGrhSepGDysL1RF4JMsK5HpD37F GNHMx+fs8Lw+phNO1lROB7+KlHUzJs8n/OqR3+I4P/i0Pg9+8vd8UH8coVF/JZlycg1xGt LURn2PKMMEDFbFSAylV/1vkaglV7zWNxRgrB1xXlj9D4wXSAhJ11OC6aqHgQG91y9VWe1r RgRuPc2tfiEz9pe0klesELtazt2XY1hg+usRe9ykTzFbNBgbqokWX5UTUnBNGw== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=CWzyzcThJ1xsiy8bC89xELDhW5e4djNdwcPfJVZmO4/MjJKg7esbnVLYRvpt3ToM3gJXFhR1J5krgpchxIRmmyDg+32xJwmH1SB/2ef6R2OhIJHgOE8DEl/pTSm9xCfLW+DJrgy5QHREUfrVAlqSTMlHgUwz1AThua8rr45ULsYj8QCSjeQBGvHb1sTsZLU7NnXQ5P2xle5VnVqHjGd1j2mvvDHilPr+AfmGjLZBsHJH6vB6LHk1sIrU3ae9FGmiUFinodH5wBZ1c3xkjWkb78i9TPMr+BNrKvZFjyinQHzCA6OhVHkP8BdZsCctGV+6zz2tpxMog5+y+sgFrOIg6g== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org 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. Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Damien Hedde --- 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..6f96d8bfd0 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 Fri Sep 25 10:17:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304435 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 18126C4727F for ; Fri, 25 Sep 2020 10:23: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 9A9BC21D91 for ; Fri, 25 Sep 2020 10:23: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="Di5T9gsY" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9A9BC21D91 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]:60662 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLksr-0000JQ-Mx for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:23:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42710) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknK-00017P-3a; Fri, 25 Sep 2020 06:17:38 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58102) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLkn8-0007QM-CO; Fri, 25 Sep 2020 06:17:37 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 16C69C60F1B; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/tKa1P2RI8QqeDivN4AwKZq089IN8gBMXYs/CxNR70A=; b=Di5T9gsYyNKiIQa1A2BerU2u5MUBsMgWmxBBGdSIo+0W7JCnxq+Nl+UlmyVghd/xiA4ze7 h7CwGbgYBW9KfeqfRKRPhiSmMMVO9LLXynqEOj0eBwLJ8GUC04C0I6oWdELgGPfutjKoQi jVElSY82BxiBBfYdLwZp0DHNCq/E/SqaprgVVRZmmnwDt6HDUXVoGpnY/FPJX8RuywHzgC 4y/PcwJXb8Pagkv1JbCQkgwpOT9ZCMHAJp1pxPRuDXF82MMF/o0xd1M0WZ6gyCpVc246uF SDwUuDraUWeOJ1M73XIswaJ+OUSsDhI+J03neuXa2ei3z3Dp6jXS3LVdbC2fXQ== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 03/14] hw/arm/raspi: fix cprman base address Date: Fri, 25 Sep 2020 12:17:20 +0200 Message-Id: <20200925101731.2159827-4-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/tKa1P2RI8QqeDivN4AwKZq089IN8gBMXYs/CxNR70A=; b=b+YFla3H32U0KcBLxS1Kwb+jVwYfCEfZYn04ZWOGWCoVYteklzMcrDn5RQvifuIg+Q1DN/ 75qI1zKGtmwDxV8+l5mctaBoD/3kpQeWsJMcCtTOe66ula2Gy3s7rW3AJkDW+y3aWQCO0T FUalF+xAymcG0YHvBZL52u62njA/eyB9Ex1y2rwhCSSgYK9Kcqi+ZHPFQ8VJvkpVvsecDj w/lDeb7hqHK3Re6qhLUABXctV8BDD8DhRiDAZAMxf448FxPWfNRa/Wqt+FvPdG3VBtdmZs NJhzBdJYnsl3hUQ3HmArCHxJBUvmmJPt6q5WCrJfNNuvuSCX+0DyhumkOGAtNg== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=immFFgtyNuj6HTtbPGPzuSGZORnYh1JrJd/+MGtz0nkRwZIvdTmpn+Pvt1QZPKOYQC/5Abag4aqHlfOZdT20PDuMOlwBpyy4uI0pVYUFvOhKryDnuI+McjWHlA2KtLvjGTLrpBH1qmcRe3yl1YCOkPiaRk7X1Z1VFevU/IkiYAV2nf++5NRn3megf7OnbYm0Uvom+jgL9q9dOdR4rIfcTbjXZK/1xGWemYubItsbiJlSCFbI32l0wZNvZMvgbI0+A4r50LUDjeUFoiOuRFKqiKP4elImEut/x0aVrLtijrQQD5QZw8VVwXe94WbTmJlCuS3kW1ERP1GXUH3JG5oVmw== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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>; [...] }; Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- 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 13d7c4c553..199088425a 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -44,12 +44,12 @@ struct BCM2835PeripheralState { qemu_irq irq, fiq; BCM2835SystemTimerState systmr; BCM2835MphiState mphi; 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 61b04a1bd4..51a477cdc2 100644 --- a/include/hw/arm/raspi_platform.h +++ b/include/hw/arm/raspi_platform.h @@ -34,13 +34,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 */ #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 #define MMCI0_OFFSET 0x202000 diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index a9d7f53f6e..f0802c91e0 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -342,12 +342,12 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->dwc2), 0, qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_USB)); 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 Fri Sep 25 10:17:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 272760 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 D32C3C4727F for ; Fri, 25 Sep 2020 10:21:06 +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 3350E21D91 for ; Fri, 25 Sep 2020 10:21: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="Kevn0f3j" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3350E21D91 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]:54380 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkqf-00063q-AC for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:21:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42668) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknE-00014C-VN; Fri, 25 Sep 2020 06:17:32 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58100) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLkn8-0007QL-AP; Fri, 25 Sep 2020 06:17:32 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 28283C60F1C; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=raXzaOuCKS7gHcT4Y4vqhXTILWOECsdtqSASUoQ9XTo=; b=Kevn0f3jRLKSH2PEfU7ND7apEpK3HEk/3sQx3/+cKTy/JtpH/e5uXKfUWaJp4AMaqV3SQY hF8Vz4VP8me8LCTPLOm95xxmgIBFq+nndlJtmwXqpaTNbgVSHVkBnnYZzj29M0ZAcnsUsY fYTXNPYFmEE0eQXgfnyggnQfPNTwwVmvchbsTRChVbPoN2phkMqMLjhyPjUd2Ku9R3axb1 oNqIK7A71RDTahEpsjNYgI+MkLonKptWqOCOHkl3aifXMzMMzn2PRQfesbdMl9+27TRZz8 WoxleXrbCXQzI3Z4DVTqtCzIp2cpnXtR/weJOi0BK2WkP7LkCQlm+b4AFNhIlw== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 04/14] hw/arm/raspi: add a skeleton implementation of the cprman Date: Fri, 25 Sep 2020 12:17:21 +0200 Message-Id: <20200925101731.2159827-5-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=raXzaOuCKS7gHcT4Y4vqhXTILWOECsdtqSASUoQ9XTo=; b=Y6NL4bH7MFWfkA1rlQsfO3CRXLwP0mJ1ase/PaZ6SP/YvDoXKeB2qV4MXDHbqpk/EbpROe v/PuFz55lUG2jEwZn7wKzcTL4UhsoGAJ3E01MgVqCwTjTJJKaq+RY59958cKEEYSUHTrUn UFDtgWrrU0RQ3vpo2ynGFifhD6YiXC2rvNycxVVoyjPfpiWyZJ8unbvnUiPptFzxjCg1CH IvzapWr+OH2fqMqQkeBVgjJxjcHCUU6fSYALmO5sC9ZS3IL+Ppug6s7SdmvNWj2Jgf8CYu ND9pOG7PsohjewVxLnTv76+eZc2EsFlGgy2gJ/IKDNV/bOuul3MDLu1JWaUrpQ== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=cxtvBXZzZSy5DUbmsJYsfoc46NGCb69qN60ZWAs5EnJ3JFoj+bzUE58ABbD8M/yIPw65lRzqoAmF0cXeiPtN4KI7Hcns1jPpMMRZvDFnlYP/riPiOXJvQtuBtQ5s/tUQ3MFpUNXKWDSWwIcb/10sH1lljEmUzdCudgMI5jPejhE5Pgner+twXo6gWyBZHv5gKIF4Ul8aYa+bUS63NoULrgG92BJT8cuYhsx6exgrtLHFK+5hISmfGIRvf3s5Mo6fYTy2abD+3qWMhRuHMtt+59RGo8q4msQ6myTuj+sLZ8pzxQh7v6pOwG7vIIwm6yVO+5jU6yick9v1K9wFCwSTrQ== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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. Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- 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 | 171 +++++++++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 5 + 7 files changed, 250 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 199088425a..002bb5e73b 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" @@ -45,11 +46,11 @@ struct BCM2835PeripheralState { BCM2835SystemTimerState systmr; BCM2835MphiState mphi; 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..de9bd01b23 --- /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..6a10b60930 --- /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 f0802c91e0..958aadeeb9 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 */ @@ -343,11 +353,10 @@ 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->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..d2ea0c9236 --- /dev/null +++ b/hw/misc/bcm2835_cprman.c @@ -0,0 +1,171 @@ +/* + * 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). It can selects one or the other through a control register. + * Each mux has one output clock that also goes out of the CPRMAN. It 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 = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +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 Clock *init_internal_clock(BCM2835CprmanState *s, + const char *name) +{ + Object *obj; + Clock *clk; + + obj = object_new(TYPE_CLOCK); + object_property_add_child(OBJECT(s), name, obj); + object_unref(obj); + + clk = CLOCK(obj); + clock_setup_canonical_path(clk); + + return clk; +} + +static void cprman_init(Object *obj) +{ + BCM2835CprmanState *s = CPRMAN(obj); + + s->xosc = init_internal_clock(s, "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", 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 Fri Sep 25 10:17:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 272757 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 7872DC4363D for ; Fri, 25 Sep 2020 10:28:38 +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 EBE00221EB for ; Fri, 25 Sep 2020 10:28:37 +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="M55ogn6B" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EBE00221EB 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]:45054 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkxx-0005tI-1H for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:28:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42736) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknM-0001CW-IB; Fri, 25 Sep 2020 06:17:40 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58232) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknD-0007Rf-Rz; Fri, 25 Sep 2020 06:17:40 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 388EAC60F1D; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DxLq6yF2P1PSV1T4dAT3trqFlDD3EhX8tSWRxGzE38E=; b=M55ogn6B2VG5AXoGHC2KrI1BJWtFDTcP9YakDtVmEwbzKBkfTRlpK6ETtnGeims/qucQpY ygSlwa2MtaA6mHS71aP2dgUHFq4AiOCp+aQg3dl7xZQv3o0dAjKk70XnwSFMzbkiJG5Ura P7eQmZL7B9cGGInCUD3nkZC/6z6IcgVIhQ4vlYgyob54LZJNIFKDBIm8aOMA0dMiFDB9ri TwnHN3BESGCv4IM7gFKgnMhJB9Q3yZZdFdfA23foq+ZJrp0Fxl+1rjygqlsjxGdWSusA2E 8lNBwUF8iBhF+xniLpagd2p0EoVObHe9kyr7eLYgqySFo2B6jRsE+1qtEnY9MA== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 05/14] hw/misc/bcm2835_cprman: add a PLL skeleton implementation Date: Fri, 25 Sep 2020 12:17:22 +0200 Message-Id: <20200925101731.2159827-6-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DxLq6yF2P1PSV1T4dAT3trqFlDD3EhX8tSWRxGzE38E=; b=EfWcuqPe5iGvmNRTleVCApAtyShNJjBSARtNnFTQ87t5P0PDXwn29yL5wfcmJWfkeTgi4p P15Ol0pWmTyEjezxLZEspRRtnSNm1P6FwtNLKv/fYHJsOX7BJizf47To5A9FBuQhPQ+wZZ s8SZ4hrjlU+tUb6L9oM9CgANOoq+FKRo8NsszgWg7pcbj9FqktN4Us1cbXoDhzSf5/6YkC knsnG7cHCr8GtyaDVXBAw4/++fayOOxm7I8c/q20SI8/lPjZoGQMtcz6cnk24YUoH9KEbn AvRx6/6cnOevoj857BNmjjv7LT/M6qD+VoYfCaQrfZW3nlvd3vx+JLzFGcRxkA== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=TdSt1GvoNop84UY2oI/YZ0sBH8Qxy30xyHYPdbJgo1VSipyi9DxqrGkDhtbWIPOeZlRn6vU+Kg/r6+hSMT17lS+/kXr4yH9CMevHsS1WF6vJ98hSigYGc32mE6HHNPVO10BASbe5eBpTjFD0spjTc1neYh9M3F/ynLfNfFofwbG27bIaNlBle+pKLoYqIo8g/e3vbsn/4f30WOIbmgzz+6SZHY2LwniU9kEv2Sw5OEn5flZN+ztLHp3zg5epBloC/+fNxBACC75Ig+u+6jeA2j/VRYHkRLkiiPGxo5buFYwmW8CQCdqkT7hfG9hnHGTecfI/F4dfC+6NI5ckNG67zw== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" There is 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. Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- 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 de9bd01b23..f186ab0104 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; + 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 6a10b60930..5cfa849492 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 d2ea0c9236..ad71d30a86 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 = { @@ -96,13 +174,18 @@ 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 Clock *init_internal_clock(BCM2835CprmanState *s, const char *name) @@ -121,18 +204,41 @@ static Clock *init_internal_clock(BCM2835CprmanState *s, } 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 = init_internal_clock(s, "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[]) { @@ -148,10 +254,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); } @@ -164,8 +271,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 Fri Sep 25 10:17:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 272761 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 5BA2DC4727C for ; Fri, 25 Sep 2020 10:20: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 C0AA421D91 for ; Fri, 25 Sep 2020 10:20: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="bQh+xYff" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C0AA421D91 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]:51732 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkpx-0004qa-Ne for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:20:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42688) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknJ-00015W-9T; Fri, 25 Sep 2020 06:17:37 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58230) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknD-0007Ri-Si; Fri, 25 Sep 2020 06:17:36 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 52DAEC60F1E; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FcBIzmQAZtEmj8qCZRpqLApGyCCP0+6Pwhqm+5t6clU=; b=bQh+xYffT7DzsX3tbkSjp6Whl4VXzh71EhhJjvDnZ6MR7F6aT/RYhphYo7IGk2Pq2ULAHf JW0GZkNLT8vn7SHIMVkTgvt8uoYAEC1i3jMGNHnWRWERguzHZCP2za1hmiG7F5PRf6Enxy 2S3l+W82/8VM0XqihegViKe/i+BrCBCvo3D5jIRJEcXve6Cjf7kPurWAcfAd+ocestfSlS r/nLRimb7+c2aBJao2FQ7cxZO+OOiHGS4iDUOJQd71AoYoOPpdut5+hUy6CRmaAZtPhFmH iG8MdWHfFIW+D6B+bH9bDe5Q+o757jriRGk5nHL4NJ6mmkuJjzJC87i+mZlFag== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 06/14] hw/misc/bcm2835_cprman: implement PLLs behaviour Date: Fri, 25 Sep 2020 12:17:23 +0200 Message-Id: <20200925101731.2159827-7-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FcBIzmQAZtEmj8qCZRpqLApGyCCP0+6Pwhqm+5t6clU=; b=MQQy2NJkSTrUBjcMLhmMkVPWGC+M8WLIuBYVh0TRq94RJXuTM+nS6TRFZtE3aei+DGlIP2 kMzaFZCFGAwjTxcfnSfi0k8sjSut+UEqSD4mDRYU8IIiPmDlEVwpC+Ng8jHc94Q2HOAdJe shCbn5U8QjR+00WV74DoH8JY2DKaE+wTfDTCm2V/qdsMJJHW6h7eWzYdyuqOhnzMddLD/c phbm38Lz5aW+Tcd4zckcbwPDhlFBGUcz0I+gecJJB4Ev+ZymZgBg0Rj56oyDDVOwvLDft7 VAnRw8CLgoXICY1amOn1NQAKo5BwKh46P1hdaU4LZ85/TU1WNyIsbnYjk21otw== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=ABKocZKBspjBpwdV3Vm9KlcAHubFk7ylIe5IyrJMfKd3vcZtHDKswXM6H8en/v5MJ1hxMJP5czI3dOdYmH3C6r97LH8cSXhMobIqeder0oRDr84yohDb+iNJj9PBlOyqq+IL0dRA3UxzKEAof+1RexBGa+s5voi2gcDlMitr1gJozy+wivj/Qc/D5X7aAZALrbBQK0Mp2cYjAcRdTV8+jkepepBqyJHcMuD9ZdLwbVwOCe7HdREvEdaBM1JivNT6Egl7O/Vd5pqYg/2D87lQ6cxczJlvWiCRwtFZyd31Or+knCgV8kFuJGqGzICZCKvZl9qfmk2LNJ+UvMQTd4dkqw== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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 fractionnal 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 stabilise). Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- 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 5cfa849492..22a2500ab0 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 ad71d30a86..ba82522eb1 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_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 Fri Sep 25 10:17:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304438 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 ADFEEC4363D for ; Fri, 25 Sep 2020 10:19:30 +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 9857D21741 for ; Fri, 25 Sep 2020 10:19:29 +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="JCmSYYDL" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9857D21741 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]:47476 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkp6-00034q-Lp for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:19:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42732) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknL-0001Ai-Ek; Fri, 25 Sep 2020 06:17:39 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58234) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknF-0007Rz-37; Fri, 25 Sep 2020 06:17:39 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 6BFA2C60F1F; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VJd34/7OS7c3o3033uLyqBxQ35yFAlW7/56yUtCbDKg=; b=JCmSYYDLEbwJgFipqAmgDebYuVqPqI6Vjz/hquCUhN20ksa1DFNvvTHHf6U9alL4o7DKUf 9/JPegsE1/hwJYYCsSCmX+KWL2ES10PX5Guc/dma5DPMxIF7522BEvLJ/YwNByP+GgjFv4 tztbV2NppBDE+ywIW2YcVfbAqqxnMIYEoJWXHYU4ybfFDbSMcQCrKae9xfxK9Ehtu4n7rP iQhGDMOT6/kXkubI138IslrAexV7wyA3jrMz3SQGchzztPXyC7GNlis5DYETuS9PVEHTtM aXZcXJm0fzOEtTLzUBZeNCTx8NrD9cTO9sNMK2WEy5LyAi3sXNJkPAqvZxC8cg== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 07/14] hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation Date: Fri, 25 Sep 2020 12:17:24 +0200 Message-Id: <20200925101731.2159827-8-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VJd34/7OS7c3o3033uLyqBxQ35yFAlW7/56yUtCbDKg=; b=LKijZJOnCkHum6eroKJk5/laZPpWnho9kA43J1WLVFbdstpmxE4IkakhS7+h/Kww6NYuUd 3YscgPgKyj1qiBesHCBwc1JBsyF8TK46mzaF6fISAUcuU9ZO2cAnfEXIfIBuKkodJU/Inq OvLasKhhCx3EIw75VMt8Ev68c1S5SMltUE6Y4VB4rJVMVZ6/2CxpdqQHpWiVBFGwTHoODr hAc0umDMHZGSYJ+zDWBANlIPQBVz8tXJakm5F9OzQBi6+EWB44F+i/BLg2FtknjdBj0wXU gw9meKSYXN6OVWj3H43cTq40jHjhKEm2uuxQQq1dnpHwwUfn1KsipvRKY81r+g== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=SUGHgptDCcJk1/8g1qiRzGdPfqg2luIOqPaikMBVLfvIA9PjM6qxivq+D+0jhtsgQAmrUeGTT0T1lEzODGs0SjjcR+F3Xc3FYeLF8xXjYrcAZkFNstfMijLVgrMdZrJdn4LgoyiUSEQBu2u5B8Im91yK5lUwtbm6culL6gpNrLgvtOxsbaXo4B2FELeDviw2UUJO2/tqr6X6+WMNel0hBji/uDNNInhGnpQ0nVWbGAGf2lNXUMCGzhoKD6nnGQ2yd68yoM9qLvpdxkVyvL+sizBNnul6FnGaqeEKxQ0e+uvBX2oI+be3JtcWFnfFYHn7HhAYBcWaF/afOx9E3jJf2A== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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. Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- 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 f186ab0104..aaf15fb20c 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 22a2500ab0..8a5b9aae67 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 ba82522eb1..2c70a3f317 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[] = { @@ -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, @@ -244,10 +359,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 Clock *init_internal_clock(BCM2835CprmanState *s, const char *name) @@ -274,10 +393,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 = init_internal_clock(s, "xosc"); memory_region_init_io(&s->iomem, obj, &cprman_ops, s, "bcm2835-cprman", 0x2000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); @@ -295,10 +421,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, @@ -334,8 +472,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 Fri Sep 25 10:17:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304434 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 59EA9C4363D for ; Fri, 25 Sep 2020 10:26:55 +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 AC47D221EB for ; Fri, 25 Sep 2020 10:26:54 +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="AVXE/d/X" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AC47D221EB 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]:38708 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkwH-0003CQ-Js for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:26:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42722) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknK-00018X-Jl; Fri, 25 Sep 2020 06:17:38 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58236) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknF-0007S0-2M; Fri, 25 Sep 2020 06:17:38 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 882DFC60F20; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=B9F/66Vuw8urIeiKnlqbUW/o4qpDy+MtTRBF5H3Fg5c=; b=AVXE/d/XTTIiawt4nUJt41/1Hmz/YG0EH6zFbA1oFPjXxDxJuuHFsxQPgaIgJlZWHR/vW3 sRbev50NEYQ+uPHTvI583mXhN/gYDtA30rPVnf2pFf7grBLT7zJvfI1/e//RhbzuyvoKk3 SzLSjiQwE66t4DDMysmqFzLBQCfOqSayU+02qv8AgeDbIOyGOSTtlt5D1ZapleVyLMt2Uh JEy/iezn5AVdf5o2AxpmVAbr4w2M2R6WAdHi4Wy3ii4DIriwBpuiFAkRYAw6jwrGtebSpD A1BNOanOektZOc1NcC/uRauEduotRcp2LwO30phIPLYhNXCTqsOG6OlsjIHHFw== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 08/14] hw/misc/bcm2835_cprman: implement PLL channels behaviour Date: Fri, 25 Sep 2020 12:17:25 +0200 Message-Id: <20200925101731.2159827-9-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=B9F/66Vuw8urIeiKnlqbUW/o4qpDy+MtTRBF5H3Fg5c=; b=cjG8tE9mjEqEETyVlvOrkQk58Ad0Oxr2DJV4YmsqU78TzJvh0BkuyoTUllvyGnjw/y0C/5 g7t+s8FSYwgpJMS7heYsnkYnbCqLGwBS/XABLZT08EzWIStE49XP9xVdUlhtp2ZaQTIgpY gDxF1vcNtMOJxI4teUZkr3vcCJdKODdRJsPdM+iMWCz+ILlK++VLYZxYEpzw4hO+J/mi8V b1kp139A0TkO61wu8fp8wFZi36VtYSzLGS8ZV9DqoQ16DWoBwYBgZpSs7Qt3QqQiM4/Xil y/BOdZWrgnpQWr3UqOY4wMjjz6Vn6tR+7/DQld+EC5X4M2BIS2xrjZLULp8EOw== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=VeYE3jpca0MJWf8Zlf4SpfqlJupuXimZz/NaA+DOUWPnY1wlEo3W35C/e5QeyLe+APuPTnv9mKn+uGOeVkhCEsZK+vUUk5a+zFn2V/gfTi97HKVLJ055GBtMk/QHglr4wJzI3yCu60egR5/v+t0h7SYhbR/cWA5pAyN5tMzsTzRAa80z8VNfT8p3l2ZZ3N4AkeNJyi4uf3AfdNhBz3bb2+hJLv+9GcWyxTUEP8FISaTouRrzzrNRui/fD32dB7ygMlaPMoilQxFCmz0/jKWEIdXfpzT+tY8+y3r/CiaVDAxhxuDoZ7KBaMyIXJ4Jygh3iR3IrNBsRzlz7exnOegWvw== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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 a additional fixed divider which is always applied to the signal. 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 2c70a3f317..e644aeb2b5 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 Fri Sep 25 10:17:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304432 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 0CCC2C4363D for ; Fri, 25 Sep 2020 10:29:43 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 900A9221EB for ; Fri, 25 Sep 2020 10:29:42 +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="Ny5gMLcI" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 900A9221EB 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]:47526 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkyz-0006yf-Np for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:29:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42812) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknn-0001cp-Rb; Fri, 25 Sep 2020 06:18:07 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58238) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknd-0007SF-9O; Fri, 25 Sep 2020 06:18:07 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 97D56C60F21; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=v/uiZF1SCdR1bRANIJzuR1+OmsRilHDQs3qMfJu0mlc=; b=Ny5gMLcIT5LVGwu96dSmeIQMW6zMOS44WIGOXbpT98YGM9Dk+ub9nLyQhN7DkCHNy5ovbi 8NyOJxZVzcN4DecaVT2SSyzcM0hYnaUVrdqYN3qPnNodWv8PtQe6zRMRQCI4Eu8LgKnqMq brga4yk4ha3T7IV+8DjqUT53CphM2EEPwNadz9j09dJ5x855d5BqG/fHWbzIBtUuzdZAJl LMZGdqB7tK/BIoTvUO8lObrvr7/yf9Wf9fSFlPIAFB7BHRzKtRVbHofTmUHVyhvg74bef8 9DtjHaRhKfKjxCgX1cc8AIIkmq0DorC3t+7OZ1ktPRuGjagq046DcTHpEhle5w== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 09/14] hw/misc/bcm2835_cprman: add a clock mux skeleton implementation Date: Fri, 25 Sep 2020 12:17:26 +0200 Message-Id: <20200925101731.2159827-10-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=v/uiZF1SCdR1bRANIJzuR1+OmsRilHDQs3qMfJu0mlc=; b=UASWEYRVO/rnTq6Twa176OYt79KIeKLKLplcx3TlusE1GF4Pmc3jOl0t+Ga02IevyeutLD GEZuKzhB/c7/BqH7Sk5F/Wihbqd1j8kf6aztpx4xAR8bGSsCw/vmiJKrt5Y/gIc9vy+Vz4 vC6cq1xdRBPvNLTVJA40DTSODVEd6Tr7VcoGHCIVdnpczqDJNrauS7J2pEaNoQwp8GoxJC ywOkZXIpnmlGsEk6oRrTYXrR5ZMUN9MAF8iT99NmymfwiD77CJGdlfNzoWjlpACXno1Gb7 8hVOt8RE0bqMzqF/rpImbaIwX81mvq+M3q0w68JGaizJvg5gdjDxlhCuN67ojA== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=abkHKzLcVT2uNScMxu2uIs7QKz9pgBczqZVi8arvjlzjy26u5xC3i6JbfVPfuestCo9UJX/7j7KyMDHEJcc5XHqXgw4pU7mwdFqVG/7vy0AV6gWjdSLFcm+jwXjRnu/Df2KqpJWZHO5LmJMTvykMNwWoNrggx39bxP9B74krrJXzlJc/14253o2q/Qp7NHZcn+oLjOuCUizSfqzQJkR4jfka9sQMKdMh+LIOLjVTUycMc5wBzBKf4dmJMV+7bghLjRwonvLuEmequVD9IhXiyOMidR6JUqG4YU+9Z9WAXrl8XDCengxnM7KT9iM7QBpGYfxso4ZfRbQyBAd84uyFIw== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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.) Signed-off-by: Luc Michel --- include/hw/misc/bcm2835_cprman.h | 84 ++++ include/hw/misc/bcm2835_cprman_internals.h | 421 +++++++++++++++++++++ hw/misc/bcm2835_cprman.c | 151 ++++++++ 3 files changed, 656 insertions(+) diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index aaf15fb20c..c2a89e8e90 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,45 @@ typedef struct CprmanPLLChannelState { Clock *pll_in; Clock *out; } CprmanPLLChannelState; +typedef struct CprmanClockMuxState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + CprmanClockMux id; + + uint32_t *reg_cm; + 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 8a5b9aae67..a2b5a1aa50 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,340 @@ 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; + 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_cm = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset]; + 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 e644aeb2b5..8df2db0fd9 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[] = { @@ -291,10 +353,23 @@ 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 == idx + 4)) { + 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 +438,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 @@ -394,10 +478,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 Clock *init_internal_clock(BCM2835CprmanState *s, const char *name) @@ -431,17 +519,69 @@ 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 = init_internal_clock(s, "xosc"); + s->gnd = init_internal_clock(s, "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; @@ -464,10 +604,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, @@ -504,8 +654,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 Fri Sep 25 10:17:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304436 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 2D75CC4363D for ; Fri, 25 Sep 2020 10:22: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 9AC4421D91 for ; Fri, 25 Sep 2020 10:22: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="G2msWkse" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9AC4421D91 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]:57962 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkrq-0007Z8-EE for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:22:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42730) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknK-00019X-VO; Fri, 25 Sep 2020 06:17:38 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58240) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknJ-0007SE-7j; Fri, 25 Sep 2020 06:17:38 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id AAAA6C60F22; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YOuCNbOOvSsStZNfbQT6hnxWhxzA58znlB/MmjZ2y5Y=; b=G2msWksehXz8+B/Ovvn/E5LRViL4pvyLW1sALYAcTxj/PZimXJtVomTYV9Soz80kz0jWpl 99USxdF3nWyh7ZQbcdPxoP0X6sPmeNkiDtJBAt2Iygu17s62FX2v7wMxk0TIJEhPc41y/e hhTG7Rhr5hI1f683WUkbsLJoYChY87cpEcAtM/xn5kR3rtJM/FYSmBVSwNCKoRszooNlBH 7mFE+lUzE4sRlAIvS0HGD6NOd+fkjASL3r48PXvcU4jhaRSu1Gt48zkzuW0FjopmBN4Gtn qd/rw6q2AWoOWVlVAdo38mcs4Xkw8LeU3eDLDJuqnFvlJcbNqnXGlzldoR0Luw== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 10/14] hw/misc/bcm2835_cprman: implement clock mux behaviour Date: Fri, 25 Sep 2020 12:17:27 +0200 Message-Id: <20200925101731.2159827-11-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YOuCNbOOvSsStZNfbQT6hnxWhxzA58znlB/MmjZ2y5Y=; b=bo65Qd9oZX9y5njzIvy/q/o7FobEiPuAX8wXitUrkGEQNS11R9Hf6bO8kxDEqAV3nAhRTB 6T2fnpDuWcg9KJZjMp8Y81UZKyK5A2aOaHs8QIhWhuDshZOlTe3wR5yAmH7IMBjmbdGm5d 29ejZSqzmVV4XrEInL/0SvDHmiRD/1O2hdiLuWYNEOsVkcxVE+7qdDggQBSKfGQaAbrYuX QDJ8HbLKkvhHR0eVZUBfLSyAdGi9vkFvsCusS+wrs4wqxIZ1e9VFjOBdI5TbabFNKQfDVu yqdHMAUbUW5c/ZSeKgXOsJ9sPo4cexS95VKaZtkw3rcg2Frgzy0WZtBoL+idPQ== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=GGDkSOnTdXoBFQ9yRk9piF5O1J/EAg7hbZwHfCxkXhQ+b1DbGL3OaiyGSm/2d0+YYkfAHJuSpw1JXVU6hlyXxHVnDYccaxmEqWf314fihXJp5mkS5meMyGmcDpUC0Ukx79Jo5uOHCbG1J1Cukf7T2Css9BhP6MBgfW34cbtNFkmKXAcK5MHnDaOdMpXeTdppk/0xFfYb50Iao6rARHpMqZkEkjBFNyCro5h7dDjDNw82qm+tYSa+78QR/Q2xKNfYSjWXVJz7yrLC0Ht0SDL5Hml8pjTf7NzGHdB8JXyHjBcVQrv/9juVniTOPhFjEhRytrj2Pi7ibyDCWkRbLpoGvw== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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 fractionnal part. The number of bits of each part is mux dependant. Signed-off-by: Luc Michel --- hw/misc/bcm2835_cprman.c | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 8df2db0fd9..75bc11939b 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -229,19 +229,60 @@ static const TypeInfo cprman_pll_channel_info = { }; /* clock mux */ +static bool clock_mux_is_enabled(CprmanClockMuxState *mux) +{ + return FIELD_EX32(*mux->reg_cm, CM_CLOCKx_CTL, ENABLE); +} + static void clock_mux_update(CprmanClockMuxState *mux) { - clock_update(mux->out, 0); + uint64_t freq, div; + uint32_t src = FIELD_EX32(*mux->reg_cm, CM_CLOCKx_CTL, SRC); + bool enabled = clock_mux_is_enabled(mux); + + *mux->reg_cm = FIELD_DP32(*mux->reg_cm, 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. + */ + div = mux->reg_cm[1] >> (R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits); + div &= (1 << (mux->int_bits + mux->frac_bits)) - 1; + + freq = (freq << 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; + uint32_t current_src; + + current_src = FIELD_EX32(*s->reg_cm, CM_CLOCKx_CTL, SRC); + + if (current_src != src) { + return; + } clock_mux_update(s); } static void clock_mux_init(Object *obj) From patchwork Fri Sep 25 10:17:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 272759 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 33458C4363D for ; Fri, 25 Sep 2020 10:23:22 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B510921D91 for ; Fri, 25 Sep 2020 10:23: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="Z/yixsQk" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B510921D91 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]:60614 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLksq-0000I7-QZ for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:23:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42734) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknL-0001BX-V7; Fri, 25 Sep 2020 06:17:39 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58242) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknJ-0007SP-8I; Fri, 25 Sep 2020 06:17:39 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id C5B91C60F23; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MsNBR+iq9fdf+lKa2N77Xg9ZgMSlmTYx7Lrf4dgXr5M=; b=Z/yixsQk9LhChvn6Av25PKVNnCU2u7tFz3KPh7EOcnLhdElmL1kfIOWnpJL2YC+Le18X6R KBqwmEO+EJXlt11nAmINSnb/YxDTMwA+NLHrTpPJvmKi4NQ1QNJvE60lFqQRt8ymcy6BRC Hh0qEM/zT3EtAgDM9Lbo+CgWhdBukFNpvdAIqTt2xN6CKfQQgShNy0S1rrOkdNFEdmXNBB wSE/9HKiV7GWHm9hzXfpMISLrTLVb2MnPWBnQ1FluxEuDBz/rzaUR4jNMAkcBAg+4efW3m 5wMVjLglF0i1BvAPUB54FpCfF56z4cbTnhfOpRK8Lwg4pUspgE7KtoxAlDa1+g== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 11/14] hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer Date: Fri, 25 Sep 2020 12:17:28 +0200 Message-Id: <20200925101731.2159827-12-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MsNBR+iq9fdf+lKa2N77Xg9ZgMSlmTYx7Lrf4dgXr5M=; b=YV1ALaM0Zcy3/FLJKBAK9mQZDveD4zzRvBsNo3PrzIOw03rR6XLWLLSUA6Q3IVXuyzXv0/ NmXVrJDCFFXIMK7kHCKRvFryHAc0FFCs2Bi8d3rrgmq5LV8JdA4uxVam1TtOMHbcsH4V+O Q6ckXBEp/6eYUEnUjxME1Jr34yJUIHt/2dC+JhCE5kJsEbSdn03Wh0aOWdenrSd1UsF8Ke EnQWza/M4EJYWPhSpW8JnJPcMl2VA6Lga5ZlwNWmDW7+V5ARvxJjmWrIlYTPYWYZTkoDri vJvy5DbYn72GkV4PKehHQ0OTZ/tw120ZyMR5CwUgw1fsALffqhWDgmD+VWZTMw== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=IeGihrNl9K3ZP6IAGdpfdOYwR4CiL/lsj4Eqk4LV6LwzRbX+ne/R32W0x0fb6XWZSeVLBO2woHl3zALMLRm6yNaM3xJjdQGCoxXZ0c8b+vGUShlhlo6FpjBJWzCwdPLbaupAK5agxnnbW7ChVySO93T/vB4puJmeBsdvshNpP+IGN4HAi1Kcv1lLZWLdVh+M6DJ4KjjoDrf5SENX9PBpfXR7TRVdxX5SoncP7jO7ufnWqtDvIsW4FMEan+7qI5HbWXAp4o4d/0LdvJk35pYoq6QoUQeFEUjJ25gU9t0erdZRah5L2k2iC55NKH6VaBqzhCZ/ZyQf5GG8KmNMTOE2bQ== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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. Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- include/hw/misc/bcm2835_cprman.h | 15 +++++ include/hw/misc/bcm2835_cprman_internals.h | 6 ++ hw/misc/bcm2835_cprman.c | 78 +++++++++++++++++++++- 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index c2a89e8e90..5555a299fc 100644 --- a/include/hw/misc/bcm2835_cprman.h +++ b/include/hw/misc/bcm2835_cprman.h @@ -171,20 +171,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 a2b5a1aa50..ad07cf5276 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 75bc11939b..e576ab2642 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -327,10 +327,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[] = { @@ -488,10 +540,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 @@ -519,10 +575,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); @@ -560,10 +618,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], @@ -608,11 +670,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; } @@ -646,10 +708,23 @@ static void cprman_realize(DeviceState *dev, Error **errp) if (!qdev_realize(DEVICE(channel), NULL, errp)) { return; } } + { + CprmanDsi0HsckMuxState *dsi0hsck_mux = &s->dsi0hsck_mux; + + clock_set_source(dsi0hsck_mux->plla_in, + s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out); + clock_set_source(dsi0hsck_mux->plld_in, + s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out); + + if (!qdev_realize(DEVICE(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); @@ -696,8 +771,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 Fri Sep 25 10:17:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 272756 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 5912FC4363D for ; Fri, 25 Sep 2020 10:30:12 +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 B7543221EB for ; Fri, 25 Sep 2020 10:30:11 +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="DHi72S62" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B7543221EB 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]:49294 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkzS-0007iE-PN for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:30:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42786) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknj-0001XP-Ia; Fri, 25 Sep 2020 06:18:04 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58244) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknd-0007SN-9R; Fri, 25 Sep 2020 06:18:02 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id D7558C60F24; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XYmTD4UkWAFnlkcU34EMX40lMfSmz6vUyQ7STKLwesk=; b=DHi72S62IkVE1v4kGD8A1tHQY8kC7rYG6BbaYGUK6rtKRvXH4iBap0uNnKVJsl1uyGzsqj Ji8eZXalGWg+gjsxDlRSlI3BWz9qZdVw6+1X/C3nxSKa7UwF/bbOpN88fZg8ZiLisJljku hpmwb68xQn6jFSSWbuiDPb0GR88AH00DHAXBgwi8OQo2DNgfD8FsKmhIil0FHRkxkogKm1 vLF0wcr5FzIFOp2dc8ehRXTWbfkbtcokSbwkDDDhXWLEoqGY9hSQK2TRoBSDRH6OGTV9Ue nqVdPVeLjWxZPm8ae9aU1r0Qv642srci7tzhZeZbUEuijqdhm7KHzGgOgOYVzg== From: Luc Michel To: qemu-devel@nongnu.org Subject: [PATCH 12/14] hw/misc/bcm2835_cprman: add sane reset values to the registers Date: Fri, 25 Sep 2020 12:17:29 +0200 Message-Id: <20200925101731.2159827-13-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XYmTD4UkWAFnlkcU34EMX40lMfSmz6vUyQ7STKLwesk=; b=ZFNBK2dF7KwM8aqyZZL3phW8mwtRk6JuKM7rzuab5DBEqYC/Fdy3U4BOuYIgjyB9obFCzi /zRv3q6VyPdDPjJJDk2HiOEiGOGLn1ecF6LgzvTiQ9vAfgKXyWFCc3GpD8YMcipef41LEs PQnasQwRSa4VlCLzB5f2ENr83TJc/BlqBYf9cDRp1qOLtw04a7AU3/zHPTIknf1xHRYvF7 Xjh5XXKxFcxwkXDV/kl25XUiiHyc6X2LYAZJoxholPkpOh6CsSu/hs8kV1wHizfEWQgIiZ zrtuhlXtpW6ieBkQLoD+q9tVven7hWBDMGa4TGnS/mIb79f+ZOWVmlhL82nGhw== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=jOzjd6FCZeN40HNRxAGmjxQHWaC87Pn6Sumkyke9Pfv+oVNLn/DnvYtqUZcReq27qiKR6+bdWgE4DFiZBzop4KsSTzo3C/Cb0DhiCq+1FBAWYomNMKftNs00k4XJPuUgjLydsN8ExhiPhuA9ePkMvT7Q8yocikot/pT/hkrlLAjwQHVMDy6YNKV4XjV+AYJ9YkVVcxuXSg5rCZPcHL+JVgr2fR3fOiA8w/Q4SrmS8BNPvijrCXq8t/YPff5WUHSV1zCcvkpEA40+7NkNL4IekEmVLNsC44kSUMNXT6wZXP38vPsbSo8+vgLjdB95B++qn1Uwuovztbuh+ifwOyAGvA== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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. 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 ad07cf5276..f5e168ccf9 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -744,6 +744,275 @@ static inline void set_clock_mux_init_info(BCM2835CprmanState *s, mux->reg_cm = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset]; 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_ctrl; + uint32_t cm_div; +} ClockMuxResetInfo; + +static const ClockMuxResetInfo CLOCK_MUX_RESET_INFO[] = { + [CPRMAN_CLOCK_GNRIC] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_VPU] = { + .cm_ctrl = 0x00000245, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_SYS] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_PERIA] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_PERII] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_H264] = { + .cm_ctrl = 0x00000244, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_ISP] = { + .cm_ctrl = 0x00000244, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_V3D] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_CAM0] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_CAM1] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_CCP2] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_DSI0E] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_DSI0P] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_DPI] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_GP0] = { + .cm_ctrl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_GP1] = { + .cm_ctrl = 0x00000096, + .cm_div = 0x00014000, + }, + + [CPRMAN_CLOCK_GP2] = { + .cm_ctrl = 0x00000291, + .cm_div = 0x00249f00, + }, + + [CPRMAN_CLOCK_HSM] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_OTP] = { + .cm_ctrl = 0x00000091, + .cm_div = 0x00004000, + }, + + [CPRMAN_CLOCK_PCM] = { + .cm_ctrl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_PWM] = { + .cm_ctrl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_SLIM] = { + .cm_ctrl = 0x00000200, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_SMI] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_TEC] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_TD0] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_TD1] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_TSENS] = { + .cm_ctrl = 0x00000091, + .cm_div = 0x0000a000, + }, + + [CPRMAN_CLOCK_TIMER] = { + .cm_ctrl = 0x00000291, + .cm_div = 0x00013333, + }, + + [CPRMAN_CLOCK_UART] = { + .cm_ctrl = 0x00000296, + .cm_div = 0x0000a6ab, + }, + + [CPRMAN_CLOCK_VEC] = { + .cm_ctrl = 0x00000097, + .cm_div = 0x00002000, + }, + + [CPRMAN_CLOCK_PULSE] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_SDC] = { + .cm_ctrl = 0x00004006, + .cm_div = 0x00003000, + }, + + [CPRMAN_CLOCK_ARM] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, + + [CPRMAN_CLOCK_AVEO] = { + .cm_ctrl = 0x00000000, + .cm_div = 0x00000000, + }, + + [CPRMAN_CLOCK_EMMC] = { + .cm_ctrl = 0x00000295, + .cm_div = 0x00006000, + }, + + [CPRMAN_CLOCK_EMMC2] = { + .cm_ctrl = 0, /* unknown */ + .cm_div = 0 + }, +}; + #endif diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index e576ab2642..a8b54cccdb 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, @@ -283,10 +304,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_cm[0] = info->cm_ctrl; + clock->reg_cm[1] = info->cm_div; +} + static void clock_mux_init(Object *obj) { CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj); size_t i; @@ -315,10 +345,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 Fri Sep 25 10:17:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 272758 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 CD221C4363D for ; Fri, 25 Sep 2020 10:24:56 +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 47AB2221EB for ; Fri, 25 Sep 2020 10:24:56 +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="hfb9RzTP" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 47AB2221EB 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]:36090 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkuN-0001tH-Ci for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:24:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42800) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknm-0001Z8-4l; Fri, 25 Sep 2020 06:18:06 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58262) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknh-0007So-TJ; Fri, 25 Sep 2020 06:18:05 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id EBF81C60F25; Fri, 25 Sep 2020 10:17:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jzk0uP9k3MS5cnLaH5qrGE/fnKTXANTCV6K+Nith/Go=; b=hfb9RzTP6dXBiznw5KlW87C53QFgpKuyurFMogcw5A/Z2+gOsWWxdJj4lq1H9IXIm7XtDj Ze7oGFn2YoThG2R0mJqc3CDLxkl0qSS575WHOVQ4WcHDBqD+STFCtn8c56y1bLGegu5yf4 CaxOw6SzzjqP5nR6U/vqzuP+zA6PlUHqGXy8uyu4CCmJNKbr2CB+GnsrFyBjxuXQAcIlMD RMTarrPtfFPgIEb9b7B1CKRUlzS3+Nuw65nO4uXiFUkBeUFUNV0tSKFmejCgcn6dKnEJwV kNh1+f1FuzgYMLbRZMMP+RmU7rS0NEGbey+DSXCmUuBv13CbMueF3H8cw2Rf6g== From: Luc Michel To: qemu-devel@nongnu.org Subject: [RFC PATCH 13/14] hw/char/pl011: add a clock input Date: Fri, 25 Sep 2020 12:17:30 +0200 Message-Id: <20200925101731.2159827-14-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029040; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jzk0uP9k3MS5cnLaH5qrGE/fnKTXANTCV6K+Nith/Go=; b=K7cR4DFHW1uDWtw0Zq2Nf+uvUafaWoKIX+uHHeLscLRVPa3Z+sOTH+i1aQW+HLaO0J0v73 WndHOfijhOKHuEGS6aGp/DH+oF3k6E37RNTeDtCXzA8xKTmDWUvtIKW7zgVnkL0zJhVImr /O53zFTXZ0y+QzlEnJJrh53eP7I5HWPNlpF6H54vMBqjHD/gny8KZXJL4Gs/ATpFUSsu6o +C//+KLXNdsQY24m8bxXoxBdfrYeCco4JMxGUqIqcHurnyxn+NT26t+CYiJu5HhJRfoY5O 0G9wpv3NtnFyO+xkwUIVqk8uS8pQ+d6dnVmlph4hLg25H6Nr2oyBdIBUnkBzzQ== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029040; a=rsa-sha256; cv=none; b=jRVhJgajq0sjnjwiJcf6nqb9KPhUuxZgd4rOkvSmsHk/GljfvnMhM0rOigoBnb1AdA6hqd0vJ4mZ2bFEQvBTEIA8rXnFfATMpguvYKORcUcVxc+xFTb2+NiVb0afVH208m1h2HfA3k6ax4fuEweL92JniKyuE5XT+U5RkBJ7M7ttAiZCDoTwF/oej4NIcNhMTpnpoVUajShAoKMeP8qNuLUrQSMuV71e4lqJGpcHCE1WYQNhoIESlmKOny1mrJMRakAeDgW5j4eiGFs0eDnhqgvO06Xz0A0zEPsh7D94S8PMis9+mofBIXBZNKxUNabjtFSJa5JFFj56Vefy+sivIg== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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. Signed-off-by: Luc Michel Reviewed-by: Philippe Mathieu-Daudé --- 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 2442a9f7d5..cc1f0065ac 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -62,10 +62,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 Fri Sep 25 10:17:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luc Michel X-Patchwork-Id: 304433 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 9BE7EC4363D for ; Fri, 25 Sep 2020 10:27:52 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 31B95221EB for ; Fri, 25 Sep 2020 10:27:52 +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="DW5g0qjJ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 31B95221EB 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]:42364 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLkxD-0004kB-5V for qemu-devel@archiver.kernel.org; Fri, 25 Sep 2020 06:27:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42798) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknk-0001Yd-TO; Fri, 25 Sep 2020 06:18:06 -0400 Received: from pharaoh.lmichel.fr ([149.202.28.74]:58264) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLknh-0007Sp-TQ; Fri, 25 Sep 2020 06:18:04 -0400 Received: from sekoia-pc.bar.greensocs.com (sekoia-pc.home.lmichel.fr [192.168.61.100]) by pharaoh.lmichel.fr (Postfix) with ESMTPS id 08C2BC61424; Fri, 25 Sep 2020 10:17:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lmichel.fr; s=pharaoh; t=1601029041; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nYIO6oVFxUZV1TH9x+9OCm3cGZXkpXFo/VqRcUn44+U=; b=DW5g0qjJIUMvhhgTBWSkRp+9YOyVNrwX/TP5EYfA9pPjQkKw4xKeLN3MSNEh5ScPFyHrsz NGZkXToXVrQ4VgC6E6iKmkeB8/EqM3i4iydCSaODOPMDqu1xtd0yAgQ+caGy11LnD2Bgjy zE+guOKG/BER9sTPEXjFevFEIs6z0PPPr2tgmwBI2xvGjMZQzDMx5gemd96iAoTjNmTw7a hUlh5VdfCNUMm3sTMOStOyz6Gbsiv+AonGiJzSVMg78KEMq1FWy5UzMp1+UUGCeCkbsCwa e+euD6wI4Cq3DYAsMV1KHVkLxW43dB2B38Szm2apup60oYERn38NACX+1KH52w== From: Luc Michel To: qemu-devel@nongnu.org Subject: [RFC PATCH 14/14] hw/arm/bcm2835_peripherals: connect the UART clock Date: Fri, 25 Sep 2020 12:17:31 +0200 Message-Id: <20200925101731.2159827-15-luc@lmichel.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925101731.2159827-1-luc@lmichel.fr> References: <20200925101731.2159827-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=1601029041; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nYIO6oVFxUZV1TH9x+9OCm3cGZXkpXFo/VqRcUn44+U=; b=Aj75JlhH/otuCtkq4rHuO8rkZ1y1YmCKr6nxnldTCBp2pdnqhPc5BMFOeJSXWWviXcJC+f gCne17Goy45PTbFyltcgeJK/zdDvLftHFwbzxh9PhKQKRvQv9Ho+q7jafOuPxmHr3n8Jhl QebBDH2fgUYE0/6NosS2GaaAy5WWM8mtFd9cyGyXCOB1iAeLYtqLCelEt8RLqQdkbUjNFl kH9YGs9GDlm92Xr/ji2olgHyZ+sQDJUoJ3GRWry22EKmM/9qa8yUB6MGaxw9hfhybOvLhb EQqGiaySnlq7hDIUKHTqXELGVIJ2mXfncJHplhXskMvnV9w9980X9vJC8CLFYg== ARC-Seal: i=1; s=pharaoh; d=lmichel.fr; t=1601029041; a=rsa-sha256; cv=none; b=dyaLWTww/X8AwLKqegqfKpDMeoo40HdqROuBVcSkNUZvT333OEohA5CHKidBgtgK9MkUQ6nejgfcVPKIC5EGg7kUKQWmUTHfAFGiIaYKOoY7uzQECeY6Ilxv+5AMtLzXSaQoW4pTyM7zIFT9nGZ0ByoM6MqFF7kXcW9YzfNUR+OjaWV5DkQWnJnT2fTjXC0Naq1ZomoUe8bv7kR5Ak+iYZ2JvIJb3FbevTKJx/zb12HXkRjc2udg2mGUOmOOX+m/0GIZna9VPZL1laMBqKmEFwJofyN+AAqJXLfSBX7My0LDYcq3mNpS3A9cz53u0pKfa3+gs/gN5ZNJRcUcq+S8uQ== 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/09/25 06:17:20 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 , qemu-arm@nongnu.org, Luc Michel , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Andrew Baumann 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. 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 958aadeeb9..9e4e85c3ad 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));