From patchwork Wed Dec 7 13:14:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergiu Moga X-Patchwork-Id: 1713293 X-Patchwork-Delegate: eugen.hristev@microchip.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=microchip.com header.i=@microchip.com header.a=rsa-sha256 header.s=mchp header.b=HUwZ7jMF; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NRybQ5j1jz23ys for ; Thu, 8 Dec 2022 00:21:06 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id E1051855FC; Wed, 7 Dec 2022 14:18:39 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=microchip.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=microchip.com header.i=@microchip.com header.b="HUwZ7jMF"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id A3AA485610; Wed, 7 Dec 2022 14:18:17 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H2, SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id C4A9E85631 for ; Wed, 7 Dec 2022 14:17:50 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=microchip.com Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=Sergiu.Moga@microchip.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1670419070; x=1701955070; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lbrLgF96QuzcKNza3oVs5vBknjmCWi1x4BJ7EWPc/lM=; b=HUwZ7jMFSv1Xlpe13pLh99+49VHNVW/98m2aRZNApo56Tqy+4edVKK1X BAOn1LIe4XyhBVF8nNECJi8+DXf5ZULfuyL8wlbkERJd4DAOJyOKsMgTF IOhUeWKIBgCQaW6v22mGTsW68ex+fzD/sWRZ+IMlA/dM/D9u3bBVhkNsU UtIkE06Wj94M0CySaLIc1BX2pVaSW8II9KdbGiQB6A4DwXro93XyFQsup 7IhqIgQkKOzv3OGrgKBWqBnamA49JkxXquMAW0ddTIaZNc1M6h9FLYim6 5dU2JZiftG/No/+EKoQ7OiPmaAi2fiTVXPVm2k8iGN13NArev9M7SJ22Y w==; X-IronPort-AV: E=Sophos;i="5.96,225,1665471600"; d="scan'208";a="192068695" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Dec 2022 06:17:49 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.85.144) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Wed, 7 Dec 2022 06:17:49 -0700 Received: from ROB-ULT-M68701.mchp-main.com (10.10.115.15) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Wed, 7 Dec 2022 06:17:43 -0700 From: Sergiu Moga To: , , , , , , , , , , , , , , , , , , , , , , , CC: Subject: [PATCH 12/18] phy: at91: Add support for the USB 2.0 PHY's of SAMA7 Date: Wed, 7 Dec 2022 15:14:41 +0200 Message-ID: <20221207131447.40590-13-sergiu.moga@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221207131447.40590-1-sergiu.moga@microchip.com> References: <20221207131447.40590-1-sergiu.moga@microchip.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean In order to have USB functionality, drivers for SAMA7's USB 2.0 PHY's have been added. There is one driver for UTMI clock's SFR and RESET required functionalities and one for its three possible subclocks of the phy's themselves. In order for this layout to properly work in conjunction with CCF and DT, the former driver will also act as a clock provider for the three phy's with the help of a custom hook into the driver's of_xlate method. Signed-off-by: Sergiu Moga Tested-by: Mihai Sain --- drivers/phy/Kconfig | 10 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-sama7-usb.c | 92 ++++++++++++++ drivers/phy/phy-sama7-utmi-clk.c | 202 +++++++++++++++++++++++++++++++ 4 files changed, 305 insertions(+) create mode 100644 drivers/phy/phy-sama7-usb.c create mode 100644 drivers/phy/phy-sama7-utmi-clk.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index cf4d5908d7..9fbb956783 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -281,6 +281,16 @@ config PHY_XILINX_ZYNQMP Enable this to support ZynqMP High Speed Gigabit Transceiver that is part of ZynqMP SoC. +config PHY_MICROCHIP_SAMA7_USB + tristate "Microchip SAMA7 USB 2.0 PHY" + depends on PHY && ARCH_AT91 + help + Enable this to support SAMA7 USB 2.0 PHY. + + The USB 2.0 PHY integrates high-speed, full-speed and low-speed + termination and signal switching. With a single resistor, it + requires minimal external components. + source "drivers/phy/rockchip/Kconfig" source "drivers/phy/cadence/Kconfig" source "drivers/phy/ti/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index a3b9f3c5b1..9d50affd47 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o +obj-$(CONFIG_PHY_MICROCHIP_SAMA7_USB) += phy-sama7-utmi-clk.o phy-sama7-usb.o obj-y += cadence/ obj-y += ti/ obj-y += qcom/ diff --git a/drivers/phy/phy-sama7-usb.c b/drivers/phy/phy-sama7-usb.c new file mode 100644 index 0000000000..b6fe40ecc1 --- /dev/null +++ b/drivers/phy/phy-sama7-usb.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Support for Atmel/Microchip USB PHY's. + * + * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries + * + * Author: Sergiu Moga + */ + +#include +#include +#include +#include +#include +#include + +struct sama7_usb_phy { + struct clk *uclk; + struct regmap *sfr; + int port; +}; + +int sama7_usb_phy_init(struct phy *phy) +{ + struct sama7_usb_phy *sama7_phy = dev_get_priv(phy->dev); + int port = sama7_phy->port; + + regmap_update_bits(sama7_phy->sfr, SAMA7_SFR_UTMI0R(port), + SAMA7_SFR_UTMI_RX_TX_PREEM_AMP_TUNE_1X, + SAMA7_SFR_UTMI_RX_TX_PREEM_AMP_TUNE_1X); + + regmap_update_bits(sama7_phy->sfr, SAMA7_SFR_UTMI0R(port), + SAMA7_SFR_UTMI_RX_VBUS, + SAMA7_SFR_UTMI_RX_VBUS); + + return 0; +} + +int sama7_phy_power_on(struct phy *phy) +{ + struct sama7_usb_phy *sama7_phy = dev_get_priv(phy->dev); + + clk_prepare_enable(sama7_phy->uclk); + + return 0; +} + +int sama7_phy_power_off(struct phy *phy) +{ + struct sama7_usb_phy *sama7_phy = dev_get_priv(phy->dev); + + clk_disable_unprepare(sama7_phy->uclk); + + return 0; +} + +int sama7_usb_phy_probe(struct udevice *dev) +{ + struct sama7_usb_phy *sama7_phy = dev_get_priv(dev); + + sama7_phy->uclk = devm_clk_get(dev, "utmi_clk"); + if (IS_ERR(sama7_phy->uclk)) + return PTR_ERR(sama7_phy->uclk); + + sama7_phy->sfr = syscon_regmap_lookup_by_phandle(dev, "sfr-phandle"); + if (IS_ERR(sama7_phy->sfr)) { + sama7_phy->sfr = NULL; + return PTR_ERR(sama7_phy->sfr); + } + + return dev_read_u32(dev, "reg", &sama7_phy->port); +} + +static const struct phy_ops sama7_usb_phy_ops = { + .init = sama7_usb_phy_init, + .power_on = sama7_phy_power_on, + .power_off = sama7_phy_power_off, +}; + +static const struct udevice_id sama7_usb_phy_of_match[] = { + { .compatible = "microchip,sama7g5-usb-phy", }, + { }, +}; + +U_BOOT_DRIVER(sama7_usb_phy_driver) = { + .name = "sama7-usb-phy", + .id = UCLASS_PHY, + .of_match = sama7_usb_phy_of_match, + .ops = &sama7_usb_phy_ops, + .probe = sama7_usb_phy_probe, + .priv_auto = sizeof(struct sama7_usb_phy), +}; diff --git a/drivers/phy/phy-sama7-utmi-clk.c b/drivers/phy/phy-sama7-utmi-clk.c new file mode 100644 index 0000000000..ab9fddccf6 --- /dev/null +++ b/drivers/phy/phy-sama7-utmi-clk.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Support for Atmel/Microchip USB PHY's. + * + * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries + * + * Author: Sergiu Moga + */ + +#include +#include +#include +#include +#include +#include +#include + +struct sama7_utmi_clk { + struct clk uclk; + struct regmap *regmap_sfr; + struct reset_ctl *reset; + u8 id; +}; + +#define to_sama7_utmi_clk(_c) container_of(_c, struct sama7_utmi_clk, uclk) + +#define UBOOT_DM_CLK_MICROCHIP_SAMA7G5_UTMI "sama7-utmi-clk" +#define UBOOT_DM_MICROCHIP_SAMA7G5_UTMI "sama7-utmi" + +#define AT91_TO_CLK_ID(_t, _i) (((_t) << 8) | ((_i) & 0xff)) + +/* + * UTMI clock description + * @n: clock name + * @p: clock parent name + * @id: clock id in RSTC_GRSTR + */ +static struct { + const char *n; + const char *p; + u8 id; +} sama7_utmick[] = { + { .n = "utmi1", .p = "utmick", .id = 0, }, + { .n = "utmi2", .p = "utmi1", .id = 1, }, + { .n = "utmi3", .p = "utmi1", .id = 2, }, +}; + +static int sama7_utmi_clk_enable(struct clk *clk) +{ + int ret; + + struct sama7_utmi_clk *utmi = to_sama7_utmi_clk(clk); + u8 id = utmi->id; + + ret = reset_assert(utmi->reset); + if (ret) + return ret; + + ret = regmap_update_bits(utmi->regmap_sfr, SAMA7_SFR_UTMI0R(id), + SAMA7_SFR_UTMI_COMMONON, 0); + if (ret < 0) + return ret; + + ret = reset_deassert(utmi->reset); + if (ret) + return ret; + + /* Datasheet states a minimum of 45 us before any USB operation */ + udelay(50); + + return 0; +} + +static int sama7_utmi_clk_disable(struct clk *clk) +{ + int ret; + struct sama7_utmi_clk *utmi = to_sama7_utmi_clk(clk); + u8 id = utmi->id; + + ret = reset_assert(utmi->reset); + if (ret) + return ret; + + regmap_update_bits(utmi->regmap_sfr, SAMA7_SFR_UTMI0R(id), + SAMA7_SFR_UTMI_COMMONON, SAMA7_SFR_UTMI_COMMONON); + + return 0; +} + +static ulong sama7_utmi_clk_get_rate(struct clk *clk) +{ + /* Return utmick's rate: 480MHz */ + return clk_get_parent_rate(clk); +} + +static const struct clk_ops sama7_utmi_clk_ops = { + .enable = sama7_utmi_clk_enable, + .disable = sama7_utmi_clk_disable, + .get_rate = sama7_utmi_clk_get_rate, +}; + +static struct clk* +sama7_utmi_clk_register(struct regmap *regmap_sfr, struct reset_ctl *reset, + const char *name, const char *parent_name, u8 id) +{ + struct clk *clk; + struct sama7_utmi_clk *utmi_clk; + int ret; + + if (!regmap_sfr || !reset || !name || !parent_name) + return ERR_PTR(-EINVAL); + + utmi_clk = kzalloc(sizeof(*utmi_clk), GFP_KERNEL); + if (!utmi_clk) + return ERR_PTR(-ENOMEM); + + utmi_clk->reset = reset; + utmi_clk->regmap_sfr = regmap_sfr; + utmi_clk->id = id; + + clk = &utmi_clk->uclk; + ret = clk_register(clk, UBOOT_DM_CLK_MICROCHIP_SAMA7G5_UTMI, + name, parent_name); + if (ret) { + kfree(utmi_clk); + clk = ERR_PTR(ret); + } + + clk_dm(AT91_TO_CLK_ID(UTMI, utmi_clk->id), clk); + + return clk; +} + +static int sama7_utmi_probe(struct udevice *dev) +{ + struct clk *utmi_parent_clk, *utmi_clk; + struct regmap *regmap_sfr; + struct reset_ctl *phy_reset; + int i; + char name[16]; + + utmi_parent_clk = devm_clk_get(dev, "utmi_clk"); + if (IS_ERR(utmi_parent_clk)) + return PTR_ERR(utmi_parent_clk); + + regmap_sfr = syscon_regmap_lookup_by_phandle(dev, "sfr-phandle"); + if (IS_ERR(regmap_sfr)) + return PTR_ERR(regmap_sfr); + + for (i = 0; i < ARRAY_SIZE(sama7_utmick); i++) { + snprintf(name, sizeof(name), "usb%d_reset", i); + phy_reset = devm_reset_control_get(dev, name); + if (IS_ERR(phy_reset)) + return PTR_ERR(phy_reset); + + utmi_clk = sama7_utmi_clk_register(regmap_sfr, phy_reset, + sama7_utmick[i].n, + sama7_utmick[i].p, + sama7_utmick[i].id); + if (IS_ERR(utmi_clk)) + return PTR_ERR(utmi_clk); + } + + return 0; +}; + +static const struct udevice_id sama7_utmi_clk_dt_ids[] = { + { .compatible = "microchip,sama7g5-utmi-clk", }, + { /* sentinel */}, +}; + +static int utmi_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count != 1) { + debug("UTMI: clk: Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + clk->id = AT91_TO_CLK_ID(UTMI, args->args[0]); + + return 0; +} + +static const struct clk_ops sama7_utmi_ops = { + .of_xlate = utmi_clk_of_xlate, + .enable = ccf_clk_enable, + .disable = ccf_clk_disable, +}; + +U_BOOT_DRIVER(microhip_sama7g5_utmi_clk) = { + .name = UBOOT_DM_CLK_MICROCHIP_SAMA7G5_UTMI, + .id = UCLASS_CLK, + .ops = &sama7_utmi_clk_ops, +}; + +U_BOOT_DRIVER(microhip_sama7g5_utmi) = { + .name = UBOOT_DM_MICROCHIP_SAMA7G5_UTMI, + .of_match = sama7_utmi_clk_dt_ids, + .id = UCLASS_CLK, + .ops = &sama7_utmi_ops, + .probe = sama7_utmi_probe, +};