From patchwork Fri Oct 4 19:56:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Stockhausen X-Patchwork-Id: 13822993 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 9201DCF885D for ; Fri, 4 Oct 2024 21:02:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=sucb3svdgaARBZBADtPtrhNjtGkNNKSpuAtzrHLLxgM=; b=El8g/SoFntBjIF kd6NF16hKNPoMwtXAwhFRW5vHWf9Qpr1BK0pn/2bvgWQNRiw87+uQysMFYJn6b559XQjgOx6nv9vH tEEVVT8jgk4kURZ2/ZHE539USW5mH8hoIBmgvrzZofcseS9inIzfXv3cFMaKj5IeOkjl1OaQj85TS UPI9eww/0roIFWsESonXzcMomGx+PYPwztC6wQ5qzoY0NLRYH0j+Rh7yKwCYmYfBWK77Wv4hNrenI xVkOapROOuqQYRnBokIe2bWyBO3sIbY5cew52EeyL0YAIoQF6TZT/dp/RJz+43vM6IWeKm68BuIRl V0oQCG39xnHqcZ84HCxg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1swpR9-0000000EE8b-11a1; Fri, 04 Oct 2024 21:02:07 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQp-0000000E13n-3fA0 for linux-phy@bombadil.infradead.org; Fri, 04 Oct 2024 19:57:44 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Transfer-Encoding:MIME-Version :References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=RBix+wqd4rPTZ9hwcpM5atQMEjXDAmOeIkKruBi46lc=; b=EKJAXJVALTjyZwfYvoJrNOi7KY 12OAZc7vaWX54ckyJJA/Qgy9vtNsv0ZqC2j2GjEpYQTMgetn+QNdGqsyM3qi7+YCm1HKt1M/X1o2r iy9ZTXzLzdWumhvxIxphWbk2vP60k9MKI9W600OGZVZzlw9+iqCJW2BaiX8d6I448+2II7DS0UXVp 1dNfoaorasBp66bydmF9NCYB6PQkbnyye7fw9fKCiEzCvnArs1fAMbg14iQNeIlJIWFhHU7/bOAdr vOixLJPEL8hYYn3emAdH0d5Xl/5fpWmfjOx2aER7eE8WeghfMrhG/1dQRwbOqNN/Ll3So/u5yZFo0 /wFt8OGg==; Received: from mout.gmx.net ([212.227.17.22]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQl-00000003vw3-2gKl for linux-phy@lists.infradead.org; Fri, 04 Oct 2024 19:57:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmx.de; s=s31663417; t=1728071836; x=1728676636; i=markus.stockhausen@gmx.de; bh=RBix+wqd4rPTZ9hwcpM5atQMEjXDAmOeIkKruBi46lc=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:Message-ID:In-Reply-To: References:MIME-Version:Content-Transfer-Encoding:cc: content-transfer-encoding:content-type:date:from:message-id: mime-version:reply-to:subject:to; b=hbHoRiqypa8+2G1Tw3M0KdvmmGx0qaNWfV43sH9SKBe1mZElpnwy9REocsfhUQLo CwQWQivQnpSO8IukGwB/YlIxObgRUy/gA2PFs9JxInDcZUv2Dy1gMKrzm1DxHXAXM EDAeq//pNDYWo8XHNuTgMlg841hjQWk/S6TBAHek7uLSm5Ae/FMsLoa+BEiC5TFIY iSZHP7CWqF9IVMYPIep9DY7fvFJzFCKnsY+Y3pq4MAjg0vivvXNbPnigCWl7V0qRN JyC7cA3Kyv0/7GYkbEqmjiJxgBETbttU+nwwzc/4mNYHZhHy+TPK0ubvknn2xPUWX HqlOJ84z2pq6BNirEQ== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from openwrt ([94.31.70.81]) by mail.gmx.net (mrgmx104 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MdefJ-1tWQI63XCj-00eBQT; Fri, 04 Oct 2024 21:57:15 +0200 From: Markus Stockhausen To: linux-phy@lists.infradead.org, chris.packham@alliedtelesis.co.nz Cc: Markus Stockhausen Subject: [PATCH 1/4] phy: Realtek Otto SerDes: add header file Date: Fri, 4 Oct 2024 15:56:07 -0400 Message-ID: <20241004195712.1891488-2-markus.stockhausen@gmx.de> X-Mailer: git-send-email 2.46.2 In-Reply-To: <20241004195712.1891488-1-markus.stockhausen@gmx.de> References: <20241004195712.1891488-1-markus.stockhausen@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:PiA6jVv76VM4E+O1reVAfyMAhX63/z+7XCh6izc9atkugIA9evT LTcWbV0lCNC1EJitDasPUQ79rSvc1mEKKBcJvdtHG946ySAc5X6AcuvS4lU8sxTvQpP+4vd 3bAa+mcl5E7LrAj8BE3c+yH7ZNHzeuXG7FGAd1w3Pyl5F2nsSrZQtAUulfbcRF6HQhmtEf3 eJDTeBcEg5Pm9fSp9WTtA== UI-OutboundReport: notjunk:1;M01:P0:DRyco9o7Pso=;TV3/Ewbf+Plhm7NO/MP2AkVYzEC HezziUjwIFMXjXwyvNNlSfbWKTgo0Eo7jht05cCvg/Oe7dCCQ8gb21ZUEO0K/g7jWIIInO0Ox SvtonRwBIV9Jx3OdU0N5FWUp9xyT2ylM9bd3MLW4vdh4VXq0XldfzFWVUCs9q+O3Yil8gfpsA fioZBMWi+ZQ0m6GL/xmiqrfrlxEjzUblbIFUX2ezsA+n1Z0xD8rF+BHdqNP8kWOiuCYfrBv8O QTLHw3MwOcQETmHyvGBLN+hHN4J4n09+SLBwA8uSJQaTklwwtZ//2rOByoh4YYkgrJWPPXw8y aw0sa5tnR+1jqcxsXIPXGmA5S4tdwpTqDaEvkaMtBDcs6B2+G20SBMvKTOMwDsWCnAmfkh6Nv y9eM9T/j2dcoDCo6r6mT3xHZHrLhhaSRvIfwJYmBq3KYBl6MG8elU73oAr6LwGGYNMiE6VCD4 b6OTjYKzr285drtFzfTmU1udTVqTAHIa0ALpJtw/KlfOpWQQT7U0MejZaqjPoD1MYM1EJeN5l 6mQJaagW0kE3EBp9NtHE4l/PM13bdf6vlch13X4KWHeG7K47CmIQEfPJ7Kht54ON69aVI2U7V YgjNunpDSF/UehMku+suQEuKBJoHJ0uGUuCL5ksM4ShlpByJGP7ZXKpV5KXJZ+wq615CpBGYq NBLbggLd/XiAVnExGixdmjoEnyPyy/fTECAsGoEszN8T5lho4MlfUmTxOKQEza4JcCrPrMgvh NgmhRvqhgeATHUf6vQ4BuYUVjPLRjaRj8U1iuyZsfDaXt4f0LwmJ+ImfqR5wLhaxrwbfgcnpd 8SEYQ1qQK2atXOjWXSQFwjeg== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241004_205740_064895_EAD3155D X-CRM114-Status: GOOD ( 11.84 ) X-BeenThere: linux-phy@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux Phy Mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-phy" Errors-To: linux-phy-bounces+linux-phy=archiver.kernel.org@lists.infradead.org This adds the header file for the new Otto SerDes driver. --- drivers/phy/realtek/phy-rtl-otto-serdes.h | 126 ++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 drivers/phy/realtek/phy-rtl-otto-serdes.h -- 2.44.0 diff --git a/drivers/phy/realtek/phy-rtl-otto-serdes.h b/drivers/phy/realtek/phy-rtl-otto-serdes.h new file mode 100644 index 000000000000..4d951731c02c --- /dev/null +++ b/drivers/phy/realtek/phy-rtl-otto-serdes.h @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Realtek RTL838x, RTL839x, RTL930x & RTL931x SerDes PHY driver + * Copyright (c) 2024 Markus Stockhausen + */ + +#ifndef _PHY_RTL_OTTO_SERDES_H +#define _PHY_RTL_OTTO_SERDES_H + +#include +#include +#include +#include +#include +#include +#include + +#define RTSDS_PAGE_SDS 0 +#define RTSDS_PAGE_SDS_EXT 1 +#define RTSDS_PAGE_FIB 2 +#define RTSDS_PAGE_FIB_EXT 3 +#define RTSDS_PAGE_NAMES 48 + +#define RTSDS_INV_HSO 0x100 +#define RTSDS_INV_HSI 0x200 + +#define RTSDS_EVENT_SETUP 0 +#define RTSDS_EVENT_INIT 1 +#define RTSDS_EVENT_POWER_ON 2 +#define RTSDS_EVENT_PRE_SET_MODE 3 +#define RTSDS_EVENT_POST_SET_MODE 4 +#define RTSDS_EVENT_PRE_RESET 5 +#define RTSDS_EVENT_POST_RESET 6 +#define RTSDS_EVENT_PRE_POWER_OFF 7 +#define RTSDS_EVENT_POST_POWER_OFF 8 +#define RTSDS_EVENT_MAX 8 + +#define RTSDS_SEQ_STOP 0 +#define RTSDS_SEQ_MASK 1 +#define RTSDS_SEQ_WAIT 2 + +#define RTSDS_SWITCH_ADDR_BASE (0xbb000000) +#define RTSDS_REG(x) ((void __iomem __force *)RTSDS_SWITCH_ADDR_BASE + (x)) +#define iomask32(mask, value, addr) iowrite32((ioread32(addr) & ~(mask)) | (value), addr) + +#define RTSDS_838X_MAX_SDS 5 +#define RTSDS_838X_MAX_PAGE 3 +#define RTSDS_838X_SDS_MODE_SEL RTSDS_REG(0x0028) +#define RTSDS_838X_INT_MODE_CTRL RTSDS_REG(0x005c) + +#define RTSDS_839X_MAX_SDS 13 +#define RTSDS_839X_MAX_PAGE 11 +#define RTSDS_839X_MAC_SERDES_IF_CTRL RTSDS_REG(0x0008) + +#define RTSDS_930X_MAX_SDS 11 +#define RTSDS_930X_MAX_PAGE 63 +#define RTSDS_930X_SDS_MODE_SEL_0 RTSDS_REG(0x0194) +#define RTSDS_930X_SDS_MODE_SEL_1 RTSDS_REG(0x02a0) +#define RTSDS_930X_SDS_MODE_SEL_2 RTSDS_REG(0x02a4) +#define RTSDS_930X_SDS_MODE_SEL_3 RTSDS_REG(0x0198) +#define RTSDS_930X_SDS_SUBMODE_CTRL0 RTSDS_REG(0x01cc) +#define RTSDS_930X_SDS_SUBMODE_CTRL1 RTSDS_REG(0x02d8) + +#define RTSDS_931X_MAX_SDS 13 +#define RTSDS_931X_MAX_PAGE 191 +#define RTSDS_931X_SERDES_MODE_CTRL RTSDS_REG(0x13cc) +#define RTSDS_931X_PS_SERDES_OFF_MODE_CTRL RTSDS_REG(0x13f4) +#define RTSDS_931X_SDS_FORCE_SETUP 0x80 + +#define RTSDS_COMBOMODE(mode, submode) (0x10000 | (mode << 8) | submode) +#define RTSDS_MODE(combomode) ((combomode >> 8) & 0xff) +#define RTSDS_SUBMODE(combomode) (combomode & 0xff) + +struct __attribute__ ((__packed__)) rtsds_seq { + u16 action; + u16 ports; + u16 page; + u16 reg; + u16 val; + u16 mask; +}; + +struct rtsds_sds { + struct phy *phy; + int mode; + int link; + int min_port; + int max_port; +}; + +struct rtsds_ctrl { + struct device *dev; + void __iomem *base; + struct mutex lock; + u32 sds_mask; + struct rtsds_conf *conf; + struct rtsds_sds sds[RTSDS_930X_MAX_SDS + 1]; + struct rtsds_seq *sequence[RTSDS_EVENT_MAX + 1]; +}; + +struct rtsds_macro { + struct rtsds_ctrl *ctrl; + u32 sid; +}; + +struct rtsds_conf { + u32 max_sds; + u32 max_page; + int (*read)(struct rtsds_ctrl *ctrl, u32 idx, u32 page, u32 reg); + int (*mask)(struct rtsds_ctrl *ctrl, u32 idx, u32 page, u32 reg, u32 val, u32 mask); + int (*reset)(struct rtsds_ctrl *ctrl, u32 idx); + int (*set_mode)(struct rtsds_ctrl *ctrl, u32 idx, int mode); + int (*get_mode)(struct rtsds_ctrl *ctrl, u32 idx); + int mode_map[PHY_INTERFACE_MODE_MAX]; +}; + +/* + * This SerDes module should be written in quite a clean way so that direct calls are + * not needed. The following functions are provided just in case ... + */ + +int rtsds_read(struct phy *phy, u32 page, u32 reg); +int rtsds_write(struct phy *phy, u32 page, u32 reg, u32 val); +int rtsds_mask(struct phy *phy, u32 page, u32 reg, u32 val, u32 mask); + +#endif /* _PHY_RTL_OTTO_SERDES_H */ From patchwork Fri Oct 4 19:56:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Stockhausen X-Patchwork-Id: 13822994 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 73191CF885B for ; Fri, 4 Oct 2024 21:02:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=+2YAN01H/Z/3aEaBl1ziA4HzIpkTSjbHzpNE1CVwTls=; b=OzGE0RIcj0LG+7 0MQdQXPlVLcZEchVpOP7dNTtAf3AhRz0lMTxLxJiv5wlpWyzgcLfbbnmGLl7fAlssfufCHjaW29kz iQdVUz2908SHBSbWVMS08U3JUWhAu+SN4UkdtFB4zhcTUlPzguhmcDwtVlsGdpmWsohOR+3dwnvHh enylMQDinOYClGilC4HKKKHG6jQGZ25yp7MfbEzCvRHHqlkSkhkfsTFTkfs6LGpIYmsxWIK/pOZlE /HIQnNYp1jOWBw/7RZAKOTSCXONx/M3fFyigbxECP0nAeXO8akqRIKYSQt/Wj02XOZSjlrVKDuC5h mbPB17DoQJNTEK9dmtrA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1swpR8-0000000EE7i-0DlP; Fri, 04 Oct 2024 21:02:06 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQd-0000000E120-0RXn for linux-phy@bombadil.infradead.org; Fri, 04 Oct 2024 19:57:31 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Transfer-Encoding:MIME-Version :References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=4EiZB57Ije44d5unSa0zzmwhV7tOSVS8o5yzMkwZGS0=; b=JHM98W/fnazMt4AhhbJjHgMptl ztbhmF0e9UvG6HzRibYuvebvgKUSY6/RgmQGb6P418P6ZCWCdjpEUNdENi0wWZMmaCtMu3qhiyciv yDy1tZgMSSKrgw7wLOGOJHcdXmZYZyot5xEXOEghwV8jMvJPbCzOrKmLOhazR7/n0SeEn3sqH5c9C eU8tLU4Tc1e9j4oeE+/T+I4kenTkgNJYZnRHLAbGYi4JD/9wBaqtX1lY5tZlHpfKM5vX/gL+5W423 8Qd/jo9q2av4o6pcd/bAPuWU+/R+2gOl/zf6zo4o6I+jNW2tsspv9uoesuXyQYQLdFAXRKk6zedNI wWCgP4Ug==; Received: from mout.gmx.net ([212.227.17.21]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQX-00000003vtQ-2AwS for linux-phy@lists.infradead.org; Fri, 04 Oct 2024 19:57:27 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmx.de; s=s31663417; t=1728071836; x=1728676636; i=markus.stockhausen@gmx.de; bh=4EiZB57Ije44d5unSa0zzmwhV7tOSVS8o5yzMkwZGS0=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:Message-ID:In-Reply-To: References:MIME-Version:Content-Transfer-Encoding:cc: content-transfer-encoding:content-type:date:from:message-id: mime-version:reply-to:subject:to; b=BZ13Fa6krd+ph0TsiKBveMIKoNU6QpKFaGLYyJArkw7prvtU7Q/svHpjPz9uwxqL mTMCVziPPN1k5Cv+OJfoNMMzE/eyK4nB68tUoEw2f09c9rQZo76wl6fQeRDfGV4SP u08BFjw5aS43h8pRSvLzAmxVcFRlGWos5uP+MFqAIYwySavxtvqBmwsWr22MIoG0b PAKV7Vynz4GwQiXoBPrcWtRqUlKGetXHeihdyzZTI843HlPqqXw6mJEJtat/OZeO9 1lkAj0AZLC8KEeiwTVwof7YoyMZSdIGcuJw7gS5DXCFUW1jNgt/4w/hQksHuZfybe VQl7qRJnF569j2Y4dg== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from openwrt ([94.31.70.81]) by mail.gmx.net (mrgmx104 [212.227.17.168]) with ESMTPSA (Nemesis) id 1Mo6ux-1tmPvb00a3-00kDqJ; Fri, 04 Oct 2024 21:57:16 +0200 From: Markus Stockhausen To: linux-phy@lists.infradead.org, chris.packham@alliedtelesis.co.nz Cc: Markus Stockhausen Subject: [PATCH 2/4] phy: Realtek Otto SerDes: add driver source Date: Fri, 4 Oct 2024 15:56:08 -0400 Message-ID: <20241004195712.1891488-3-markus.stockhausen@gmx.de> X-Mailer: git-send-email 2.46.2 In-Reply-To: <20241004195712.1891488-1-markus.stockhausen@gmx.de> References: <20241004195712.1891488-1-markus.stockhausen@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:F5P5pbwCGeah2h5HeJr/LoJpE2yuCxk3uvn0IN2hI5KlqKs5qGH d0DhHv6vpzbbos7lniwRNFETZU7fBeav4v5i8hRVnGdkcBLDzmPXS5myDUg8qPSJ6KTKAFs qKO1Uobd3hcxibgTCnNvhTuTrD1FnqeqgezyoDddUVrAEmntp0D5b7wiDXVT5jL3Ln6iSXE 6rKSRqOIrL8i9esGAsPww== UI-OutboundReport: notjunk:1;M01:P0:nx7OjdBY7gw=;Sjn3ZGKCUFJiV0ySqtPY0voo+Y3 zGUSSBlJi2epuLbF9sVSVYpnFp4tR8eQgoW+o64j4285P5o2s3NnN/RzNbtUXcnDsHsNQH+PO 0MbjySUN0rQpOD/IOecp53viRQvM43apZnV+VIBz8KItPMYWJ+M4Kvu7r0+2dVFP7vlD5nrBc jvCzIJxkJznV01QPk9y9bSBvSS50JJ3I/FEKJp/KyTiXlZVkOFFViMDHs26aTWvKa3KsKyNDX Hb+HVEK55fzKQvkkB/LSP81AqLdzDWoGCA2fMs8euG92xHekVIKHxcZaZgVRn7Y2q+Ay2dNiz kXnDl5mfxFohO6OvkwAYWW/UAV4Ucw0FSX0zQ4OF4+eYLW2gvMbnQcKIT2xMiozGJg4F876xZ 9bu9mObUxHsPXWyCwHhFIqw3o/DWX7oMHvX54w+dQ3aayy10FDsc8mmAjjFAEpeBa+bcD6Cd6 AqVSK2cTEv1VqNcGZcaasjgjjqKs1qAPOPzVzC98t1fIoufTFrQbyl+6S2NjlCEPWykrdClcd TPhRo9HLxh3yZ7YYHhFW6SIlXdTLHGwWnQcdRzknP/ItYIJeqV0vUCVSMIZo2yugvzSsmIf/0 99Ib0e6QQhpYTw6G5CtUs/SifehG1Rg1tmvZRBj3eV8wOwc57qOA1TLuCbhteJCWBhsvXxyXE U9N7QryWr+pmoSb7YAQYZ18bIAbpKSEXKfKIwpjeShtRGcH63FzFRqV/Qn1sCERdA/Sjboq2E 1KHpaU9Qrpf6m+WEo8B6cCh3JLpaKtHwwGfMEtD6XE0cYXm7yo1BPcFlScwy1+Ihyv8zbLPx3 K29KIl31QBjFh+ZwGPSt/4Cg== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241004_205725_909173_E5CE8545 X-CRM114-Status: GOOD ( 22.88 ) X-BeenThere: linux-phy@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux Phy Mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-phy" Errors-To: linux-phy-bounces+linux-phy=archiver.kernel.org@lists.infradead.org This adds the source for the new Otto SerDes driver. --- drivers/phy/realtek/phy-rtl-otto-serdes.c | 1181 +++++++++++++++++++++ 1 file changed, 1181 insertions(+) create mode 100644 drivers/phy/realtek/phy-rtl-otto-serdes.c -- 2.44.0 diff --git a/drivers/phy/realtek/phy-rtl-otto-serdes.c b/drivers/phy/realtek/phy-rtl-otto-serdes.c new file mode 100644 index 000000000000..c3a2584a69d0 --- /dev/null +++ b/drivers/phy/realtek/phy-rtl-otto-serdes.c @@ -0,0 +1,1181 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Realtek RTL838x, RTL839x, RTL930x & RTL931x SerDes PHY driver + * Copyright (c) 2024 Markus Stockhausen + */ + +#include "phy-rtl-otto-serdes.h" + +/* + * The Otto platform has a lot of undocumented features and registers that configure + * the SerDes behaviour. Trying to include that here would clutter the driver. To + * provide maximum flexibility the driver can run register modification sequences + * during operation, E.g. when calling phy_reset() or phy_power_on(). These sequences + * need to be stored in the device tree. More documentation over there. + */ + +static const char *rtsds_events[RTSDS_EVENT_MAX + 1] = { + [RTSDS_EVENT_SETUP] = "cmd-setup", + [RTSDS_EVENT_INIT] = "cmd-init", + [RTSDS_EVENT_POWER_ON] = "cmd-power-on", + [RTSDS_EVENT_PRE_SET_MODE] = "cmd-pre-set-mode", + [RTSDS_EVENT_POST_SET_MODE] = "cmd-post-set-mode", + [RTSDS_EVENT_PRE_RESET] = "cmd-pre-reset", + [RTSDS_EVENT_POST_RESET] = "cmd-post-reset", + [RTSDS_EVENT_PRE_POWER_OFF] = "cmd-pre-power-off", + [RTSDS_EVENT_POST_POWER_OFF] = "cmd-post-power-off", +}; + +static void rtsds_load_events(struct rtsds_ctrl *ctrl) +{ + int i, elems, sz = sizeof(struct rtsds_seq); + + for (i = 0; i <= RTSDS_EVENT_MAX; i++) { + elems = of_property_count_u16_elems(ctrl->dev->of_node ,rtsds_events[i]); + if (elems <= 0) + continue; + + if ((elems * sizeof(u16)) % sz) { + dev_err(ctrl->dev, "ignore sequence %s (incomplete data)\n", rtsds_events[i]); + continue; + } + + /* alloc one more element to provide stop marker in case it is missing in dt */ + ctrl->sequence[i] = devm_kzalloc(ctrl->dev, elems * sizeof(u16) + sz, GFP_KERNEL); + if (!ctrl->sequence[i]) { + dev_err(ctrl->dev, "ignore sequence %s (allocation failed)\n", rtsds_events[i]); + continue; + } + + if (of_property_read_u16_array(ctrl->dev->of_node, rtsds_events[i], + (u16 *)ctrl->sequence[i], elems)) { + dev_err(ctrl->dev, "ignore sequence %s (DT load failed)\n", rtsds_events[i]); + kfree(ctrl->sequence[i]); + ctrl->sequence[i] = NULL; + continue; + } + } +} + +static int rtsds_run_event(struct rtsds_ctrl *ctrl, u32 sid, int evt) +{ + struct rtsds_seq *seq; + int ret, step = 1, delay = 0; + + if (evt > RTSDS_EVENT_MAX || sid > ctrl->conf->max_sds) + return -EINVAL; + + seq = ctrl->sequence[evt]; + + if (!seq) + return 0; + + while (seq->action != RTSDS_SEQ_STOP) { + if ((seq->action == RTSDS_SEQ_WAIT) && (seq->ports & BIT(sid))) + delay = seq->val; + + if (delay) + usleep_range(delay << 10, (delay << 10) + 1000); + + if ((seq->action == RTSDS_SEQ_MASK) && (seq->ports & BIT(sid))) { + ret = ctrl->conf->mask(ctrl, sid, seq->page, + seq->reg, seq->val, seq->mask); + + if (ret) { + dev_err(ctrl->dev, "sequence %s failed at step %d", rtsds_events[evt], step); + return -EIO; + } + } + + seq++; + step++; + } + + return 0; +} + +static int rtsds_hwmode_to_phymode(struct rtsds_ctrl *ctrl, int hwmode) +{ + for (int m = 0; m < PHY_INTERFACE_MODE_MAX; m++) + if (ctrl->conf->mode_map[m] == hwmode) + return m; + + return PHY_INTERFACE_MODE_MAX; +} + +static void rtsds_83xx_soft_reset(struct rtsds_ctrl *ctrl, u32 sidlo, u32 sidhi, int usec) +{ + for (u32 sid = sidlo; sid <= sidhi; sid++) + ctrl->conf->mask(ctrl, sid, 0x00, 0x03, 0x7146, 0xffff); + usleep_range(usec, usec + 1000); + for (u32 sid = sidlo; sid <= sidhi; sid++) + ctrl->conf->mask(ctrl, sid, 0x00, 0x03, 0x7106, 0xffff); +} + +/* + * The RTL838x has 6 SerDes. The 16 bit registers start at 0xbb00e780 and are mapped + * directly into 32 bit memory addresses. High 16 bits are always empty. Quite confusing + * but the register ranges are cluttered and contain holes. + */ + +static int rtsds_838x_offset(u32 sid, u32 page, u32 reg) +{ + if (page == 0 || page == 3) + return (sid << 9) + (page << 7) + (reg << 2); + else + return 0xb80 + (sid << 8) + (page << 7) + (reg << 2); +} + +static int rtsds_838x_read(struct rtsds_ctrl *ctrl, u32 sid, u32 page, u32 reg) +{ + int offs; + + if (sid > RTSDS_838X_MAX_SDS || page > RTSDS_838X_MAX_PAGE || reg > 31) + return -EINVAL; + + offs = rtsds_838x_offset(sid, page, reg); + + /* read twice for link status latch */ + if (page == 2 && reg == 1) + ioread32(ctrl->base + offs); + + return ioread32(ctrl->base + offs); +} + +static int rtsds_838x_mask(struct rtsds_ctrl *ctrl, u32 sid, u32 page, u32 reg, u32 val, u32 mask) +{ + int offs; + + if (sid > RTSDS_838X_MAX_SDS || page > RTSDS_838X_MAX_PAGE || reg > 31) + return -EINVAL; + + offs = rtsds_838x_offset(sid, page, reg); + + /* read twice for link status latch */ + if (page == 2 && reg == 1) + ioread32(ctrl->base + offs); + + iomask32(mask, val, ctrl->base + offs); + + return 0; +} + +static int rtsds_838x_reset(struct rtsds_ctrl *ctrl, u32 sid) +{ + if (sid > RTSDS_838X_MAX_SDS) + return -EINVAL; + + /* RX reset */ + rtsds_838x_mask(ctrl, sid, 0x01, 0x09, 0x0200, 0x0200); + rtsds_838x_mask(ctrl, sid, 0x01, 0x09, 0x0000, 0x0200); + + /* CMU reset */ + rtsds_838x_mask(ctrl, sid, 0x01, 0x00, 0x4040, 0xffff); + rtsds_838x_mask(ctrl, sid, 0x01, 0x00, 0x4740, 0xffff); + rtsds_838x_mask(ctrl, sid, 0x01, 0x00, 0x47c0, 0xffff); + rtsds_838x_mask(ctrl, sid, 0x01, 0x00, 0x4000, 0xffff); + + rtsds_83xx_soft_reset(ctrl, sid, sid, 1000); + + /* RX/TX reset */ + rtsds_838x_mask(ctrl, sid, 0x00, 0x00, 0x0400, 0xffff); + rtsds_838x_mask(ctrl, sid, 0x00, 0x00, 0x0403, 0xffff); + + return 0; +} + +static int rtsds_838x_set_mode(struct rtsds_ctrl *ctrl, u32 sid, int combomode) +{ + int shift, mode = RTSDS_MODE(combomode), submode = RTSDS_SUBMODE(combomode); + + if (sid > RTSDS_838X_MAX_SDS) + return -EINVAL; + + if (sid == 4 || sid == 5) { + shift = (sid - 4) * 3; + iomask32(0x7 << shift, (submode & 0x7) << shift, RTSDS_838X_INT_MODE_CTRL); + } + + shift = 25 - sid * 5; + iomask32(0x1f << shift, (mode & 0x1f) << shift, RTSDS_838X_SDS_MODE_SEL); + + return 0; +} + +static int rtsds_838x_get_mode(struct rtsds_ctrl *ctrl, u32 sid) +{ + int shift, mode, submode = 0; + + if (sid < 0 || sid > RTSDS_838X_MAX_SDS) + return -EINVAL; + + if (sid == 4 || sid == 5) { + shift = (sid - 4) * 3; + submode = (ioread32(RTSDS_838X_INT_MODE_CTRL) >> shift) & 0x7; + } + + shift = 25 - sid * 5; + mode = (ioread32(RTSDS_838X_SDS_MODE_SEL) >> shift) & 0x1f; + + return RTSDS_COMBOMODE(mode, submode); +} + +/* + * The RLT839x has 14 SerDes starting at 0xbb00a000. 0-7, 10, 11 are 5GBit, 8, 9, 12, 13 + * are 10GBit. Two adjacent SerDes are tightly coupled and share a 1024 bytes register area. + * Per 32 bit address two registers are stored. The first register is stored in the lower + * 2 bytes ("on the right" due to big endian) and the second register in the upper 2 bytes. + * We know the following register areas: + * + * - XSG0 (4 pages @ offset 0x000): for even SerDes + * - XSG1 (4 pages @ offset 0x100): for odd SerDes + * - TGRX (4 pages @ offset 0x200): for even 10G SerDes + * - ANA_RG (2 pages @ offset 0x300): for even 5G SerDes + * - ANA_RG (2 pages @ offset 0x380): for odd 5G SerDes + * - ANA_TG (2 pages @ offset 0x300): for even 10G SerDes + * - ANA_TG (2 pages @ offset 0x380): for odd 10G SerDes + * + * The most consistent mapping we can achieve that aligns to the RTL93xx devices is: + * + * even 5G SerDes odd 5G SerDes even 10G SerDes odd 10G SerDes + * Page 0: XSG0/0 XSG1/0 XSG0/0 XSG1/0 + * Page 1: XSG0/1 XSG1/1 XSG0/1 XSG1/1 + * Page 2: XSG0/2 XSG1/2 XSG0/2 XSG1/2 + * Page 3: XSG0/3 XSG1/3 XSG0/3 XSG1/3 + * Page 4: TGRX/0 + * Page 5: TGRX/1 + * Page 6: TGRX/2 + * Page 7: TGRX/3 + * Page 8: ANA_RG ANA_RG + * Page 9: ANA_RG_EXT ANA_RG_EXT + * Page 10: ANA_TG ANA_TG + * Page 11: ANA_TG_EXT ANA_TG_EXT + */ + +static int rtsds_839x_offset(u32 sid, u32 page, u32 reg) +{ + int offs = ((sid & 0xfe) << 9) + ((reg & 0xfe) << 1); + + if (page < 4) { + offs += ((sid & 1) << 8) + (page << 6); + } else if (page < 8) { + if (sid != 8 && sid != 12) + return -1; + offs += 0x100 + (page << 6); + } else if (page < 10) { + if (sid == 8 || sid == 9 || sid == 12 || sid == 13) + return -1; + offs += 0x100 + ((sid & 1) << 7) + (page << 6); + } else { + if (sid != 8 && sid != 9 && sid != 12 && sid != 13) + return -1; + offs += 0x100 + ((sid & 1) << 7) + ((page - 2) << 6); + } + + return offs; +} + +static int rtsds_839x_read(struct rtsds_ctrl *ctrl, u32 sid, u32 page, u32 reg) +{ + int offs, shift = (reg << 4) & 0x10; + + if (sid > RTSDS_839X_MAX_SDS || page > RTSDS_839X_MAX_PAGE || reg > 31) + return -EINVAL; + + offs = rtsds_839x_offset(sid, page, reg); + if (offs < 0) + return 0; + + /* read twice for link status latch */ + if (page == 2 && reg == 1) + ioread32(ctrl->base + offs); + + return (ioread32(ctrl->base + offs) >> shift) & 0xffff; +} + +static int rtsds_839x_mask(struct rtsds_ctrl *ctrl, u32 sid, u32 page, u32 reg, u32 val, u32 mask) +{ + int oldval, offs = ((sid & 0xfe) << 9) + ((reg & 0xfe) << 1); + + if (sid > RTSDS_839X_MAX_SDS || page > RTSDS_839X_MAX_PAGE || reg > 31) + return -EINVAL; + + offs = rtsds_839x_offset(sid, page, reg); + if (offs < 0) + return 0; + + /* read twice for link status latch */ + if (page == 2 && reg == 1) + ioread32(ctrl->base + offs); + + oldval = ioread32(ctrl->base + offs); + val = reg & 1 ? (oldval & ~(mask << 16)) | (val << 16) : (oldval & ~mask) | val; + iowrite32(val, ctrl->base + offs); + + return 0; +} + +static int rtsds_839x_set_mode(struct rtsds_ctrl *ctrl, u32 sid, int combomode) +{ + int shift = (sid & 7) << 2, offs = (sid >> 1) & ~3; + int mode = RTSDS_MODE(combomode), submode = RTSDS_SUBMODE(combomode); + + if (sid > RTSDS_839X_MAX_SDS) + return -EINVAL; + + rtsds_839x_mask(ctrl, sid, 0, 4, (submode << 12) & 0xf000, 0xf000); + iomask32(0xf << shift, (mode & 0xf) << shift, RTSDS_839X_MAC_SERDES_IF_CTRL + offs); + + return 0; +} + +static int rtsds_839x_get_mode(struct rtsds_ctrl *ctrl, u32 sid) +{ + int mode, submode, shift = (sid & 7) << 2, offs = (sid >> 1) & ~3; + + if (sid > RTSDS_839X_MAX_SDS) + return -EINVAL; + + submode = (rtsds_839x_read(ctrl, sid, 0, 4) >> 12) & 0xf; + mode = (ioread32(RTSDS_839X_MAC_SERDES_IF_CTRL + offs) >> shift) & 0xf; + + return RTSDS_COMBOMODE(mode, submode); +} + +static int rtsds_839x_reset(struct rtsds_ctrl *ctrl, u32 sid) +{ + int lo = sid & ~1, hi = sid | 1; + + if (sid > RTSDS_839X_MAX_SDS) + return -EINVAL; + + /* + * A reset basically consists of two steps. First a clock (CMU) reset and a + * digital soft reset afterwards. Some of the CMU registers are shared on + * adjacent SerDes so as of now we can only perform a reset on a pair. + */ + + if (lo < 8 || lo == 10) { + rtsds_839x_mask(ctrl, hi, 0x09, 0x01, 0x0050, 0xffff); + rtsds_839x_mask(ctrl, hi, 0x09, 0x01, 0x00f0, 0xffff); + rtsds_839x_mask(ctrl, hi, 0x09, 0x01, 0x0000, 0xffff); + rtsds_839x_mask(ctrl, lo, 0x08, 0x14, 0x0000, 0x0001); + rtsds_839x_mask(ctrl, lo, 0x08, 0x14, 0x0200, 0x0200); + usleep_range(100000, 101000); + rtsds_839x_mask(ctrl, lo, 0x08, 0x14, 0x0000, 0x0200); + } else { + rtsds_839x_mask(ctrl, lo, 0x0a, 0x10, 0x0000, 0x0008); + rtsds_839x_mask(ctrl, lo, 0x0b, 0x00, 0x8000, 0x8000); + usleep_range(100000, 101000); + rtsds_839x_mask(ctrl, lo, 0x0b, 0x00, 0x0000, 0x8000); + } + + rtsds_83xx_soft_reset(ctrl, lo, hi, 100000); + + return 0; +} + +/* + * The RTL930x family has 12 SerdDes. They are accessed through two IO registers + * at 0xbb0003b0 which simulate commands to an internal MDIO bus. From the current + * observation there are 3 types of SerDes: + * + * - SerDes 0,1 are of unknown type + * - SerDes 2-9 are USXGMII capabable with either quad or single configuration + * - SerDes 10-11 are of unknown type + */ + +static int rtsds_930x_read(struct rtsds_ctrl *ctrl, u32 sid, u32 page, u32 reg) +{ + int cnt = 100, cmd = (sid << 2) | (page << 7) | (reg << 13) | 1; + + if (sid > RTSDS_930X_MAX_SDS || page > RTSDS_930X_MAX_PAGE || reg > 31) + return -EINVAL; + + iowrite32(cmd, ctrl->base); + + while (--cnt && (ioread32(ctrl->base) & 1)) + usleep_range(50, 60); + + return cnt ? ioread32(ctrl->base + 4) & 0xffff : -EIO; +} + +static int rtsds_930x_mask(struct rtsds_ctrl *ctrl, u32 sid, u32 page, u32 reg, u32 val, u32 mask) +{ + int oldval, cnt = 100, cmd = (sid << 2) | (page << 7) | (reg << 13) | 3; + + if (sid > RTSDS_930X_MAX_SDS || page > RTSDS_930X_MAX_PAGE || reg > 31) + return -EINVAL; + + if (mask != 0xffff) { + oldval = rtsds_930x_read(ctrl, sid, page, reg); + if (oldval < 0) + return -EIO; + oldval &= ~mask; + val |= oldval; + } + + iowrite32(val, ctrl->base + 4); + iowrite32(cmd, ctrl->base); + + while (--cnt && (ioread32(ctrl->base) & 1)) + usleep_range(50, 60); + + return cnt ? 0 : - EIO; +} + +static void rtsds_930x_mode_offset(int sid, + void __iomem __force **modereg, int *modeshift, + void __iomem __force **subreg, int *subshift) +{ + if (sid > 3) { + *subreg = RTSDS_930X_SDS_SUBMODE_CTRL1; + *subshift = (sid - 4) * 5; + } else { + *subreg = RTSDS_930X_SDS_SUBMODE_CTRL0; + *subshift = (sid - 2) * 5; + } + + if (sid < 4) { + *modeshift = sid * 6; + *modereg = RTSDS_930X_SDS_MODE_SEL_0; + } else if (sid < 8) { + *modeshift = (sid - 4) * 6; + *modereg = RTSDS_930X_SDS_MODE_SEL_1; + } else if (sid < 10) { + *modeshift = (sid - 8) * 6; + *modereg = RTSDS_930X_SDS_MODE_SEL_2; + } else { + *modeshift = (sid - 10) * 6; + *modereg = RTSDS_930X_SDS_MODE_SEL_3; + } +} + +static int rtsds_930x_set_mode(struct rtsds_ctrl *ctrl, u32 sid, int combomode) +{ + int modeshift, subshift; + int mode = RTSDS_MODE(combomode); + int submode = RTSDS_SUBMODE(combomode); + void __iomem __force *modereg; + void __iomem __force *subreg; + + if (sid > RTSDS_930X_MAX_SDS) + return -EINVAL; + + rtsds_930x_mode_offset(sid, &modereg, &modeshift, &subreg, &subshift); + if (sid >= 2 || sid <= 9) + iomask32(0x1f << subshift, (submode & 0x1f) << subshift, subreg); + iomask32(0x1f << modeshift, (mode & 0x1f) << modeshift, modereg); + + return 0; +} + +static int rtsds_930x_get_mode(struct rtsds_ctrl *ctrl, u32 sid) +{ + int modeshift, subshift, mode, submode = 0; + void __iomem __force *modereg; + void __iomem __force *subreg; + + if (sid > RTSDS_930X_MAX_SDS) + return -EINVAL; + + rtsds_930x_mode_offset(sid, &modereg, &modeshift, &subreg, &subshift); + if (sid >= 2 || sid <= 9) + submode = (ioread32(subreg) >> subshift) & 0x1f; + mode = ioread32(modereg) >> modeshift & 0x1f; + + return RTSDS_COMBOMODE(mode, submode); +} + +static int rtsds_930x_reset(struct rtsds_ctrl *ctrl, u32 sid) +{ + int modecur, modeoff = ctrl->conf->mode_map[PHY_INTERFACE_MODE_NA]; + + if (sid > RTSDS_930X_MAX_SDS) + return -EINVAL; + + modecur = rtsds_930x_get_mode(ctrl, sid); + + /* It is enough to power off SerDes and set to old mode again */ + if (modecur != modeoff) { + rtsds_930x_set_mode(ctrl, sid, modeoff); + rtsds_930x_set_mode(ctrl, sid, modecur); + } + + return 0; +} + +/* + * The RTL931x family has 14 "frontend" SerDes that are magically cascaded. All + * operations (e.g. reset) work on this frontend view while their registers are + * distributed over a total of 32 background SerDes. Two types of SerDes have been + * identified: + * + * A "even" SerDes with numbers 0, 1, 2, 4, 6, 8, 10, 12 works on on two background + * SerDes. 64 analog und 64 XGMII data pages are coming from a first background + * SerDes while another 64 XGMII pages are served from a second SerDes. + * + * The "odd" SerDes with numbers 3, 5, 7, 9, 11 & 13 SerDes consist of a total of 3 + * background SerDes (one analog and two XGMII) each with an own page/register set. + * + * As strange as this reads try to get this aligned and mix pages as follows + * + * frontend page "even" frontend SerDes "odd" frontend SerDes + * page 0-63 (analog): back sid page 0-63 back sid page 0-63 + * page 64-127 (XGMII1): back sid page 0-63 back sid +1 page 0-63 + * page 128-191 (XGMII2): back sid +1 page 0-63 back sid +2 page 0-63 + */ + +static int rtsds_931x_backsid(u32 sid, u32 page) +{ + int map[] = {0, 1, 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23}; + int backsid = map[sid]; + + if ((sid & 1) && (sid != 1)) + backsid += (page >> 6); /* distribute "odd" to 3 background SerDes */ + else if (page >= 128) + backsid += 1; /* "distribute "even" to 2 background SerDes */ + + return backsid; +} + +static int rtsds_931x_read(struct rtsds_ctrl *ctrl, u32 sid, u32 page, u32 reg) +{ + int backsid, cmd, cnt = 100; + + if (sid > RTSDS_931X_MAX_SDS || page > RTSDS_931X_MAX_PAGE || reg > 31) + return -EINVAL; + + backsid = rtsds_931x_backsid(sid, page); + cmd = (backsid << 2) | ((page & 0x3f) << 7) | (reg << 13) | 1; + + iowrite32(cmd, ctrl->base); + while (--cnt && (ioread32(ctrl->base) & 1)) + usleep_range(50, 60); + + return cnt ? ioread32(ctrl->base + 4) & 0xffff : -EIO; +} + +static int rtsds_931x_mask(struct rtsds_ctrl *ctrl, u32 sid, u32 page, + u32 reg, u32 val, u32 mask) +{ + int backsid, cmd, oldval, cnt = 100; + + if (sid > RTSDS_931X_MAX_SDS || page > RTSDS_931X_MAX_PAGE || reg > 31) + return -EINVAL; + + backsid = rtsds_931x_backsid(sid, page); + cmd = (backsid << 2) | ((page & 0x3f) << 7) | (reg << 13) | 3; + + if (mask != 0xffff) { + oldval = rtsds_931x_read(ctrl, sid, page, reg); + if (oldval < 0) + return -EIO; + oldval &= ~mask; + val |= oldval; + } + + iowrite32(val, ctrl->base + 4); + iowrite32(cmd, ctrl->base); + while (--cnt && (ioread32(ctrl->base) & 1)) + usleep_range(50, 60); + + return cnt ? 0 : - EIO; +} + +static int rtsds_931x_set_mode(struct rtsds_ctrl *ctrl, u32 sid, int combomode) +{ + int shift = (sid & 3) << 3, offs = sid & ~3; + int mode = RTSDS_MODE(combomode); + int submode = RTSDS_SUBMODE(combomode); + + if (sid > RTSDS_931X_MAX_SDS) + return -EINVAL; + + rtsds_931x_mask(ctrl, sid, 31, 9, (submode & 0x3f << 6), 0x0fc0); + iomask32(0xff << shift, ((mode | RTSDS_931X_SDS_FORCE_SETUP) & 0xff) << shift, + RTSDS_931X_SERDES_MODE_CTRL + offs); + + return 0; +} + +static int rtsds_931x_get_mode(struct rtsds_ctrl *ctrl, u32 sid) +{ + int mode, submode, shift = (sid & 3) << 3, offs = sid & ~3; + + if (sid > RTSDS_931X_MAX_SDS) + return -EINVAL; + + submode = (rtsds_931x_read(ctrl, sid, 31, 9) >> 6) & 0x3f; + mode = (ioread32(RTSDS_931X_SERDES_MODE_CTRL + offs) >> shift) & 0x1f; + + return RTSDS_COMBOMODE(mode, submode); +} + +static int rtsds_931x_reset(struct rtsds_ctrl *ctrl, u32 sid) +{ + int pwr, modecur, modeoff = ctrl->conf->mode_map[PHY_INTERFACE_MODE_NA]; + + if (sid > RTSDS_931X_MAX_SDS) + return -EINVAL; + + modecur = rtsds_931x_get_mode(ctrl, sid); + + if (modecur != modeoff) { + /* reset with mode switch cycle while being powered off */ + pwr = ioread32(RTSDS_931X_PS_SERDES_OFF_MODE_CTRL); + iowrite32(pwr | BIT(sid), RTSDS_931X_PS_SERDES_OFF_MODE_CTRL); + rtsds_931x_set_mode(ctrl, sid, modeoff); + rtsds_931x_set_mode(ctrl, sid, modecur); + iowrite32(pwr, RTSDS_931X_PS_SERDES_OFF_MODE_CTRL); + } + + return 0; +} + +int rtsds_read(struct phy *phy, u32 page, u32 reg) +{ + struct rtsds_macro *macro = phy_get_drvdata(phy); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 sid = macro->sid; + + return ctrl->conf->read(ctrl, sid, page, reg); +} + +int rtsds_mask(struct phy *phy, u32 page, u32 reg, u32 val, u32 mask) +{ + struct rtsds_macro *macro = phy_get_drvdata(phy); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 sid = macro->sid; + + if (!(ctrl->sds_mask & BIT(sid))) + return -EACCES; + + return ctrl->conf->mask(ctrl, sid, page, reg, val, mask); +} + +int rtsds_write(struct phy *phy, u32 page, u32 reg, u32 val) +{ + return rtsds_mask(phy, page, reg, val, 0xffff); +} + +static int rtsds_phy_init(struct phy *phy) +{ + struct rtsds_macro *macro = phy_get_drvdata(phy); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 sid = macro->sid; + int ret; + + if (!(ctrl->sds_mask & BIT(sid))) + return 0; + + mutex_lock(&ctrl->lock); + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_INIT); + mutex_unlock(&ctrl->lock); + + if (ret) + dev_err(ctrl->dev, "init failed for SerDes %d\n", sid); + + return ret; +} + +static int rtsds_phy_power_on(struct phy *phy) +{ + struct rtsds_macro *macro = phy_get_drvdata(phy); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 sid = macro->sid; + int ret; + + if (!(ctrl->sds_mask & BIT(sid))) + return 0; + + mutex_lock(&ctrl->lock); + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_POWER_ON); + mutex_unlock(&ctrl->lock); + + if (ret) + dev_err(ctrl->dev, "power on failed for SerDes %d\n", sid); + + return ret; +} + +static int rtsds_phy_power_off(struct phy *phy) +{ + struct rtsds_macro *macro = phy_get_drvdata(phy); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 sid = macro->sid; + int ret; + + if (!(ctrl->sds_mask & BIT(sid))) + return 0; + + mutex_lock(&ctrl->lock); + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_PRE_POWER_OFF); + if (!ret) + ret = ctrl->conf->set_mode(ctrl, sid, ctrl->conf->mode_map[PHY_INTERFACE_MODE_NA]); + if (!ret) + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_POST_POWER_OFF); + mutex_unlock(&ctrl->lock); + + if (ret) + dev_err(ctrl->dev, "power off failed for SerDes %d\n", sid); + + return ret; +} + +static int rtsds_phy_set_mode_int(struct rtsds_ctrl *ctrl, u32 sid, int phymode, int hwmode) +{ + int ret; + + mutex_lock(&ctrl->lock); + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_PRE_SET_MODE); + if (!ret) + ret = ctrl->conf->set_mode(ctrl, sid, hwmode); + if (!ret) { + ctrl->sds[sid].mode = phymode; + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_POST_SET_MODE); + } + mutex_unlock(&ctrl->lock); + + if (ret) + dev_err(ctrl->dev, "set mode failed for SerDes %d\n", sid); + + return ret; +} + +static int rtsds_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct rtsds_macro *macro = phy_get_drvdata(phy); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 sid = macro->sid; + + if (!(ctrl->sds_mask & BIT(sid))) + return 0; + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + return rtsds_phy_set_mode_int(ctrl, sid, submode, ctrl->conf->mode_map[submode]); +} + +static int rtsds_phy_reset_int(struct rtsds_ctrl *ctrl, u32 sid) +{ + int ret; + + mutex_lock(&ctrl->lock); + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_PRE_RESET); + if (!ret) + ret = ctrl->conf->reset(ctrl, sid); + if (!ret) + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_POST_RESET); + mutex_unlock(&ctrl->lock); + + if (ret) + dev_err(ctrl->dev, "reset failed for SerDes %d\n", sid); + + return ret; +} + +static int rtsds_phy_reset(struct phy *phy) +{ + struct rtsds_macro *macro = phy_get_drvdata(phy); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 sid = macro->sid; + + if (!(ctrl->sds_mask & BIT(sid))) + return 0; + + return rtsds_phy_reset_int(ctrl, sid); +} + +static const struct phy_ops rtsds_phy_ops = { + .init = rtsds_phy_init, + .power_on = rtsds_phy_power_on, + .power_off = rtsds_phy_power_off, + .reset = rtsds_phy_reset, + .set_mode = rtsds_phy_set_mode, + .owner = THIS_MODULE, +}; + +/* + * The SerDes offer a lot of magic that sill needs to be uncovered. To help further + * development provide some basic debugging about registers, modes and polarity. The + * mode can be changed on the fly and executes the normal setter including events. + */ + +#ifdef CONFIG_DEBUG_FS +static const char *rtsds_page_name[RTSDS_PAGE_NAMES] = { + [0] = "SDS", [1] = "SDS_EXT", + [2] = "FIB", [3] = "FIB_EXT", + [4] = "DTE", [5] = "DTE_EXT", + [6] = "TGX", [7] = "TGX_EXT", + [8] = "ANA_RG", [9] = "ANA_RG_EXT", + [10] = "ANA_TG", [11] = "ANA_TG_EXT", + [31] = "ANA_WDIG", + [32] = "ANA_MISC", [33] = "ANA_COM", + [34] = "ANA_SP", [35] = "ANA_SP_EXT", + [36] = "ANA_1G", [37] = "ANA_1G_EXT", + [38] = "ANA_2G", [39] = "ANA_2G_EXT", + [40] = "ANA_3G", [41] = "ANA_3G_EXT", + [42] = "ANA_5G", [43] = "ANA_5G_EXT", + [44] = "ANA_6G", [45] = "ANA_6G_EXT", + [46] = "ANA_10G", [47] = "ANA_10G_EXT", +}; + +static ssize_t rtsds_dbg_mode_show(struct seq_file *seqf, void *unused) +{ + struct rtsds_macro *macro = dev_get_drvdata(seqf->private); + struct rtsds_ctrl *ctrl = macro->ctrl; + int mode, sid = macro->sid; + + mutex_lock(&ctrl->lock); + mode = ctrl->conf->get_mode(ctrl, sid); + mutex_unlock(&ctrl->lock); + + seq_printf(seqf, "hw mode: 0x%X\n", mode); + seq_printf(seqf, "phy mode: "); + + if (ctrl->sds[sid].mode == PHY_INTERFACE_MODE_NA) + seq_printf(seqf, "off\n"); + else + seq_printf(seqf, "%s\n", phy_modes(ctrl->sds[sid].mode)); + + return 0; +} + +static ssize_t rtsds_dbg_mode_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct seq_file *seqf = file->private_data; + struct rtsds_macro *macro = dev_get_drvdata(seqf->private); + struct rtsds_ctrl *ctrl = macro->ctrl; + int ret, hwmode, phymode, sid = macro->sid; + + ret = kstrtou32_from_user(userbuf, count, 10, &hwmode); + if (ret) + return ret; + + /* + * As we are still exploring the SerDes this debug function allows to set + * arbitrary modes into the SerDes. While this might confuse the internal + * driver handling it helps to avoid to rebuild & start from scratch for + * every test. + */ + phymode = rtsds_hwmode_to_phymode(ctrl, hwmode); + rtsds_phy_set_mode_int(ctrl, sid, phymode, hwmode); + + return count; +} +DEFINE_SHOW_STORE_ATTRIBUTE(rtsds_dbg_mode); + +static int rtsds_dbg_registers_show(struct seq_file *seqf, void *unused) +{ + struct rtsds_macro *macro = dev_get_drvdata(seqf->private); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 page, reg, sid = macro->sid; + + seq_printf(seqf, "%*s", 12 , ""); + for (int i = 0;i < 32; i++) + seq_printf(seqf, "%*d", 5, i); + + for (page = 0; page <= ctrl->conf->max_page; page++) { + if (page < RTSDS_PAGE_NAMES && rtsds_page_name[page]) + seq_printf(seqf, "\n%*s: ", -11, rtsds_page_name[page]); + else if (page == 64 || page == 128) + seq_printf(seqf, "\nXGMII_%d : ", page >> 6); + else + seq_printf(seqf, "\nPAGE_%03d : ", page); + for (reg = 0; reg < 32; reg++) + seq_printf(seqf, "%04X ", ctrl->conf->read(ctrl, sid, page, reg)); + } + seq_printf(seqf, "\n"); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rtsds_dbg_registers); + +static int rtsds_dbg_polarity_show(struct seq_file *seqf, void *unused) +{ + struct rtsds_macro *macro = dev_get_drvdata(seqf->private); + struct rtsds_ctrl *ctrl = macro->ctrl; + u32 reg, sid = macro->sid; + + reg = ctrl->conf->read(ctrl, sid, RTSDS_PAGE_SDS, 0); + + seq_printf(seqf, "tx polarity: "); + seq_printf(seqf, reg & RTSDS_INV_HSO ? "inverse" : "normal"); + seq_printf(seqf, "\nrx polarity: "); + seq_printf(seqf, reg & RTSDS_INV_HSI ? "inverse" : "normal"); + seq_printf(seqf, "\n"); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rtsds_dbg_polarity); + +static void rtsds_dbg_init(struct rtsds_ctrl *ctrl, u32 sid) +{ + debugfs_create_file("mode", 0600, ctrl->sds[sid].phy->debugfs, + &ctrl->sds[sid].phy->dev, &rtsds_dbg_mode_fops); + + debugfs_create_file("polarity", 0400, ctrl->sds[sid].phy->debugfs, + &ctrl->sds[sid].phy->dev, &rtsds_dbg_polarity_fops); + + debugfs_create_file("registers", 0400, ctrl->sds[sid].phy->debugfs, + &ctrl->sds[sid].phy->dev, &rtsds_dbg_registers_fops); +} +#endif /* CONFIG_DEBUG_FS */ + +static void rtsds_setup(struct rtsds_ctrl *ctrl) +{ + int hwmode, ret; + + for (u32 sid = 0; sid <= ctrl->conf->max_sds; sid++) { + if (ctrl->sds_mask & BIT(sid)) { + /* power off controlled SerDes */ + hwmode = ctrl->conf->mode_map[PHY_INTERFACE_MODE_NA]; + ret = ctrl->conf->set_mode(ctrl, sid, hwmode); + if (!ret) + ret = rtsds_run_event(ctrl, sid, RTSDS_EVENT_SETUP); + if (ret) + dev_err(ctrl->dev, "setup failed for SerDes %d\n", sid); + } + /* in any case sync back hardware status */ + hwmode = ctrl->conf->get_mode(ctrl, sid); + ctrl->sds[sid].mode = rtsds_hwmode_to_phymode(ctrl, hwmode); + } +} + +static struct phy *rtsds_simple_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct rtsds_ctrl *ctrl = dev_get_drvdata(dev); + int sid, sid2, min_port, max_port; + + /* + * Some Realtek Ethernet transceivers (e.g. RLT8218B) will be attached via a + * bonded 2x QSGMII link to two SerDes. Others (e.g. RTL8218D) allow to make + * use of single XGMII or dual QSGMII links. When a switch port tries to lookup + * the SerDes it is attached to we honour that by an enhanced mapping. We allow + * two possible configuration options. Standalone or linked to another. E.g. + * + * Single: port@24 { phys = <&serdes 4 -1 MinPort MaxPort>; }; + * Dual: port@24 { phys = <&serdes 4 5 MinPort MaxPort>; }; + * + * As we can only hand over a single phy this function will return the primary + * phy. The secondary phy can be identified later on by the link attribute in + * the controller structure. + */ + + if (args->args_count != 4) + return ERR_PTR(-EINVAL); + + sid = args->args[0]; + if (sid < 0 || sid > ctrl->conf->max_sds) + return ERR_PTR(-EINVAL); + + sid2 = args->args[1]; + if (sid2 < -1 || sid2 > ctrl->conf->max_sds) + return ERR_PTR(-EINVAL); + + /* + * Additionally to a linked SerDes also get the ports whose traffic is going + * through this SerDes. As of now we do not care much about that but later on + * it might be helpful. + */ + + min_port = args->args[2]; + if (min_port < 0) + return ERR_PTR(-EINVAL); + + max_port = args->args[3]; + if (max_port < min_port) + return ERR_PTR(-EINVAL); + + ctrl->sds[sid].link = sid2; + if (sid2 >= 0) + ctrl->sds[sid2].link = sid; + + ctrl->sds[sid].min_port = min_port; + ctrl->sds[sid].max_port = max_port; + + return ctrl->sds[sid].phy; +} + +static int rtsds_phy_create(struct rtsds_ctrl *ctrl, u32 sid) +{ + struct rtsds_macro *macro; + + ctrl->sds[sid].phy = devm_phy_create(ctrl->dev, NULL, &rtsds_phy_ops); + if (IS_ERR(ctrl->sds[sid].phy)) + return PTR_ERR(ctrl->sds[sid].phy); + + macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL); + if (!macro) + return -ENOMEM; + + macro->sid = sid; + macro->ctrl = ctrl; + phy_set_drvdata(ctrl->sds[sid].phy, macro); + + ctrl->sds[sid].link = -1; + ctrl->sds[sid].min_port = -1; + ctrl->sds[sid].max_port = -1; + +#ifdef CONFIG_DEBUG_FS + rtsds_dbg_init(ctrl, sid); +#endif + return 0; +} + +static int rtsds_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct rtsds_ctrl *ctrl; + int ret; + + if (!np) + return -EINVAL; + + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + ctrl->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ctrl->base)) { + dev_err(dev, "failed to map SerDes memory\n"); + return PTR_ERR(ctrl->base); + } + + ctrl->dev = dev; + ctrl->conf = (struct rtsds_conf *)of_device_get_match_data(dev); + + ret = of_property_read_u32(np, "controlled-ports", &ctrl->sds_mask); + if (ret) { + ctrl->sds_mask = 0; + dev_warn(dev, "property controlled-ports not found, switched to read-only mode\n"); + } + + for (u32 sid = 0; sid <= ctrl->conf->max_sds; sid++) { + ret = rtsds_phy_create(ctrl, sid); + if (ret) { + dev_err(dev, "failed to create PHY for SerDes %d\n", sid); + return ret; + } + } + + mutex_init(&ctrl->lock); + dev_set_drvdata(dev, ctrl); + provider = devm_of_phy_provider_register(dev, rtsds_simple_xlate); + + rtsds_load_events(ctrl); + rtsds_setup(ctrl); + + dev_info(dev, "initialized (%d SerDes, %d pages, 32 registers, mask 0x%04x)", + ctrl->conf->max_sds + 1, ctrl->conf->max_page + 1, ctrl->sds_mask); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct rtsds_conf rtsds_838x_conf = { + .max_sds = RTSDS_838X_MAX_SDS, + .max_page = RTSDS_838X_MAX_PAGE, + .mask = rtsds_838x_mask, + .read = rtsds_838x_read, + .reset = rtsds_838x_reset, + .set_mode = rtsds_838x_set_mode, + .get_mode = rtsds_838x_get_mode, + .mode_map = { + [PHY_INTERFACE_MODE_NA] = RTSDS_COMBOMODE(0, 0), + [PHY_INTERFACE_MODE_1000BASEX] = RTSDS_COMBOMODE(4, 1), /* SerDes 4, 5 only */ + [PHY_INTERFACE_MODE_100BASEX] = RTSDS_COMBOMODE(5, 1), /* SerDes 4, 5 only */ + [PHY_INTERFACE_MODE_QSGMII] = RTSDS_COMBOMODE(6, 0), + }, +}; + +static const struct rtsds_conf rtsds_839x_conf = { + .max_sds = RTSDS_839X_MAX_SDS, + .max_page = RTSDS_839X_MAX_PAGE, + .mask = rtsds_839x_mask, + .read = rtsds_839x_read, + .reset = rtsds_839x_reset, + .set_mode = rtsds_839x_set_mode, + .get_mode = rtsds_839x_get_mode, + .mode_map = { + [PHY_INTERFACE_MODE_NA] = RTSDS_COMBOMODE(0, 0), + [PHY_INTERFACE_MODE_10GBASER] = RTSDS_COMBOMODE(1, 0), /* SerDes 8, 12 only */ + [PHY_INTERFACE_MODE_1000BASEX] = RTSDS_COMBOMODE(7, 0), /* SerDes 12, 13 only */ + [PHY_INTERFACE_MODE_100BASEX] = RTSDS_COMBOMODE(8, 0), + [PHY_INTERFACE_MODE_QSGMII] = RTSDS_COMBOMODE(6, 0), + [PHY_INTERFACE_MODE_SGMII] = RTSDS_COMBOMODE(7, 5), /* SerDes 8, 12, 13 only */ + }, +}; + +static const struct rtsds_conf rtsds_930x_conf = { + .max_sds = RTSDS_930X_MAX_SDS, + .max_page = RTSDS_930X_MAX_PAGE, + .mask = rtsds_930x_mask, + .read = rtsds_930x_read, + .reset = rtsds_930x_reset, + .set_mode = rtsds_930x_set_mode, + .get_mode = rtsds_930x_get_mode, + .mode_map = { + [PHY_INTERFACE_MODE_NA] = RTSDS_COMBOMODE(31, 0), + [PHY_INTERFACE_MODE_10GBASER] = RTSDS_COMBOMODE(26, 0), + [PHY_INTERFACE_MODE_2500BASEX] = RTSDS_COMBOMODE(22, 0), + [PHY_INTERFACE_MODE_1000BASEX] = RTSDS_COMBOMODE(4, 0), + [PHY_INTERFACE_MODE_USXGMII] = RTSDS_COMBOMODE(13, 0), /* SerDes 2-9 only */ + [PHY_INTERFACE_MODE_QUSGMII] = RTSDS_COMBOMODE(13, 2), /* SerDes 2-9 only */ + [PHY_INTERFACE_MODE_QSGMII] = RTSDS_COMBOMODE(6, 0), + }, +}; + +static const struct rtsds_conf rtsds_931x_conf = { + .max_sds = RTSDS_931X_MAX_SDS, + .max_page = RTSDS_931X_MAX_PAGE, + .mask = rtsds_931x_mask, + .read = rtsds_931x_read, + .reset = rtsds_931x_reset, + .set_mode = rtsds_931x_set_mode, + .get_mode = rtsds_931x_get_mode, + .mode_map = { + [PHY_INTERFACE_MODE_NA] = RTSDS_COMBOMODE(31, 63), + [PHY_INTERFACE_MODE_10GBASER] = RTSDS_COMBOMODE(31, 53), + [PHY_INTERFACE_MODE_1000BASEX] = RTSDS_COMBOMODE(31, 57), /* 1G/10G auto */ + [PHY_INTERFACE_MODE_USXGMII] = RTSDS_COMBOMODE(13, 0), + [PHY_INTERFACE_MODE_XGMII] = RTSDS_COMBOMODE(16, 0), + [PHY_INTERFACE_MODE_QSGMII] = RTSDS_COMBOMODE(6, 0), + }, +}; + +static const struct of_device_id rtsds_compatible_ids[] = { + { .compatible = "realtek,rtl8380-serdes", + .data = &rtsds_838x_conf, + }, + { .compatible = "realtek,rtl8390-serdes", + .data = &rtsds_839x_conf, + }, + { .compatible = "realtek,rtl9300-serdes", + .data = &rtsds_930x_conf, + }, + { .compatible = "realtek,rtl9310-serdes", + .data = &rtsds_931x_conf, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtsds_compatible_ids); + +static struct platform_driver rtsds_platform_driver = { + .probe = rtsds_probe, + .driver = { + .name = "realtek,otto-serdes", + .of_match_table = of_match_ptr(rtsds_compatible_ids), + }, +}; + +module_platform_driver(rtsds_platform_driver); + +MODULE_AUTHOR("Markus Stockhausen "); +MODULE_DESCRIPTION("SerDes driver for Realtek RTL83xx, RTL93xx switch SoCs"); +MODULE_LICENSE("Dual MIT/GPL"); From patchwork Fri Oct 4 19:56:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Stockhausen X-Patchwork-Id: 13822991 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 E5D04CF885C for ; Fri, 4 Oct 2024 21:02:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Ria9wMnSPYBXJA/c1/nDS4/IeMULAir/h2EF3Kngb5k=; b=Fp/UmSuzp/F9QW xIZxnvnKjqpoEJSV7/L47zW4B7QtUHIcdNpXptWHTmcoOzUW9euJ849IFsLZR3/FOB2vp85PgK9mf 5bE4kaexC+egW2LWd6ie7FOZYa9MnvquJKHEGDYRldbpYXKqfLJ3C7/krUd2hD6PAOIxbK5R5tYkz W4VxoEUG/eHl7MSqQ/TkkVjO3cHRE5+zH3cUKZmTmtyCZiNEUs7ouOWfK4tZpluUUnTRNZMewMnQw GDjbums+/CsuPH6UgY6B/rPghBCczIIuCCGdGFIf/73nupAjs7R1TbSW9AvwGlhhJAu+kp+xlhxZC R+zY+bjWRBxlrx23NquA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1swpR8-0000000EE7y-2Zm7; Fri, 04 Oct 2024 21:02:06 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQp-0000000E13l-3UNW for linux-phy@bombadil.infradead.org; Fri, 04 Oct 2024 19:57:43 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Transfer-Encoding:MIME-Version :References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=BcN1ryMvOwwt2Dlfb4YKA2Wdv1MdcqwO9HnMeLljjgk=; b=UK2qvBilA50BBUzmEuKmI5+Bjm pwndLTf64/nl7zTIeR3MNnsc69Az322kaGxNfMSwn7A5KOlcFw8Kn70E86VDda3zP4D0ldpIl/tCc Be+Vs1eXPiOkTBD5zNaCJbLawMXi0M/SPGGs9Msy+QayRDnPT7WFJE6s0gsbN8Bw4ksI5aRyxJt2U CoLUTLPAT7dJ3W8/Ejzw8UCmgW3K2+NNqYtFZmu3Vc2mPMAEmJ/SQet+XF0Xa3Wjtsbj5HiY3u6mZ 0VrEo7SxfdCXgEGnL132e7uG7yxnvFt0iW1p0UbR/uHSG7456apC5jFIBW9ZXNz8Uh6pzJv6nQroc bwIuRS2A==; Received: from mout.gmx.net ([212.227.17.20]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQk-00000003vw0-1cVF for linux-phy@lists.infradead.org; Fri, 04 Oct 2024 19:57:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmx.de; s=s31663417; t=1728071836; x=1728676636; i=markus.stockhausen@gmx.de; bh=BcN1ryMvOwwt2Dlfb4YKA2Wdv1MdcqwO9HnMeLljjgk=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:Message-ID:In-Reply-To: References:MIME-Version:Content-Transfer-Encoding:cc: content-transfer-encoding:content-type:date:from:message-id: mime-version:reply-to:subject:to; b=E70nC+y9NespXruFfDzoKOIYaZ4IhE7bgBjsWI08XAaZcRto3wn6KfLXSK4AITnr BlrEcZ/MCc0PSv9EfUCezAVhW895ILj0JwVMgU4unW0lKPNs0D3K1CU+v5pOeyI2R DHZmzX8sCWXkdXW1bY/MDXC843St88LvNHnEGhGacIQ3fWZrlSUX9KChHDOka2O41 zPwpKwAUtuQ8xONUJl2yM/4HeDSrM8aqxxA21qtQsAtxWEJxRuo07oAGeVvrq4zNq xtBeHuVY1kKaa8OIE0eCJdbqMQHMzj4+nNBmOaQpHMTf9+JeWZm3SC0pcB7agxQh/ 4dSHpA1CQ42RJqq/IQ== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from openwrt ([94.31.70.81]) by mail.gmx.net (mrgmx104 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MdNY8-1tW9Ay0i3M-00eSXc; Fri, 04 Oct 2024 21:57:16 +0200 From: Markus Stockhausen To: linux-phy@lists.infradead.org, chris.packham@alliedtelesis.co.nz Cc: Markus Stockhausen Subject: [PATCH 3/4] phy: Realtek Otto SerDes: include driver Date: Fri, 4 Oct 2024 15:56:09 -0400 Message-ID: <20241004195712.1891488-4-markus.stockhausen@gmx.de> X-Mailer: git-send-email 2.46.2 In-Reply-To: <20241004195712.1891488-1-markus.stockhausen@gmx.de> References: <20241004195712.1891488-1-markus.stockhausen@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:QHc4NLpzmbXLlogmMNPyyDgcn4jHHopkniK7hviLrZoJRvYaN2D dIfi10FAZaHY76DN2PZwHWRPJejbZaXAKMp3Cb4ZQUl/oRG5hAnZbhDovbMR/NtELy+mfSK ARH7cU4mzhuOqPZ68yLhj+DyfhEyEB3AoaGEFEBHj+WiG6oZsc9syKzL11ZMJ6aeHufLSHE TLnc3TbBrjed5zYQ3mO6g== UI-OutboundReport: notjunk:1;M01:P0:c/cHjFOoleA=;oxBe3N4fdBwS+40Qa9mnTstj+s3 4o065wWSU9a2CuqLSweeRA8a9GoBAkSvY+cqwlsjuNoRBrpxn3stvaLKVprsqO4OxE0XDDzEl HpZxaL2u+mWO8n6ZibPm5zCCrw1NgTusFhL7xT1sWeQYt2cZSeVJ6TVrVf7PbS9OSg0zLdvG8 mrKkWPdNZLxGFOoAeufhdDCDmip32PDqyTzId6aW/CEZMvHEoUfGl6c44pCGOJ9yFyqp8CAHq KDrVS4h7rNCvlWy6aRQAsTrAZ2esFu+XqV9rkaI8FT285t8NKtX01QdcIuuLreeKcHRQDGv2A F/8X4+PAhSEglb5T7iKgimwHmARE3g+Uvmk6KApp1r09dz/KWRmcSRm+fg9+cTvPCBvgX87EY hPk1J6zzWZUeAIusE4eDWdFdRnbhIu4OAy8d9cqHJmG+y3gKFjMItcYBl4yZsmo2CeX+J2+PQ ZlRQ0pMjJ8K/9N/7MRHYAcICQLNPGlZyYYgcy9cv3CYQuRTbv+08v/tgM3nvaAGLXOrVgEM2E 3yVZkZp+ufNDCdpiZooEWtFxE8HL45102VKPDGaRzNj3ZxaIqCufgLLYXY2YDJ6VCcP7inLrL QDlrX4ja/hHZlcfiI7C/TJeCj+hw4DvSQ+3HtLk1ujvpnTwTk+SIKFuMHl6mJw10ZTXD1+hhX E2k2y2FL2W7ageubCZwyAA490L3dMlNhSZEsPriRJFcpGbmUDz1utrTcAPO0XJgI+anevFwvd 6OsoQCgYxixsaVFleD0br9SvPXNxqrmjvlaI/4owieFJ1mdr9w16/UomMR4erq/VvrUaVszsj 8cBH45/2PbZJa77JoYnq9mWQ== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241004_205739_209073_423CBF65 X-CRM114-Status: UNSURE ( 8.10 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-phy@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux Phy Mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-phy" Errors-To: linux-phy-bounces+linux-phy=archiver.kernel.org@lists.infradead.org Make the driver available in the build system. --- drivers/phy/realtek/Kconfig | 7 +++++++ drivers/phy/realtek/Makefile | 1 + 2 files changed, 8 insertions(+) -- 2.44.0 diff --git a/drivers/phy/realtek/Kconfig b/drivers/phy/realtek/Kconfig index 75ac7e7c31ae..2c711016952d 100644 --- a/drivers/phy/realtek/Kconfig +++ b/drivers/phy/realtek/Kconfig @@ -30,3 +30,10 @@ config PHY_RTK_RTD_USB3PHY of the parameters. endif # ARCH_REALTEK || COMPILE_TEST + +config PHY_REALTEK_OTTO_SERDES + tristate "SerDes driver for the Realtek Otto platform" + depends on OF + select GENERIC_PHY + help + Enable this for SerDes support in RTL83xx and RTL93xx switches. diff --git a/drivers/phy/realtek/Makefile b/drivers/phy/realtek/Makefile index ed7b47ff8a26..57e14961d851 100644 --- a/drivers/phy/realtek/Makefile +++ b/drivers/phy/realtek/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PHY_RTK_RTD_USB2PHY) += phy-rtk-usb2.o obj-$(CONFIG_PHY_RTK_RTD_USB3PHY) += phy-rtk-usb3.o +obj-$(CONFIG_PHY_REALTEK_OTTO_SERDES) += phy-rtl-otto-serdes.o From patchwork Fri Oct 4 19:56:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Stockhausen X-Patchwork-Id: 13822995 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 054E3CF885E for ; Fri, 4 Oct 2024 21:02:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=245AkTMe9F4qcB/PQFQKHsp+Y+i/qhtP7yNj2xJg/68=; b=bky2dvP80AJXCi wPEtM5sDirqv/qyjnDm3AiwQa5vaLWdQRNA047BVIR5TrkSMv82BnxtjPbpdg5EdC7kVKxclbhC8T y1bOfg7zEoyKNvq16YJEq+dSO5HuNEhTe25paMpA4rmjdsrJ1V4qYXP/GQbO5qYaGcEIFFEccQrfH mR6kMaxivO6gwcThlJalrpRLaeCte3juEHtszToQTCRlWQMBe9CkhQIjMZ2x48JDQvytuYxECQMWn FipuNwHzUN9TQx1g2GG3P2I8LlzhG0f/Qzwgpd5/W8yYWY6Ei6x+VVMgy0vDI+JsBzsYOQicxSasW leqbSTGsUVAopk838uoA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1swpR9-0000000EE9A-2qmY; Fri, 04 Oct 2024 21:02:07 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQq-0000000E13q-0Uq3 for linux-phy@bombadil.infradead.org; Fri, 04 Oct 2024 19:57:44 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Transfer-Encoding:MIME-Version :References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=ENOGBk8X+eUq87I8HTpA/2gVrXQahUsEx8TMjQAwQoo=; b=gkB9GErwabfj6cG6WLWIR0BS1c nrrBFBPqKQRXXzY0Z8AqNMFVS0O3ps92IJUyJkbSdK3CfVA7seX9GURQ7zAiEoDb+CiJFRxPjUgIf JE9yfSbvgveZhYGL+TJi2YRLxxwsyDNy4DOpKigbzpR+KUA08KkUyFTkOF8uFiA7tuVPbB5AO22nY iiy0J2r7GbljWpnYHSUJ4DMccGMW23zME+xGiYYNZO9TnXEkmguASPraVhVJxfTPQATzQjz6Ucfs/ sQT0Pa9HRLg2CZUHfIfIOYEIlxevLE/qLAchMZxwiTmZuHq5rveMdH0miAXZ/YPpRaDblwPmpCSiD aVn36JZw==; Received: from mout.gmx.net ([212.227.17.22]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1swoQl-00000003vw2-2g3W for linux-phy@lists.infradead.org; Fri, 04 Oct 2024 19:57:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmx.de; s=s31663417; t=1728071836; x=1728676636; i=markus.stockhausen@gmx.de; bh=ENOGBk8X+eUq87I8HTpA/2gVrXQahUsEx8TMjQAwQoo=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:Message-ID:In-Reply-To: References:MIME-Version:Content-Transfer-Encoding:cc: content-transfer-encoding:content-type:date:from:message-id: mime-version:reply-to:subject:to; b=t3C42UF2pkBWiq8MqF+839GSWwey6QYOVwvp7djQB63Ems76n9aqcWk0kzKh0YC+ JCklHxBO7KH8qj83lb+BfMcs8Rzsdc1WrkUFAl2Y+FyaaxtctZdkXOLNwLbFu0oMh aN+uFNLMtLNuPjCfwN1k6vCzb3VgEMlAbAQxxJs4hhkofzM77iCFrywtBaa3Mp5OR KJskAS1oaCu47tMfCMmqDuB6rrTGwqpZCXxgcsWCW4zXaT3uhUWGCm0kxnnvVro6v 9scE/paWPVtpv1DXEpqSqPy9p9iqQcwZBwUuxMnSQsEsHwrA1M0v01dVykh833Vrj wY0xcFmiBBe5wlB6SA== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from openwrt ([94.31.70.81]) by mail.gmx.net (mrgmx104 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MxlzC-1tvwSA1Ppe-00uVLu; Fri, 04 Oct 2024 21:57:16 +0200 From: Markus Stockhausen To: linux-phy@lists.infradead.org, chris.packham@alliedtelesis.co.nz Cc: Markus Stockhausen Subject: [PATCH 4/4] phy: Realtek Otto Serdes: add devicetree documentation Date: Fri, 4 Oct 2024 15:56:10 -0400 Message-ID: <20241004195712.1891488-5-markus.stockhausen@gmx.de> X-Mailer: git-send-email 2.46.2 In-Reply-To: <20241004195712.1891488-1-markus.stockhausen@gmx.de> References: <20241004195712.1891488-1-markus.stockhausen@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:V2yymqao580B3jJBfAD/X1WvigV+RxDv5yKAkgCQp5oVrhMPTVR AVCxGja98BQ5IqwJAjtjMgTyVDqmzYyMQsmDg43rXz5zHwCv1vxgX1BI3tfxLFN3dP28nrp y0l4pk9Ad7fizquGL3IoZsSrpcNKwc5iwum8hzwkxlor09AaqlTCWQrl39O07qvuA5fWgy7 nlraGflh7zmXTUfsvkmTA== UI-OutboundReport: notjunk:1;M01:P0:mX9Uk5DTFEc=;6dD3jlZfjP5b+ykIloq5HRCfUk6 5iAdF6VWj941oChM0FLTwMDHLhKzL/PkECP+raaT2JDLJ6tmidB8xq/u9HsvTICqoHRrBLUzh H/Ej9dSwaK+qVjXiBEtmn+wZOiBFj9UjDxpgwxptXZoLg1G46tpqSfwM7ICxuS7Byu5jmrzF4 0lyPPxHIEg2Lr9SpuzBdMBjnnOcZyu1IAa62bcgRlhIh9BLo4rimKhpSzdZunPZchRgeOgDyU BBZWE3n3PpKSv3nU7OQCOcwjx+Hz5eKRYgQD4Cn4bUReBWx6z4EcAR8UtFWslVQiHwlPw0x1A wzCTRD6VQbsQ90P9LjguDPsTn1FBLIDV0V1RjwrxMFK0eyCkIssnxeTfSLV3oxcK8c/Qq+Fn7 xzqkmQHVPzTDyhNEh/fsphsfpiMCGawkuqzKYaA0tM96utDVybpg4C76YAvYieWumBAOoVZlo 9u1J9CBRvejGy6eVnohDuMCwNX19upUkfWwC6MZ+3C+Xmn+jVNBvG6m28ts46QCwf9wc1bbYz zlpUwXMsSusCuHBoghrdavj0Ni958HVBZhoBNkb+3jJMqYlmFSoCzbUQTsQ8VVMRi4zaGDiBg FVx1PWWR7kgqLRunBHaP7DKKW6m08a6xZPzpFdcIFovjdIW2CAp/IIyUP4nEmvRCojjxi9pyl Q3cGYPzKHqsTh1e/423QVWg8WPfwIRWPr+oJ50tb+D1mjuc473DSl4MGpLthbs4r0oa+x3ZxL y4Nx3JaKCpOqSGTvURYGGJUFqfKSqpxCddplnGxgLGDlG4FmphIj5PSwjFSuj1LNwOmWdD0U7 LiHuYQbWhmX443VZ6CRamLcA== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241004_205740_134097_C6F59B55 X-CRM114-Status: GOOD ( 17.51 ) X-BeenThere: linux-phy@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux Phy Mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-phy" Errors-To: linux-phy-bounces+linux-phy=archiver.kernel.org@lists.infradead.org To help others to integrate the driver provide the devicetree documentation. --- .../bindings/phy/realtek,otto-serdes.yaml | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/realtek,otto-serdes.yaml -- 2.44.0 diff --git a/Documentation/devicetree/bindings/phy/realtek,otto-serdes.yaml b/Documentation/devicetree/bindings/phy/realtek,otto-serdes.yaml new file mode 100644 index 000000000000..b6dad1089c6f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/realtek,otto-serdes.yaml @@ -0,0 +1,167 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/realtek,otto-serdes.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek Otto SerDes controller + +maintainers: + - Markus Stockhausen + +description: | + The MIPS based Realtek Switch SoCs of the Realtek RTL838x, RTL839x, RTL930x and + RTL931x series have multiple SerDes built in. They are linked to different single, + quad or octa PHYs like the RTL8218B, RTL8218D or RTL8214FC and are the integral + part of the up-to-52-port switch architecture. + Although these SerDes controllers have common basics they behave differently on + the SoC families and rely on heavy register magic. To keep the driver clean it can + load patch sequences from devictree and execute them during the controller actions + like phy_init(), ... + The driver exposes the SerDes registers different from the hardware but instead + gives a consistent view and programming interface. So the RTL838x series has 6 ports + and 4 pages, the RTL839x has 14 ports and 12 pages, the RTL930x has 12 ports and + 64 pages and the RTL931x has 14 ports and 192 pages. + +properties: + $nodename: + pattern: "^serdes@[0-9a-f]+$" + + compatible: + items: + - enum: + - realtek,rtl8380-serdes + - realtek,rtl8390-serdes + - realtek,rtl9300-serdes + - realtek,rtl9310-serdes + + reg: + items: + - description: | + The primary serdes register memory location. Other SerDes control and + management registers are distributed all over the I/O memory space and + identified by the driver automatically. + + controlled-ports: + description: | + A bit mask defining the ports that are actively controlled by the driver. In + case a bit is not set the driver will only process read operations on the + SerDes. If not set the driver will run all ports in read only mode. + + "#phy-cells": + const: 4 + description: | + The first number defines the SerDes to use. The second number a linked + SerDes. E.g. if a octa 1G PHY is attached to two QSGMII SerDes. The third + number is the first switch port this SerDes is working for, the fourth number + is the last switch port the SerDes is working for. + + cmd-setup: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers during driver setup. + + cmd-init: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_init(). + + cmd-power-on: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_power_on(). + + cmd-pre-set-mode: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_set_mode() and before the driver + actually sets the mode. + + cmd-post-set-mode: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_set_mode() and after the driver + has set the mode. + + cmd-pre-reset: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_reset() and before the driver + actually resets the SerDes. + + cmd-post-reset: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_reset() and after the driver + has reset the SerDes. + + cmd-pre-power-off: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_power_off() and before the + driver actually powers off the SerDes. + + cmd-post-power-off: + description: | + A field of 16 bit values that contain a patch/command sequence to run on the + SerDes registers when a controller calls phy_power_off() and after the driver + has powered off the SerDes. + +reguired: + - compatible + - reg + - port-count + - page-count + - "#phy-cells" + +additionalProperties: + false + +examples: + - | + serdes: serdes@1b00e780 { + compatible = "realtek,rtl8380-serdes", "realtek,otto-serdes"; + reg = <0x1b00e780 0x1200>; + controlled-ports = <0x003f>; + #phy-cells = <2>; + }; + - | + serdes: serdes@1b00a000 { + compatible = "realtek,rtl8390-serdes", "realtek,otto-serdes"; + reg = <0x1b00a000 0x1c00>; + controlled-ports = <0x3fff>; + #phy-cells = <2>; + }; + - | + serdes: serdes@1b0003b0 { + compatible = "realtek,rtl9300-serdes", "realtek,otto-serdes"; + reg = <0x1b0003b0 0x8>; + controlled-ports = <0x0fff>; + #phy-cells = <2>; + }; + - | + serdes: serdes@1b005638 { + compatible = "realtek,rtl9310-serdes", "realtek,otto-serdes"; + reg = <0x1b005638 0x8>; + controlled-ports = <0x3fff>; + #phy-cells = <2>; + }; + - | + #define _MASK_ 1 + #define _WAIT_ 2 + serdes: serdes@1b00a000 { + compatible = "realtek,rtl8390-serdes", "realtek,otto-serdes"; + reg = <0x1b00a000 0x1c00>; + controlled-ports = <0x3fff>; + #phy-cells = <2>; + cmd-setup = /bits/ 16 < + /* + * set clock edge bit 14 during driver setup for ports 10-11 on page 0, + * register 7. Wait 128 ms. Afterwards set whole register 0 on page 10 + * of ports 8, 9, 12, 13 to 0x5800. + */ + _MASK_ 0x0c00 0x00 0x07 0x4000 0x4000 + _WAIT_ 0x0c00 0x00 0x00 0x0080 0x0000 + _MASK_ 0x3300 0x0a 0x00 0x5800 0xffff + >; + }; \ No newline at end of file