From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 338BBC2D0A6 for ; Thu, 15 Oct 2026 18:12:29 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1xHPvf-0001b2-ST; Thu, 15 Oct 2026 14:11:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1xHPva-0001Sv-Kh for qemu-arm@nongnu.org; Thu, 15 Oct 2026 14:11:42 -0400 Received: from mail-qt1-x82c.google.com ([2607:f8b0:4864:20::82c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1xHPvY-0001Vw-KX for qemu-arm@nongnu.org; Thu, 15 Oct 2026 14:11:42 -0400 Received: by mail-qt1-x82c.google.com with SMTP id d75a77b69052e-53394bffe0fso3042601cf.1 for ; Thu, 15 Oct 2026 11:11:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792087899; x=1792692699; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=IpXjq2SzDcplb7laGRs+XIFC6vBU+wvz9DmPUswUPKY=; b=smxZ3fCoIRCHEFp5LJfQ75zd5wniGe6g2FCRWk/vJtnMZ1p5ybVNJL/T0rdx9COgHR b/hDQDEDDf4ZbeYb97Fqjh7oDppm1YPGjF21+pftK+oC6yLS4YuIEfpbgTOdA7cBy20Z r9lnCI6Rav9hIWYVlkAw4GsaMNoWjqyO0DV1NQ5oMw7Zt8MimFy5VGMu8ghOc4lOTky8 me/GNsbmXcmoyKm8uyJR8+MpBGn6sOK/oeEyIhZKp2Jzywy1Y/dRewKLyxi0KCXYV47p eQJq4Q38UY2McjMPhb9nhpcOUh85iuSQUZsq4oYdhxn332HKKRdyIWC6dPjtahBkTEgW RlXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792087899; x=1792692699; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=IpXjq2SzDcplb7laGRs+XIFC6vBU+wvz9DmPUswUPKY=; b=sggiDsLRVTP2rI7y/HucFsvMY+Fm0B77ptTDHQpeRri3c0Y1NnLn3wvnTE0r6RGTJe WDgqRtfgEI2aP5muy34AYxEpOjVmt6c4KHrYvfZ/IUtFC3mE5T9TKdbq1Q4yYmaiyp+h 7/50rvQPYP2EQawnqML0N89Ufq5add4+2u2oMeoGIUCcv2jigyVu3sK0pn+hvmERmvzL GYKo2lFCdIU/maZD8NAovvklWcvjpbh0QtU7b4YzUYEsXQMNnGtlOHfLO1EwOyPInCv3 yJj2yH+P4rsRooLpvrC78M54JO2Zey2q/I8330UA2OAN9SKJaPnyDYyLA0IkZRFiOaPB AqKg== X-Forwarded-Encrypted: i=1; AKwUvBw6+rVl3Vs6QcDtC1LONqN1hoK6AHSQGlmUEOysnjvLOiaFKedT6g+FaG6Mg92LguM3mXtJNmhAjA==@nongnu.org X-Gm-Message-State: AFq9FYIQ3EuoTfq0wWKArdwQrced35FV9u2/6MC08qlhDEi18SHDx6MV C6g1Zztt2E1rdbmYRcn90ACgVC0mh/gg089Fi1rGEXNHqNG4tiZuo9Cw X-Gm-Gg: AYBFou2lfCyEiGE4HGiWVjpmXkNeYiwy83tLZGj8BWuv0Mojqu72IJEEwug4AKPSst1 bFNv148n15tBB64sNYD7Owe7pXQP/K6UPaW6cMsFw7aA4lxr4HGdf1MsPyjZMNnyd2No9Sz6v3T egy7nk/giSAhBlO5Qsuqsjtae0HKt01amPWNNLpXU63YSmVnuz4yKJcr7RiIALpU/2+QpBkoV/R VdqaYaTCywIzyzXhddypi1otzBp+SwVK6EorZBauH6Xo/+yW2/YS4MMuzd/npfLTbCkOdMopfLK asRApCRKc18njgmUbynushIzrSUOk0fAlw5rRKE9Lyc81uIQcJrPXbZOEs+hQGrgaan3dhfQg2L 7cIMNazukrTtMCo8/ytZEXVf7DcLSoeqlR44uJdOZeEL1ar6iV0z6gW1y+MoaNqlkonj1pPc0Cf f26HHS3H9tSqCi1I9KC/xFuzPVqx3Pgd+2QZrxdHwkoZa78/wq8KWZPdTl0l8crM7lz/dr3RvC2 2FGh+GzPJQmBYFE8jID/AmA6HXBe0xmDNYC+Z+JjKOfd0bgi1Zpn+ttAEM727p7BGqpgg== X-Received: by 2002:a05:622a:1929:b0:535:1943:ccc2 with SMTP id d75a77b69052e-53626f65aacmr14955011cf.4.1792087899381; Thu, 15 Oct 2026 11:11:39 -0700 (PDT) Received: from localhost.localdomain ([2606:6d00:159:2900:919:5388:4e10:5949]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-536127efe4asm32130611cf.19.2026.10.15.11.11.38 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 15 Oct 2026 11:11:39 -0700 (PDT) From: Marcelo Manzo To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: Peter Maydell , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Sergey Kambalin , Sergey Kambalin , Marcelo Manzo , Jason Wang Subject: [PATCH v3 11/16] hw/net/bcm2838_genet: implement GENET MDIO Date: Thu, 15 Oct 2026 14:11:16 -0400 Message-ID: <20261015181122.60608-12-marcelomanzo@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20261015181122.60608-1-marcelomanzo@gmail.com> References: <20261015181122.60608-1-marcelomanzo@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2607:f8b0:4864:20::82c; envelope-from=marcelomanzo@gmail.com; helo=mail-qt1-x82c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-arm@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-arm-bounces+qemu-arm=archiver.kernel.org@nongnu.org Sender: qemu-arm-bounces+qemu-arm=archiver.kernel.org@nongnu.org From: Sergey Kambalin Implement the MDIO command register handling used to read/write the BCM54213PE PHY's standard MII registers (BMCR, BMSR, LPA, ...) plus its vendor "shadow" register blocks reached through the AUX_CTL/ EXP_SHD indirection scheme, and a simple link-state model (PHY starts down, comes up once BMCR is programmed and autonegotiation is (re)started). Part of Sergey Kambalin's original Raspberry Pi 4B PCIe/GENET networking series (patchwork series 829638, posted to qemu-devel in 2024, never merged). Carried forward and completed by Marcelo Manzo. While carrying this forward, fix the autonegotiation-restart handling in bcm2838_genet_mdio_cmd(): the guest PHY driver sets BMCR.ANRESTART and polls BMCR until it reads back as cleared, but the result of FIELD_DP16() (which returns a new value rather than modifying its argument) was discarded, so the bit never cleared and the guest spun forever at boot. Also refresh the link state once the restart has been handled. Signed-off-by: Sergey Kambalin Signed-off-by: Marcelo Manzo --- hw/net/bcm2838_genet.c | 139 ++++++++++++++++++++++++++++++++- include/hw/net/bcm2838_genet.h | 3 +- 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/hw/net/bcm2838_genet.c b/hw/net/bcm2838_genet.c index f3c5ca26c5..fe2a3cf890 100644 --- a/hw/net/bcm2838_genet.c +++ b/hw/net/bcm2838_genet.c @@ -20,6 +20,8 @@ #include "hw/net/bcm2838_genet.h" #include "trace.h" +static void bcm2838_genet_phy_update_link(BCM2838GenetState *s); + /* GENET layouts */ REG32(GENET_SYS_REV_CTRL, 0) FIELD(GENET_SYS_REV_CTRL, GPHY_REV, 0, 16) @@ -216,6 +218,7 @@ FIELD(GENET_PHY_STAT_1000, LOCALRXOK, 13, 1) FIELD(GENET_PHY_STAT_1000, MSRES, 14, 1) FIELD(GENET_PHY_STAT_1000, MSFAIL, 15, 1) +/* There are two data representations for PHY_AUX_CTRL register */ REG16(GENET_PHY_AUX_CTRL_0, 0) FIELD(GENET_PHY_AUX_CTRL_0, REG_ID_MASK, 0, 3) FIELD(GENET_PHY_AUX_CTRL_0, RSVD_3, 3, 1) @@ -272,6 +275,134 @@ static void bcm2838_genet_set_irq_prio(BCM2838GenetState *s) qemu_set_irq(s->irq_prio, level); } +static void bcm2838_genet_phy_aux_ctl_write(BCM2838GenetState *s, + uint16_t value) +{ + uint16_t reg_id = FIELD_EX16(value, GENET_PHY_AUX_CTRL_0, REG_ID); + uint16_t reg_id_mask = FIELD_EX16(value, GENET_PHY_AUX_CTRL_0, REG_ID_MASK); + uint16_t misc_wren = FIELD_EX16(value, GENET_PHY_AUX_CTRL_0, MISC_WREN); + uint16_t reg_data = FIELD_EX16(value, GENET_PHY_AUX_CTRL_0, REG_DATA); + uint16_t reg_data12 = FIELD_EX16(value, GENET_PHY_AUX_CTRL_1, REG_DATA); + + uint16_t *phy_aux_ctl_shd_reg_id = + (uint16_t *)&s->phy_aux_ctl_shd_regs + reg_id; + uint16_t *phy_aux_ctl_shd_reg_id_mask = + (uint16_t *)&s->phy_aux_ctl_shd_regs + reg_id_mask; + + if (reg_id_mask == BCM2838_GENET_PHY_AUX_CTL_MISC) { + if (reg_id == BCM2838_GENET_PHY_AUX_CTL_MISC) { + if (misc_wren == 0) { + /* write for subsequent read (8-bit from AUX_CTL_MISC) */ + FIELD_DP16(value, GENET_PHY_AUX_CTRL_0, REG_DATA, + *phy_aux_ctl_shd_reg_id); + } else { + /* write 8 bits to AUX_CTL_MISC */ + *phy_aux_ctl_shd_reg_id_mask = reg_data; + } + } else { + /* write for subsequent read (12-bit) */ + FIELD_DP16(value, GENET_PHY_AUX_CTRL_1, REG_DATA, + *phy_aux_ctl_shd_reg_id); + } + } else { + /* write 12 bits */ + *phy_aux_ctl_shd_reg_id_mask = reg_data12; + } + + s->phy_regs.aux_ctl = value; +} + +static void bcm2838_genet_phy_shadow_write(BCM2838GenetState *s, + uint16_t value) +{ + uint16_t reg_id = FIELD_EX16(value, GENET_PHY_SHADOW, REG_ID); + uint16_t wr = FIELD_EX16(value, GENET_PHY_SHADOW, WR); + uint16_t reg_data = FIELD_EX16(value, GENET_PHY_SHADOW, REG_DATA); + + uint16_t *phy_shd_reg = (uint16_t *)&s->phy_shd_regs + reg_id; + + if (wr == 0) { + FIELD_DP16(value, GENET_PHY_SHADOW, REG_DATA, *phy_shd_reg); + } else { + *phy_shd_reg = reg_data; + } + + s->phy_regs.shd = value; +} + +static void bcm2838_genet_phy_exp_shadow_write(BCM2838GenetState *s, + uint16_t value) +{ + /* + * TODO Stub implementation without side effect, + * just storing registers values + */ + uint16_t reg_id = FIELD_EX16(s->phy_regs.exp_ctrl, + GENET_PHY_EXP_SEL, REG_ID); + uint16_t block_id = FIELD_EX16(s->phy_regs.exp_ctrl, + GENET_PHY_EXP_SEL, BLOCK_ID); + + s->phy_exp_shd_regs.regs[block_id][reg_id] = value; +} + +static uint16_t bcm2838_genet_phy_exp_shadow_read(BCM2838GenetState *s) +{ + uint16_t reg_id = FIELD_EX16(s->phy_regs.exp_ctrl, + GENET_PHY_EXP_SEL, REG_ID); + uint16_t block_id = FIELD_EX16(s->phy_regs.exp_ctrl, + GENET_PHY_EXP_SEL, BLOCK_ID); + + return s->phy_exp_shd_regs.regs[block_id][reg_id]; +} + +static uint64_t bcm2838_genet_mdio_cmd(BCM2838GenetState *s, uint64_t cmd) +{ + uint32_t phy_reg_id = FIELD_EX32(cmd, GENET_UMAC_MDIO_CMD, REG_ID); + uint32_t phy_reg_data = FIELD_EX32(cmd, GENET_UMAC_MDIO_CMD, REG_DATA); + uint32_t start_busy = FIELD_EX32(cmd, GENET_UMAC_MDIO_CMD, START_BUSY); + uint32_t rd = FIELD_EX32(cmd, GENET_UMAC_MDIO_CMD, RD); + uint32_t wr = FIELD_EX32(cmd, GENET_UMAC_MDIO_CMD, WR); + uint16_t *phy_reg = (uint16_t *)&s->phy_regs + phy_reg_id; + + uint16_t anrestart = FIELD_EX16(phy_reg_data, GENET_PHY_BMCR, ANRESTART); + + if (start_busy != 0) { + cmd = FIELD_DP32(cmd, GENET_UMAC_MDIO_CMD, START_BUSY, 0); + + if (rd != 0) { + if (phy_reg_id == BCM2838_GENET_EXP_DATA) { + cmd = FIELD_DP32(cmd, GENET_UMAC_MDIO_CMD, REG_DATA, + bcm2838_genet_phy_exp_shadow_read(s)); + } else { + cmd = FIELD_DP32(cmd, GENET_UMAC_MDIO_CMD, REG_DATA, *phy_reg); + } + } else if (wr != 0) { + if (phy_reg_id == BCM2838_GENET_PHY_AUX_CTL) { + bcm2838_genet_phy_aux_ctl_write(s, phy_reg_data); + } else if (phy_reg_id == BCM2838_GENET_PHY_SHD) { + bcm2838_genet_phy_shadow_write(s, phy_reg_data); + } else if (phy_reg_id == BCM2838_GENET_EXP_DATA) { + bcm2838_genet_phy_exp_shadow_write(s, phy_reg_data); + } else { + if (phy_reg_id == BCM2838_GENET_PHY_BMCR) { + /* Initiate auto-negotiation once it has been restarted */ + if (anrestart == 1) { + phy_reg_data = FIELD_DP16(phy_reg_data, + GENET_PHY_BMCR, + ANRESTART, 0); + } + } + *phy_reg = phy_reg_data; + if (phy_reg_id == BCM2838_GENET_PHY_BMCR && anrestart == 1) { + bcm2838_genet_phy_update_link(s); + } + } + } + } + + return cmd; +} + static uint64_t bcm2838_genet_read(void *opaque, hwaddr offset, unsigned size) { uint64_t value = ~0; @@ -359,10 +490,13 @@ static void bcm2838_genet_write(void *opaque, hwaddr offset, uint64_t value, s->regs.rdma.status = (~value) & GENET_DMA_ENABLE_MASK; break; case BCM2838_GENET_UMAC_MDIO_CMD: + value = bcm2838_genet_mdio_cmd(s, value); + s->regs.intrl0.stat = FIELD_DP32(s->regs.intrl0.stat, + GENET_INTRL_0, MDIO_DONE, 1); + break; case BCM2838_GENET_TDMA_REGS ... BCM2838_GENET_TDMA_REGS + sizeof(BCM2838GenetRegsTdma) - 1: - qemu_log_mask(LOG_UNIMP, - "UMAC MDIO and TDMA aren't implemented yet"); + qemu_log_mask(LOG_UNIMP, "TDMA isn't implemented yet"); break; default: break; @@ -464,6 +598,7 @@ static void bcm2838_genet_reset(Object *obj, ResetType type) trace_bcm2838_genet_reset("done"); + bcm2838_genet_set_qemu_mac(s); bcm2838_genet_phy_reset(s); } diff --git a/include/hw/net/bcm2838_genet.h b/include/hw/net/bcm2838_genet.h index e3dee5a78f..b34c4b3ce7 100644 --- a/include/hw/net/bcm2838_genet.h +++ b/include/hw/net/bcm2838_genet.h @@ -103,7 +103,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(BCM2838GenetState, BCM2838_GENET) #define BCM2838_GENET_EXP_DATA BCM2838_GENET_PHY_REG(exp_data) #define BCM2838_GENET_EXP_SEL BCM2838_GENET_PHY_REG(exp_ctrl) -#define BCM2838_GENET_PHY_AUX_CTL_MISC 0x7 +#define BCM2838_GENET_PHY_AUX_CTL_AUXCTL 0x0 +#define BCM2838_GENET_PHY_AUX_CTL_MISC 0x7 #define BCM2838_GENET_PHY_AUX_CTL_REGS_SIZE 8 #define BCM2838_GENET_PHY_EXP_SHD_BLOCKS_CNT 256 -- 2.55.0