From nobody Sat Apr 5 17:36:42 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1737971105; cv=none; d=zohomail.com; s=zohoarc; b=SZDZQ0vLTmR7sYnmvB+HPPacDBj3KWOmcSDfH+mbXoCwmibCqpwR6uPNU/zjJ03ThH2FYHk5T3fLAZlxY96rZ3A6UZXvUBRQyNkqf8MVUM9V+zkIZh7eM1W9VDxHDEmTd4uz/lIoc+NONYA7PU8XutyMF96wf3y5GkJthvo24Ck= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1737971105; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=gvxXCpgxcR8pnFAbFm1ZXD/+Uaq5sgKqZlPpIPkXai4=; b=F0O/op/826gZrFb629ykW3rdigHYirzzboWdPdqGDSQJSjuK8tQjmVkdTnp0nQnnkJzgj5afVkExmu2D3GaibjktlwpOgTHCjCrw2H4KOA0MUyYRPzG87OdunjNFsVrzJ2eOB32YlEdLt7XYvi7equgAVzaUH01AiYjfoj0f41s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1737971105186643.102319422143; Mon, 27 Jan 2025 01:45:05 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tcLen-0006bJ-OJ; Mon, 27 Jan 2025 04:43:49 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tcLeF-0006HR-QS for qemu-devel@nongnu.org; Mon, 27 Jan 2025 04:43:19 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tcLeD-0005Ro-Op for qemu-devel@nongnu.org; Mon, 27 Jan 2025 04:43:15 -0500 Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-88-wTJvDMfFPWa2KzkVTeBabA-1; Mon, 27 Jan 2025 04:43:07 -0500 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8D34819560BB; Mon, 27 Jan 2025 09:43:00 +0000 (UTC) Received: from corto.redhat.com (unknown [10.39.192.63]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7FBA71800365; Mon, 27 Jan 2025 09:42:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1737970991; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gvxXCpgxcR8pnFAbFm1ZXD/+Uaq5sgKqZlPpIPkXai4=; b=HgUekkEi6QUljUEYtLJ27Ar+A6dYk56Mzvb/VuC/2JDSQ1Zjw6H5n1joNMQ7EHVn+WTt6A cn4ZVE+2przM7FmtP3xdysAODfwW2Nq461cQCzIxpAGqsBTDtCSZN/8sCRohH2xnW11RsD wIWx/uxOYqmBZP8q4LvJyZ4/foLs2wQ= X-MC-Unique: wTJvDMfFPWa2KzkVTeBabA-1 X-Mimecast-MFC-AGG-ID: wTJvDMfFPWa2KzkVTeBabA From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: Jamin Lin , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Subject: [PULL 05/12] hw/timer/aspeed: Add AST2700 Support Date: Mon, 27 Jan 2025 10:42:32 +0100 Message-ID: <20250127094239.636526-6-clg@redhat.com> In-Reply-To: <20250127094239.636526-1-clg@redhat.com> References: <20250127094239.636526-1-clg@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=clg@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -33 X-Spam_score: -3.4 X-Spam_bar: --- X-Spam_report: (-3.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.299, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.01, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1737971107463019000 From: Jamin Lin The timer controller include 8 sets of 32-bit decrement counters, based on either PCLK or 1MHZ clock and the design of timer controller between AST2600 and AST2700 are almost the same. TIMER0 =E2=80=93 TIMER7 has their own individual control and interrupt stat= us register. In other words, users are able to set timer control in register TMC10 with different TIMER base address and clear timer control and interrupt status in register TMC14 with different TIMER base address. Introduce new "aspeed_2700_timer_read" and "aspeed_2700_timer_write" callba= ck functions and a new ast2700 class to support AST2700. The base address of TIMER0 to TIMER7 as following. Base Address of Timer 0 =3D 0x12C1_0000 Base Address of Timer 1 =3D 0x12C1_0040 Base Address of Timer 2 =3D 0x12C1_0080 Base Address of Timer 3 =3D 0x12C1_00C0 Base Address of Timer 4 =3D 0x12C1_0100 Base Address of Timer 5 =3D 0x12C1_0140 Base Address of Timer 6 =3D 0x12C1_0180 Base Address of Timer 7 =3D 0x12C1_01C0 The register address space of each TIMER is "0x40" , and uses the following formula to get the index and register of each TIMER. timer_index =3D offset >> 6; timer_offset =3D offset & 0x3f; The TMC010 is a counter control set and interrupt status register. Write "1= " to TMC10[3:0] will set the specific bits to "1". Introduce a new "aspeed_2700_timer_set_ctrl" function to handle this register behavior. The TMC014 is a counter control clear and interrupt status register, to cle= ar the specific bits to "0", it should write "1" to TMC14[3:0] on the same bit position. Introduce a new "aspeed_2700_timer_clear_ctrl" function to handle this register behavior. TMC014 does not support read operation. Signed-off-by: Jamin Lin Acked-by: C=C3=A9dric Le Goater Link: https://lore.kernel.org/r/20250113064455.1660564-3-jamin_lin@aspeedte= ch.com Signed-off-by: C=C3=A9dric Le Goater --- include/hw/timer/aspeed_timer.h | 1 + hw/timer/aspeed_timer.c | 208 ++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) diff --git a/include/hw/timer/aspeed_timer.h b/include/hw/timer/aspeed_time= r.h index 07dc6b6f2cbd..767cae4b05ba 100644 --- a/include/hw/timer/aspeed_timer.h +++ b/include/hw/timer/aspeed_timer.h @@ -32,6 +32,7 @@ OBJECT_DECLARE_TYPE(AspeedTimerCtrlState, AspeedTimerClas= s, ASPEED_TIMER) #define TYPE_ASPEED_2500_TIMER TYPE_ASPEED_TIMER "-ast2500" #define TYPE_ASPEED_2600_TIMER TYPE_ASPEED_TIMER "-ast2600" #define TYPE_ASPEED_1030_TIMER TYPE_ASPEED_TIMER "-ast1030" +#define TYPE_ASPEED_2700_TIMER TYPE_ASPEED_TIMER "-ast2700" =20 #define ASPEED_TIMER_NR_TIMERS 8 =20 diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 24ba40cbe9b4..ecda49574e2c 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -618,6 +618,197 @@ static void aspeed_2600_timer_write(AspeedTimerCtrlSt= ate *s, hwaddr offset, } } =20 +static void aspeed_2700_timer_set_ctrl(AspeedTimerCtrlState *s, int index, + uint32_t reg) +{ + const uint8_t overflow_interrupt_mask =3D BIT(op_overflow_interrupt); + const uint8_t external_clock_mask =3D BIT(op_external_clock); + const uint8_t pulse_enable_mask =3D BIT(op_pulse_enable); + const uint8_t enable_mask =3D BIT(op_enable); + AspeedTimer *t; + uint8_t t_old; + uint8_t t_new; + int shift; + + /* + * Only 1 will set the specific bits to 1 + * Handle a dependency between the 'enable' and remaining three + * configuration bits - i.e. if more than one bit in the control set h= as + * set, including the 'enable' bit, perform configuration and then + * enable the timer. + * Interrupt Status bit should not be set. + */ + + t =3D &s->timers[index]; + shift =3D index * TIMER_CTRL_BITS; + + t_old =3D (s->ctrl >> shift) & TIMER_CTRL_MASK; + t_new =3D reg & TIMER_CTRL_MASK; + + if (!(t_old & external_clock_mask) && + (t_new & external_clock_mask)) { + aspeed_timer_ctrl_external_clock(t, true); + s->ctrl =3D deposit32(s->ctrl, shift + op_external_clock, 1, 1); + } + + if (!(t_old & overflow_interrupt_mask) && + (t_new & overflow_interrupt_mask)) { + aspeed_timer_ctrl_overflow_interrupt(t, true); + s->ctrl =3D deposit32(s->ctrl, shift + op_overflow_interrupt, 1, 1= ); + } + + + if (!(t_old & pulse_enable_mask) && + (t_new & pulse_enable_mask)) { + aspeed_timer_ctrl_pulse_enable(t, true); + s->ctrl =3D deposit32(s->ctrl, shift + op_pulse_enable, 1, 1); + } + + /* If we are enabling, do so last */ + if (!(t_old & enable_mask) && + (t_new & enable_mask)) { + aspeed_timer_ctrl_enable(t, true); + s->ctrl =3D deposit32(s->ctrl, shift + op_enable, 1, 1); + } +} + +static void aspeed_2700_timer_clear_ctrl(AspeedTimerCtrlState *s, int inde= x, + uint32_t reg) +{ + const uint8_t overflow_interrupt_mask =3D BIT(op_overflow_interrupt); + const uint8_t external_clock_mask =3D BIT(op_external_clock); + const uint8_t pulse_enable_mask =3D BIT(op_pulse_enable); + const uint8_t enable_mask =3D BIT(op_enable); + AspeedTimer *t; + uint8_t t_old; + uint8_t t_new; + int shift; + + /* + * Only 1 will clear the specific bits to 0 + * Handle a dependency between the 'enable' and remaining three + * configuration bits - i.e. if more than one bit in the control set h= as + * clear, including the 'enable' bit, then disable the timer and perfo= rm + * configuration + */ + + t =3D &s->timers[index]; + shift =3D index * TIMER_CTRL_BITS; + + t_old =3D (s->ctrl >> shift) & TIMER_CTRL_MASK; + t_new =3D reg & TIMER_CTRL_MASK; + + /* If we are disabling, do so first */ + if ((t_old & enable_mask) && + (t_new & enable_mask)) { + aspeed_timer_ctrl_enable(t, false); + s->ctrl =3D deposit32(s->ctrl, shift + op_enable, 1, 0); + } + + if ((t_old & external_clock_mask) && + (t_new & external_clock_mask)) { + aspeed_timer_ctrl_external_clock(t, false); + s->ctrl =3D deposit32(s->ctrl, shift + op_external_clock, 1, 0); + } + + if ((t_old & overflow_interrupt_mask) && + (t_new & overflow_interrupt_mask)) { + aspeed_timer_ctrl_overflow_interrupt(t, false); + s->ctrl =3D deposit32(s->ctrl, shift + op_overflow_interrupt, 1, 0= ); + } + + if ((t_old & pulse_enable_mask) && + (t_new & pulse_enable_mask)) { + aspeed_timer_ctrl_pulse_enable(t, false); + s->ctrl =3D deposit32(s->ctrl, shift + op_pulse_enable, 1, 0); + } + + /* Clear interrupt status */ + if (reg & 0x10000) { + s->irq_sts =3D deposit32(s->irq_sts, index, 1, 0); + } +} + +static uint64_t aspeed_2700_timer_read(AspeedTimerCtrlState *s, hwaddr off= set) +{ + uint32_t timer_offset =3D offset & 0x3f; + int timer_index =3D offset >> 6; + uint64_t value =3D 0; + + if (timer_index >=3D ASPEED_TIMER_NR_TIMERS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: offset 0x%" PRIx64 " out of bounds\n", + __func__, offset); + return 0; + } + + switch (timer_offset) { + /* + * Counter Status + * Counter Reload + * Counter First Matching + * Counter Second Matching + */ + case 0x00 ... 0x0C: + value =3D aspeed_timer_get_value(&s->timers[timer_index], + timer_offset >> 2); + break; + /* Counter Control and Interrupt Status */ + case 0x10: + value =3D deposit64(value, 0, 4, + extract32(s->ctrl, timer_index * 4, 4)); + value =3D deposit64(value, 16, 1, + extract32(s->irq_sts, timer_index, 1)); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%" + PRIx64"\n", __func__, offset); + value =3D 0; + break; + } + trace_aspeed_timer_read(offset, value); + return value; +} + +static void aspeed_2700_timer_write(AspeedTimerCtrlState *s, hwaddr offset, + uint64_t value) +{ + const uint32_t timer_value =3D (uint32_t)(value & 0xFFFFFFFF); + uint32_t timer_offset =3D offset & 0x3f; + int timer_index =3D offset >> 6; + + if (timer_index >=3D ASPEED_TIMER_NR_TIMERS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: offset 0x%" PRIx64 " out of bounds\n", + __func__, offset); + } + + switch (timer_offset) { + /* + * Counter Status + * Counter Reload + * Counter First Matching + * Counter Second Matching + */ + case 0x00 ... 0x0C: + aspeed_timer_set_value(s, timer_index, timer_offset >> 2, + timer_value); + break; + /* Counter Control Set and Interrupt Status */ + case 0x10: + aspeed_2700_timer_set_ctrl(s, timer_index, timer_value); + break; + /* Counter Control Clear and Interrupr Status */ + case 0x14: + aspeed_2700_timer_clear_ctrl(s, timer_index, timer_value); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%" + PRIx64"\n", __func__, offset); + break; + } +} + static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id) { AspeedTimer *t =3D &s->timers[id]; @@ -788,6 +979,22 @@ static const TypeInfo aspeed_1030_timer_info =3D { .class_init =3D aspeed_1030_timer_class_init, }; =20 +static void aspeed_2700_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + AspeedTimerClass *awc =3D ASPEED_TIMER_CLASS(klass); + + dc->desc =3D "ASPEED 2700 Timer"; + awc->read =3D aspeed_2700_timer_read; + awc->write =3D aspeed_2700_timer_write; +} + +static const TypeInfo aspeed_2700_timer_info =3D { + .name =3D TYPE_ASPEED_2700_TIMER, + .parent =3D TYPE_ASPEED_TIMER, + .class_init =3D aspeed_2700_timer_class_init, +}; + static void aspeed_timer_register_types(void) { type_register_static(&aspeed_timer_info); @@ -795,6 +1002,7 @@ static void aspeed_timer_register_types(void) type_register_static(&aspeed_2500_timer_info); type_register_static(&aspeed_2600_timer_info); type_register_static(&aspeed_1030_timer_info); + type_register_static(&aspeed_2700_timer_info); } =20 type_init(aspeed_timer_register_types) --=20 2.48.1