From patchwork Mon Apr 7 17:28:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041386 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD15F2163B8 for ; Mon, 7 Apr 2025 17:28:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046939; cv=none; b=CbHhJnT2fYtEyBX7S+S5ypI7QWgGQ86l3upLZVJjUJJCSdsrZqvnQKjOVDfsJ/m0J+yEbFAbIz4GYDxiWjsAYs1YiqlHD8J0cc6ZwGi74bJrMVV4KZHJVRZiMPZcbBixNIyNKLqICQ0fH06soGobGfkORDxCw4dxlrR5kojddfg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046939; c=relaxed/simple; bh=z13lUI9VJGolj41JA2aJQ3X8gdn3+LkRBtT+tiX/tqE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=luD5pjfN+fvCIrl95ZGe/43BHivNSxpbYJ54eB7XsTxX0iUpVTaY3NE8C3BMJh5CAGUI+nw2/7OrIf8C6ZZEAKD5uB2vwB47mY3VnNDfDhew/9wuoS2v3MBh2SeYYSZJWBJFEcxP0UZyTQDGaFXmYYyRD8MgxER8NaACWhjAFy0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Rm5dEhAn; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Rm5dEhAn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046935; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uYBd4+A9/sbkJNnoRIiVA1lW5qMA4TWhZWzzyc/OvvY=; b=Rm5dEhAn8lq21eXCOTdJRELP9XUdFlR2gGkjgSMwG+yHJ/K8xu/NQVp2JGj6CVGioMthtB jZ53wtqymuPqEEhx4JNLMXLgzv+F9o3MeQuGUpGbGFFVR+6MrT6Ndtqu5//BxAFKOBxkvM +ZJQv/E4y5GXOQ/1wbt3/nshV4wUi74= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-552-NUDQe-GzPeyMmCu1UOS9Bg-1; Mon, 07 Apr 2025 13:28:52 -0400 X-MC-Unique: NUDQe-GzPeyMmCu1UOS9Bg-1 X-Mimecast-MFC-AGG-ID: NUDQe-GzPeyMmCu1UOS9Bg_1744046930 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id ED17A1809CA5; Mon, 7 Apr 2025 17:28:49 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 35016180B488; Mon, 7 Apr 2025 17:28:43 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 01/28] mfd: Add Microchip ZL3073x support Date: Mon, 7 Apr 2025 19:28:28 +0200 Message-ID: <20250407172836.1009461-2-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This adds base MFD driver for Microchip Azurite ZL3073x chip family. These chips provide DPLL and PHC (PTP) functionality and they can be connected over I2C or SPI bus. The MFD driver provide basic communication and synchronization over the bus and common functionality that are used by the DPLL driver (later in this series) and by the PTP driver (will be added later). The chip family is characterized by following properties: * 2 separate DPLL units (channels) * 5 synthesizers * 10 input pins (references) * 10 outputs * 20 output pins (output pin pair shares one output) * Each reference and output can act in differential or single-ended mode (reference or output in differential mode consumes 2 pins) * Each output is connected to one of the synthesizers * Each synthesizer is driven by one of the DPLL unit Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- MAINTAINERS | 8 +++++ drivers/mfd/Kconfig | 30 ++++++++++++++++ drivers/mfd/Makefile | 5 +++ drivers/mfd/zl3073x-core.c | 70 ++++++++++++++++++++++++++++++++++++ drivers/mfd/zl3073x-i2c.c | 70 ++++++++++++++++++++++++++++++++++++ drivers/mfd/zl3073x-spi.c | 71 +++++++++++++++++++++++++++++++++++++ drivers/mfd/zl3073x.h | 13 +++++++ include/linux/mfd/zl3073x.h | 15 ++++++++ 8 files changed, 282 insertions(+) create mode 100644 drivers/mfd/zl3073x-core.c create mode 100644 drivers/mfd/zl3073x-i2c.c create mode 100644 drivers/mfd/zl3073x-spi.c create mode 100644 drivers/mfd/zl3073x.h create mode 100644 include/linux/mfd/zl3073x.h diff --git a/MAINTAINERS b/MAINTAINERS index 4c5c2e2c12787..c69a69d862310 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15994,6 +15994,14 @@ L: linux-wireless@vger.kernel.org S: Supported F: drivers/net/wireless/microchip/ +MICROCHIP ZL3073X DRIVER +M: Ivan Vecera +M: Prathosh Satish +L: netdev@vger.kernel.org +S: Supported +F: drivers/mfd/zl3073x* +F: include/linux/mfd/zl3073x.h + MICROSEMI MIPS SOCS M: Alexandre Belloni M: UNGLinuxDriver@microchip.com diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 22b9363100394..30b36e3ee8f7f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2422,5 +2422,35 @@ config MFD_UPBOARD_FPGA To compile this driver as a module, choose M here: the module will be called upboard-fpga. +config MFD_ZL3073X_CORE + tristate + select MFD_CORE + +config MFD_ZL3073X_I2C + tristate "Microchip Azurite DPLL/PTP/SyncE with I2C" + depends on I2C + select MFD_ZL3073X_CORE + select REGMAP_I2C + help + Support for Microchip Azurite DPLL/PTP/SyncE chip family. This option + supports I2C as the control interface. + + This driver provides common support for accessing the device. + Additional drivers must be enabled in order to use the functionality + of the device. + +config MFD_ZL3073X_SPI + tristate "Microchip Azurite DPLL/PTP/SyncE with SPI" + depends on SPI + select MFD_ZL3073X_CORE + select REGMAP_SPI + help + Support for Microchip Azurite DPLL/PTP/SyncE chip family. This option + supports SPI as the control interface. + + This driver provides common support for accessing the device. + Additional drivers must be enabled in order to use the functionality + of the device. + endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 948cbdf42a18b..76e2babc1538f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -290,3 +290,8 @@ obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o + +zl3073x-y := zl3073x-core.o +obj-$(CONFIG_MFD_ZL3073X_CORE) += zl3073x.o +obj-$(CONFIG_MFD_ZL3073X_I2C) += zl3073x-i2c.o +obj-$(CONFIG_MFD_ZL3073X_SPI) += zl3073x-spi.o diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c new file mode 100644 index 0000000000000..67a9d5a0e2d8c --- /dev/null +++ b/drivers/mfd/zl3073x-core.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include "zl3073x.h" + +/* + * Regmap ranges + */ +#define ZL3073x_PAGE_SIZE 128 +#define ZL3073x_NUM_PAGES 16 +#define ZL3073x_PAGE_SEL 0x7F + +static const struct regmap_range_cfg zl3073x_regmap_ranges[] = { + { + .range_min = 0, + .range_max = ZL3073x_NUM_PAGES * ZL3073x_PAGE_SIZE, + .selector_reg = ZL3073x_PAGE_SEL, + .selector_mask = GENMASK(3, 0), + .selector_shift = 0, + .window_start = 0, + .window_len = ZL3073x_PAGE_SIZE, + }, +}; + +/* + * Regmap config + */ +const struct regmap_config zl3073x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ZL3073x_NUM_PAGES * ZL3073x_PAGE_SIZE, + .ranges = zl3073x_regmap_ranges, + .num_ranges = ARRAY_SIZE(zl3073x_regmap_ranges), +}; + +/** + * zl3073x_get_regmap_config - return pointer to regmap config + * + * Returns pointer to regmap config + */ +const struct regmap_config *zl3073x_get_regmap_config(void) +{ + return &zl3073x_regmap_config; +} +EXPORT_SYMBOL_NS_GPL(zl3073x_get_regmap_config, "ZL3073X"); + +struct zl3073x_dev *zl3073x_dev_alloc(struct device *dev) +{ + struct zl3073x_dev *zldev; + + return devm_kzalloc(dev, sizeof(*zldev), GFP_KERNEL); +} +EXPORT_SYMBOL_NS_GPL(zl3073x_dev_alloc, "ZL3073X"); + +int zl3073x_dev_init(struct zl3073x_dev *zldev) +{ + devm_mutex_init(zldev->dev, &zldev->lock); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(zl3073x_dev_init, "ZL3073X"); + +void zl3073x_dev_exit(struct zl3073x_dev *zldev) +{ +} +EXPORT_SYMBOL_NS_GPL(zl3073x_dev_exit, "ZL3073X"); + +MODULE_AUTHOR("Ivan Vecera "); +MODULE_DESCRIPTION("Microchip ZL3073x core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/zl3073x-i2c.c b/drivers/mfd/zl3073x-i2c.c new file mode 100644 index 0000000000000..8c8b2ba176766 --- /dev/null +++ b/drivers/mfd/zl3073x-i2c.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include "zl3073x.h" + +static const struct i2c_device_id zl3073x_i2c_id[] = { + { "zl3073x-i2c", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i2c, zl3073x_i2c_id); + +static const struct of_device_id zl3073x_i2c_of_match[] = { + { .compatible = "microchip,zl3073x-i2c" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match); + +static int zl3073x_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + const struct i2c_device_id *id; + struct zl3073x_dev *zldev; + int rc = 0; + + zldev = zl3073x_dev_alloc(dev); + if (!zldev) + return -ENOMEM; + + id = i2c_client_get_device_id(client); + zldev->dev = dev; + + zldev->regmap = devm_regmap_init_i2c(client, + zl3073x_get_regmap_config()); + if (IS_ERR(zldev->regmap)) { + rc = PTR_ERR(zldev->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", rc); + return rc; + } + + i2c_set_clientdata(client, zldev); + + return zl3073x_dev_init(zldev); +} + +static void zl3073x_i2c_remove(struct i2c_client *client) +{ + struct zl3073x_dev *zldev; + + zldev = i2c_get_clientdata(client); + zl3073x_dev_exit(zldev); +} + +static struct i2c_driver zl3073x_i2c_driver = { + .driver = { + .name = "zl3073x-i2c", + .of_match_table = of_match_ptr(zl3073x_i2c_of_match), + }, + .probe = zl3073x_i2c_probe, + .remove = zl3073x_i2c_remove, + .id_table = zl3073x_i2c_id, +}; + +module_i2c_driver(zl3073x_i2c_driver); + +MODULE_AUTHOR("Ivan Vecera "); +MODULE_DESCRIPTION("Microchip ZL3073x I2C driver"); +MODULE_IMPORT_NS("ZL3073X"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/zl3073x-spi.c b/drivers/mfd/zl3073x-spi.c new file mode 100644 index 0000000000000..a6b9a366a7585 --- /dev/null +++ b/drivers/mfd/zl3073x-spi.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include "zl3073x.h" + +static const struct spi_device_id zl3073x_spi_id[] = { + { "zl3073x-spi", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(spi, zl3073x_spi_id); + +static const struct of_device_id zl3073x_spi_of_match[] = { + { .compatible = "microchip,zl3073x-spi" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match); + +static int zl3073x_spi_probe(struct spi_device *spidev) +{ + struct device *dev = &spidev->dev; + const struct spi_device_id *id; + struct zl3073x_dev *zldev; + int rc; + + zldev = zl3073x_dev_alloc(dev); + if (!zldev) + return -ENOMEM; + + id = spi_get_device_id(spidev); + zldev->dev = dev; + + zldev->regmap = devm_regmap_init_spi(spidev, + zl3073x_get_regmap_config()); + if (IS_ERR(zldev->regmap)) { + rc = PTR_ERR(zldev->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", rc); + return rc; + } + + spi_set_drvdata(spidev, zldev); + + return zl3073x_dev_init(zldev); +} + +static void zl3073x_spi_remove(struct spi_device *spidev) +{ + struct zl3073x_dev *zldev; + + zldev = spi_get_drvdata(spidev); + zl3073x_dev_exit(zldev); +} + +static struct spi_driver zl3073x_spi_driver = { + .driver = { + .name = "zl3073x-spi", + .of_match_table = of_match_ptr(zl3073x_spi_of_match), + }, + .probe = zl3073x_spi_probe, + .remove = zl3073x_spi_remove, + .id_table = zl3073x_spi_id, +}; + +module_spi_driver(zl3073x_spi_driver); + +MODULE_AUTHOR("Ivan Vecera "); +MODULE_DESCRIPTION("Microchip ZL3073x SPI driver"); +MODULE_IMPORT_NS("ZL3073X"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/zl3073x.h b/drivers/mfd/zl3073x.h new file mode 100644 index 0000000000000..582cb40d681d3 --- /dev/null +++ b/drivers/mfd/zl3073x.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ZL3073X_CORE_H +#define __ZL3073X_CORE_H + +#include + +struct zl3073x_dev *zl3073x_dev_alloc(struct device *dev); +int zl3073x_dev_init(struct zl3073x_dev *zldev); +void zl3073x_dev_exit(struct zl3073x_dev *zldev); +const struct regmap_config *zl3073x_get_regmap_config(void); + +#endif /* __ZL3073X_CORE_H */ diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h new file mode 100644 index 0000000000000..7b80c3059b5f3 --- /dev/null +++ b/include/linux/mfd/zl3073x.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __LINUX_MFD_ZL3073X_H +#define __LINUX_MFD_ZL3073X_H + +#include +#include + +struct zl3073x_dev { + struct device *dev; + struct regmap *regmap; + struct mutex lock; +}; + +#endif /* __LINUX_MFD_ZL3073X_H */ From patchwork Mon Apr 7 17:28:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041387 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5983D218AC8 for ; Mon, 7 Apr 2025 17:29:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046944; cv=none; b=s2r1M0FpfqrmzsVS8TPIkgf1rPHS1bs2udSJF9s2agmPmC3cELvPutWjHV9B2jAXZjCknmDr0Fa0g0FO4hkRfq5hKWqpTwxfPoZnQjfAAoH52N9DVTOsRsBrNaNoy6eakcbknCq7fyWLY0K9+HEwvTJ0gQRLJi4DbjXfLQJsiBw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046944; c=relaxed/simple; bh=v1rM3bKaL5fazId1hGOHxWFqoP2Wtd1q2yFOeLRU448=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=riYCumNrrku+QqHG1Q9VhwSyiN6Nu+7Wmq7umPBoOTg3kq0M8e+c2t1u6yghZ2Z7YGwNpjPc2xO9pjBjmdW+uJIMYj9sGfxPGF1Wuh/8g0eKrOPrqYfQwoOUlvKz5Fn4uuPbeoAGPOw5Jxv5g4UnoXjLE3lfD/H6JHqRhdw+yag= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Ecl821oT; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Ecl821oT" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046942; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=byI/z5EgcgD3KURSrPmsNqBUTi51FgnmC0aRsV45pBE=; b=Ecl821oTCH4EypZI0vsOFhzlSST021fIFTsTOhomGQu0ze87QMkCBf12Uw3MwcV+GU1lJM qxty8GBX1sT+rpy840iGBqRUJLOCpbQe8Ck2c6LAEDvmDHX7FB70OMefNkrGh57Ez4GQyD GD8nQEe5QGkeAVTqbtP7g0OjUQuQGIs= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-662-Eyyn3PRMMCWwXJxKennttQ-1; Mon, 07 Apr 2025 13:28:59 -0400 X-MC-Unique: Eyyn3PRMMCWwXJxKennttQ-1 X-Mimecast-MFC-AGG-ID: Eyyn3PRMMCWwXJxKennttQ_1744046937 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 68EE719560B0; Mon, 7 Apr 2025 17:28:56 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 891A2180B488; Mon, 7 Apr 2025 17:28:50 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 02/28] mfd: zl3073x: Register itself as devlink device Date: Mon, 7 Apr 2025 19:28:29 +0200 Message-ID: <20250407172836.1009461-3-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Use devlink_alloc() to alloc zl3073x_dev structure and register the device as a devlink device. Follow-up patches add support for devlink device info reporting and devlink flash interface will be later used for flashing firmware and configuration. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/Kconfig | 3 +++ drivers/mfd/zl3073x-core.c | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 30b36e3ee8f7f..a838d5dca4579 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2424,11 +2424,13 @@ config MFD_UPBOARD_FPGA config MFD_ZL3073X_CORE tristate + select NET_DEVLINK select MFD_CORE config MFD_ZL3073X_I2C tristate "Microchip Azurite DPLL/PTP/SyncE with I2C" depends on I2C + depends on NET select MFD_ZL3073X_CORE select REGMAP_I2C help @@ -2441,6 +2443,7 @@ config MFD_ZL3073X_I2C config MFD_ZL3073X_SPI tristate "Microchip Azurite DPLL/PTP/SyncE with SPI" + depends on NET depends on SPI select MFD_ZL3073X_CORE select REGMAP_SPI diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index 67a9d5a0e2d8c..71454f683eab0 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include "zl3073x.h" /* @@ -44,24 +45,46 @@ const struct regmap_config *zl3073x_get_regmap_config(void) } EXPORT_SYMBOL_NS_GPL(zl3073x_get_regmap_config, "ZL3073X"); +static const struct devlink_ops zl3073x_devlink_ops = { +}; + +static void zl3073x_devlink_free(void *ptr) +{ + devlink_free(ptr); +} + struct zl3073x_dev *zl3073x_dev_alloc(struct device *dev) { - struct zl3073x_dev *zldev; + struct devlink *devlink; - return devm_kzalloc(dev, sizeof(*zldev), GFP_KERNEL); + devlink = devlink_alloc(&zl3073x_devlink_ops, + sizeof(struct zl3073x_dev), dev); + if (!devlink) + return NULL; + + if (devm_add_action_or_reset(dev, zl3073x_devlink_free, devlink)) + return NULL; + + return devlink_priv(devlink); } EXPORT_SYMBOL_NS_GPL(zl3073x_dev_alloc, "ZL3073X"); int zl3073x_dev_init(struct zl3073x_dev *zldev) { + struct devlink *devlink; + devm_mutex_init(zldev->dev, &zldev->lock); + devlink = priv_to_devlink(zldev); + devlink_register(devlink); + return 0; } EXPORT_SYMBOL_NS_GPL(zl3073x_dev_init, "ZL3073X"); void zl3073x_dev_exit(struct zl3073x_dev *zldev) { + devlink_unregister(priv_to_devlink(zldev)); } EXPORT_SYMBOL_NS_GPL(zl3073x_dev_exit, "ZL3073X"); From patchwork Mon Apr 7 17:28:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041388 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A0B0218AC8 for ; Mon, 7 Apr 2025 17:29:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046949; cv=none; b=Jy3+zPyCOvtyLiVBS0pLsKFy6E8sjo75a0NGP8gPs2EjoISTslHIUP3bC+f9BbyYU2BUW8/fQWY4+4+NQWG662b4OgLZXymRVP/ypgJHiAtJZs4+dz1ItCH8NBiWBKXrq0BR5voQz5wMvauxVsokLADQ3rnh6RWwO2CzPjZqmFY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046949; c=relaxed/simple; bh=0wCVLf2kJcHvkMdyauZo7zlisXxqfF6avpneNWZUZrk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kxz/FbPrqrk7JOfcuEUqi17cfjwHkOTAcdyW2/HvjLkf2ADT+B3fCyFIMVpUHmcy2VINIOTmCm45EldUqEYjS9sZ3gBt9989WTNfCMcDlxjn/r8HEmUBveer1jwQzm3/MTPZR0R13v2e5GOcZBlyueYVPbVt0sFqg/6VceecKSc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=EfoCk7ss; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="EfoCk7ss" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046946; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=B0fBe2C1irn6omk1B6zTSlR0v1B01FIR0IrpHCwK7Uw=; b=EfoCk7ss2AVJmhsSopZlC3HwRhpIe6O6Om69RwuIpg3h4cUjWBXbhtwde7u3td08URMdvb zqRqjYZUyA4i9y78EDHJXxHmt7WE9N83rtdE79dCRiWmCq6sfA4bKUYITO9Uq/BQHDegzM 63uK0urWk75Hd/ArtDbiNwzVfgCrpmM= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-567-VGIaxfc_Ni6Rk6NM9QXflw-1; Mon, 07 Apr 2025 13:29:05 -0400 X-MC-Unique: VGIaxfc_Ni6Rk6NM9QXflw-1 X-Mimecast-MFC-AGG-ID: VGIaxfc_Ni6Rk6NM9QXflw_1744046943 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D342F1801A07; Mon, 7 Apr 2025 17:29:02 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 02A43180B488; Mon, 7 Apr 2025 17:28:56 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 03/28] mfd: zl3073x: Add register access helpers Date: Mon, 7 Apr 2025 19:28:30 +0200 Message-ID: <20250407172836.1009461-4-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Add helpers zl3073x_{read,write}_reg() to access device registers. These functions have to be called with device lock that can be taken by zl3073x_{lock,unlock}() or a caller can use defined guard. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 88 +++++++++++++++++++++++++++++++++++++ include/linux/mfd/zl3073x.h | 32 ++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index 71454f683eab0..39d4c8608a740 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include #include "zl3073x.h" @@ -45,6 +46,93 @@ const struct regmap_config *zl3073x_get_regmap_config(void) } EXPORT_SYMBOL_NS_GPL(zl3073x_get_regmap_config, "ZL3073X"); +/** + * zl3073x_read_reg - Read value from device register + * @zldev: device structure pointer + * @reg: register to be read + * @len: number of bytes to read + * @value: pointer to place to store value read from the register + * + * Caller has to hold the device lock that can be obtained + * by zl3073x_lock(). + * + * Returns 0 in case of success or negative value otherwise + */ +int zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, + unsigned int len, void *value) +{ + u8 buf[6]; + int rc; + + lockdep_assert_held(&zldev->lock); + + rc = regmap_bulk_read(zldev->regmap, reg, buf, len); + if (rc) + return rc; + + switch (len) { + case 1: + *(u8 *)value = buf[0]; + break; + case 2: + *(u16 *)value = get_unaligned_be16(buf); + break; + case 4: + *(u32 *)value = get_unaligned_be32(buf); + break; + case 6: + *(u64 *)value = get_unaligned_be48(buf); + break; + default: + WARN(true, "Unsupported register size: %u\n", len); + break; + } + + return rc; +} +EXPORT_SYMBOL_GPL(zl3073x_read_reg); + +/** + * zl3073x_write_reg - Write value to device register + * @zldev: device structure pointer + * @reg: register to be written + * @len: number of bytes to write + * @value: pointer to value to write to the register + * + * Caller has to hold the device lock that can be obtained + * by zl3073x_lock(). + * + * Returns 0 in case of success or negative value otherwise + */ +int zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, + unsigned int len, const void *value) +{ + u8 buf[6]; + + lockdep_assert_held(&zldev->lock); + + switch (len) { + case 1: + buf[0] = *(u8 *)value; + break; + case 2: + put_unaligned_be16(*(u16 *)value, buf); + break; + case 4: + put_unaligned_be32(*(u32 *)value, buf); + break; + case 6: + put_unaligned_be48(*(u64 *)value, buf); + break; + default: + WARN(true, "Unsupported register size: %u\n", len); + break; + } + + return regmap_bulk_write(zldev->regmap, reg, buf, len); +} +EXPORT_SYMBOL_GPL(zl3073x_write_reg); + static const struct devlink_ops zl3073x_devlink_ops = { }; diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h index 7b80c3059b5f3..0156f9044d79d 100644 --- a/include/linux/mfd/zl3073x.h +++ b/include/linux/mfd/zl3073x.h @@ -12,4 +12,36 @@ struct zl3073x_dev { struct mutex lock; }; +/** + * zl3073x_lock - Lock the device + * @zldev: device structure pointer + * + * Caller has to take this lock when it needs to access device registers. + */ +static inline void zl3073x_lock(struct zl3073x_dev *zldev) +{ + mutex_lock(&zldev->lock); +} + +/** + * zl3073x_unlock - Unlock the device + * @zldev: device structure pointer + * + * Caller unlocks the device when it does not need to access device + * registers anymore. + */ +static inline void zl3073x_unlock(struct zl3073x_dev *zldev) +{ + mutex_unlock(&zldev->lock); +} + +DEFINE_GUARD(zl3073x, struct zl3073x_dev *, zl3073x_lock(_T), + zl3073x_unlock(_T)); + +int zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, + unsigned int len, void *value); + +int zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, + unsigned int len, const void *value); + #endif /* __LINUX_MFD_ZL3073X_H */ From patchwork Mon Apr 7 17:28:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041395 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6DF3422A7EE for ; Mon, 7 Apr 2025 17:29:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046993; cv=none; b=k6V4/mRRuOYUcMLwn4gIM4HYo4OR2eIaOv6ZTvtCQ3/Rgav/HOfLgeWKWhrUX1zO7+TtTU5bg5jfV5BfPkSxIQ8/3M/ua01Lh80//r9c7STBYfqz6wzjIOjJqMNt3zPuFK/IxQ3NwMX+VQplN70bp3us022mZ+SLWYRA7j6FeJc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046993; c=relaxed/simple; bh=NWd2OapoEvDMUrXT+lsTD9tEGOgeTdX0z2/0E0iGGEM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HTd4udxN0eNqu/jNWPbZpTIpubSqCPnARb7AGE29ss7g4Jpqm1GJvzfw+liyMFZ3bd+UDcaA+qPqkRBDie5Mw3g6sOeo+JCFEnxPponXrs3t9+nHWxgoZQ3WVyehke87T1mW6F7X2OQAa3Dsw5EXmhMAGXGSXsdTNIfF6o5c/gE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ZIbp/6zh; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ZIbp/6zh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046990; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nJdQzKKxcevh2Oe2aNeMatSmfz2Nc+4P0kNC4x5l3HU=; b=ZIbp/6zhjfljCqyffEqOvMMQadWvt8Q2DD1iqX9FPH63AtgTSEJuu0uX76MJGJDfIevpiu yRprGXIkP3V9hst44ijxwrMjVjmjgk6G0KT4mGDMTKnc122U7o9yURdsgMGZQ5Ahsmeo5d WqMDjn7e001HwLuqOU53PyeJ5gUboFs= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-691-a73XDGXGMz2M0mSaS5c-tw-1; Mon, 07 Apr 2025 13:29:11 -0400 X-MC-Unique: a73XDGXGMz2M0mSaS5c-tw-1 X-Mimecast-MFC-AGG-ID: a73XDGXGMz2M0mSaS5c-tw_1744046949 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5858119560B0; Mon, 7 Apr 2025 17:29:09 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 62736180A803; Mon, 7 Apr 2025 17:29:03 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 04/28] mfd: zl3073x: Add macros for device registers access Date: Mon, 7 Apr 2025 19:28:31 +0200 Message-ID: <20250407172836.1009461-5-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Add several macros to access device registers. These macros defines a couple of static inline functions to ease an access device registers. There are two types of registers, the 1st type is a simple one that is defined by an address and size and the 2nd type is indexed register that is defined by base address, type, number of register instances and address stride between instances. Examples: __ZL3073X_REG_DEF(reg1, 0x1234, 4, u32); __ZL3073X_REG_IDX_DEF(idx_reg2, 0x1234, 2, u16, 4, 0x10); this defines the following functions: int zl3073x_read_reg1(struct zl3073x_dev *dev, u32 *value); int zl3073x_write_reg1(struct zl3073x_dev *dev, u32 value); int zl3073x_read_idx_reg2(struct zl3073x_dev *dev, unsigned int idx, u32 *value); int zl3073x_write_idx_reg2(struct zl3073x_dev *dev, unsigned int idx, u32 value); There are also several shortcut macros to define registers with certain bit widths: 8, 16, 32 and 48 bits. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- include/linux/mfd/zl3073x.h | 99 +++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h index 0156f9044d79d..3524426f0e3ba 100644 --- a/include/linux/mfd/zl3073x.h +++ b/include/linux/mfd/zl3073x.h @@ -44,4 +44,103 @@ int zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, int zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, unsigned int len, const void *value); +/** + * __ZL3073X_REG_DEF - Define a device register helpers + * @_name: register name + * @_addr: register address + * @_len: size of register value in bytes + * @_type: type of register value + * + * The macro defines helper functions for particular device register + * to access it. + * + * Example: + * __ZL3073X_REG_DEF(sample_reg, 0x1234, 4, u32) + * + * generates static inline functions: + * int zl3073x_read_sample_reg(struct zl3073x_dev *dev, u32 *value); + * int zl3073x_write_sample_reg(struct zl3073x_dev *dev, u32 value); + * + * Note that these functions have to be called with the device lock + * taken. + */ +#define __ZL3073X_REG_DEF(_name, _addr, _len, _type) \ +typedef _type zl3073x_##_name##_t; \ +static inline \ +int zl3073x_read_##_name(struct zl3073x_dev *zldev, _type * value) \ +{ \ + return zl3073x_read_reg(zldev, _addr, _len, value); \ +} \ +static inline \ +int zl3073x_write_##_name(struct zl3073x_dev *zldev, _type value) \ +{ \ + return zl3073x_write_reg(zldev, _addr, _len, &value); \ +} + +/** + * __ZL3073X_REG_IDX_DEF - Define an indexed device register helpers + * @_name: register name + * @_addr: register address + * @_len: size of register value in bytes + * @_type: type of register value + * @_num: number of register instances + * @_stride: address stride between instances + * + * The macro defines helper functions for particular indexed device + * register to access it. + * + * Example: + * __ZL3073X_REG_IDX_DEF(sample_reg, 0x1234, 2, u16, 4, 0x10) + * + * generates static inline functions: + * int zl3073x_read_sample_reg(struct zl3073x_dev *dev, unsigned int idx, + * u32 *value); + * int zl3073x_write_sample_reg(struct zl3073x_dev *dev, unsigned int idx, + * u32 value); + * + * Note that these functions have to be called with the device lock + * taken. + */ +#define __ZL3073X_REG_IDX_DEF(_name, _addr, _len, _type, _num, _stride) \ +typedef _type zl3073x_##_name##_t; \ +static inline \ +int zl3073x_read_##_name(struct zl3073x_dev *zldev, unsigned int idx, \ + _type * value) \ +{ \ + WARN_ON(idx >= (_num)); \ + return zl3073x_read_reg(zldev, (_addr) + idx * (_stride), _len, \ + value); \ +} \ +static inline \ +int zl3073x_write_##_name(struct zl3073x_dev *zldev, unsigned int idx, \ + _type value) \ +{ \ + WARN_ON(idx >= (_num)); \ + return zl3073x_write_reg(zldev, (_addr) + idx * (_stride), \ + _len, &value); \ +} + +/* + * Add register definition shortcuts for 8, 16, 32 and 48 bits + */ +#define ZL3073X_REG8_DEF(_name, _addr) __ZL3073X_REG_DEF(_name, _addr, 1, u8) +#define ZL3073X_REG16_DEF(_name, _addr) __ZL3073X_REG_DEF(_name, _addr, 2, u16) +#define ZL3073X_REG32_DEF(_name, _addr) __ZL3073X_REG_DEF(_name, _addr, 4, u32) +#define ZL3073X_REG48_DEF(_name, _addr) __ZL3073X_REG_DEF(_name, _addr, 6, u64) + +/* + * Add indexed register definition shortcuts for 8, 16, 32 and 48 bits + */ +#define ZL3073X_REG8_IDX_DEF(_name, _addr, _num, _stride) \ + __ZL3073X_REG_IDX_DEF(_name, _addr, 1, u8, _num, _stride) + +#define ZL3073X_REG16_IDX_DEF(_name, _addr, _num, _stride) \ + __ZL3073X_REG_IDX_DEF(_name, _addr, 2, u16, _num, _stride) + +#define ZL3073X_REG32_IDX_DEF(_name, _addr, _num, _stride) \ + __ZL3073X_REG_IDX_DEF(_name, _addr, 4, u32, _num, _stride) + +#define ZL3073X_REG48_IDX_DEF(_name, _addr, _num, _stride) \ + __ZL3073X_REG_IDX_DEF(_name, _addr, 6, u64, _num, _stride) + #endif /* __LINUX_MFD_ZL3073X_H */ From patchwork Mon Apr 7 17:28:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041389 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87B2D218AA0 for ; Mon, 7 Apr 2025 17:29:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046967; cv=none; b=oDOabBNzgeaN6LGKHozCWbokKryZerHiwxtljWHg7sDhKa4NaK7CuG1iBLK338yHXNdq6rDDD0YH8jxxvbXOYP7seQ6dtl1lMY/HnbXt0uXkIMNUth42z0vO13JifER+h7gb+VmZaMNTc5NHkqI2rQeq45eDwGrW+2TZRBN2mv0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046967; c=relaxed/simple; bh=oAp3VLk2xI6TpYWJRVO7zF8yUPRew6W+2d4xf3krwNw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hTS6Lu1ruELl38direIVDUJLbS95uBzo5RGE31eLeurj/5cXFgHedRd/TEFN2rMHvCaZMWxBFValnOUIZ21OOskM7RMzxv+Yvs2E8lPzFkj60h17XgJxVp3q9EY25jz0AUs1tTW9gP22huFkgqxomN0lvdSidkEKGjqJxYbq9JA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ZP4zeddv; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ZP4zeddv" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046964; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=43gtAzCXCfH36WcXLnzg04XdMF3g7xE31FVf+kgcQlk=; b=ZP4zeddvorfJgsIug5uUnM/0VcGb5KKQffxy1NFiU+gZgynf+FraNvaN/53MF/jkiO8xxE 5ocMW4Kzsl5qmRv3WLoDs9WZKhc3Isd+02mQQsjVA770GUO1lXWts48BCuqeq4GMwuZlTX TrtEYVLKg7K3L9eBGfU8h/k95IngXWc= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-100-BYAmFcKmPTahssuxqrowXA-1; Mon, 07 Apr 2025 13:29:18 -0400 X-MC-Unique: BYAmFcKmPTahssuxqrowXA-1 X-Mimecast-MFC-AGG-ID: BYAmFcKmPTahssuxqrowXA_1744046956 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1344C1800265; Mon, 7 Apr 2025 17:29:16 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DEE8C180B488; Mon, 7 Apr 2025 17:29:09 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 05/28] mfd: zl3073x: Add components versions register defs Date: Mon, 7 Apr 2025 19:28:32 +0200 Message-ID: <20250407172836.1009461-6-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Add register definitions for components versions and report them during probe. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index 39d4c8608a740..b3091b00cffa8 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -1,10 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include #include #include #include "zl3073x.h" +/* + * Register Map Page 0, General + */ +ZL3073X_REG16_DEF(id, 0x0001); +ZL3073X_REG16_DEF(revision, 0x0003); +ZL3073X_REG16_DEF(fw_ver, 0x0005); +ZL3073X_REG32_DEF(custom_config_ver, 0x0007); + /* * Regmap ranges */ @@ -159,10 +168,36 @@ EXPORT_SYMBOL_NS_GPL(zl3073x_dev_alloc, "ZL3073X"); int zl3073x_dev_init(struct zl3073x_dev *zldev) { + u16 id, revision, fw_ver; struct devlink *devlink; + u32 cfg_ver; + int rc; devm_mutex_init(zldev->dev, &zldev->lock); + scoped_guard(zl3073x, zldev) { + rc = zl3073x_read_id(zldev, &id); + if (rc) + return rc; + rc = zl3073x_read_revision(zldev, &revision); + if (rc) + return rc; + rc = zl3073x_read_fw_ver(zldev, &fw_ver); + if (rc) + return rc; + rc = zl3073x_read_custom_config_ver(zldev, &cfg_ver); + if (rc) + return rc; + } + + dev_info(zldev->dev, "ChipID(%X), ChipRev(%X), FwVer(%u)\n", + id, revision, fw_ver); + dev_info(zldev->dev, "Custom config version: %lu.%lu.%lu.%lu\n", + FIELD_GET(GENMASK(31, 24), cfg_ver), + FIELD_GET(GENMASK(23, 16), cfg_ver), + FIELD_GET(GENMASK(15, 8), cfg_ver), + FIELD_GET(GENMASK(7, 0), cfg_ver)); + devlink = priv_to_devlink(zldev); devlink_register(devlink); From patchwork Mon Apr 7 17:28:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041390 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E6E32217679 for ; Mon, 7 Apr 2025 17:29:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046970; cv=none; b=nZuUWTGpxMTZcfwvLBGP34zFug3tUDBJg2rDRHl2ZZIC2BTy7mj+CrPd9wWU+8qVdkQ12wplC0YuotEiB4weT+7yPi70G3BgQVkdnTDnHEtxPG5ES/+Pc6l7oUYS1yJ1NrgTBTHDzFLORYoH2NBu0RPaYjX1BfTynk4LWMwuCYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046970; c=relaxed/simple; bh=FNVfDjiAs80CxSrgw2joIxTPr3R1fwS+JdUgXRyMHws=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NjWqNl1IClgLAoKuXtd4GcYuTPUqHqbq1EK8QGVvYC/Lf+URrHVBaPLUaDYcKRIhk8gzu8IpQYIH68tl1rS6zzkNgdX9hwoeQV3ycVgzuu2GjOl3indNLLNyjbrbt5kLZfcgKiOSOn9/iHExZ3sv4ac47FQNXLzihqRR3eEnW64= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=gT02RBSN; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="gT02RBSN" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046968; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HuEW/SGI3isu0yVFd6QA70OIZUfyWajvSLe1fJC9qPY=; b=gT02RBSN/npL/8v5d+NYNIGFLY9IfNDCCD/t5XNqGa87qlYIbrDu3WK/P/E44RvdV+2pJ3 dLN9e9SePpKSR1R001LzGRnPjGI4hzvecp8Z2PiLp3mkPk2bCw0f4AJ4uB7veIWegoWnfy TJIANcfOsBXbc8zd1w5uO93UR0YOztI= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-644-ERpXse5eN2usobjcXKM-7g-1; Mon, 07 Apr 2025 13:29:24 -0400 X-MC-Unique: ERpXse5eN2usobjcXKM-7g-1 X-Mimecast-MFC-AGG-ID: ERpXse5eN2usobjcXKM-7g_1744046962 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 372AE1955DC6; Mon, 7 Apr 2025 17:29:22 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A49DE1828AA4; Mon, 7 Apr 2025 17:29:16 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 06/28] mfd: zl3073x: Implement devlink device info Date: Mon, 7 Apr 2025 19:28:33 +0200 Message-ID: <20250407172836.1009461-7-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Provide ASIC ID, ASIC revision, firmware version and optionally custom config version through devlink device info. Sample output: # devlink dev i2c/1-0070 # devlink dev info i2c/1-0070: driver zl3073x-i2c versions: fixed: asic.id 1E94 asic.rev 300 fw 7006 Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 73 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index b3091b00cffa8..33e76666e5694 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -142,7 +142,80 @@ int zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, } EXPORT_SYMBOL_GPL(zl3073x_write_reg); +/** + * zl3073x_devlink_info_get - Devlink device info callback + * @devlink: devlink structure pointer + * @req: devlink request pointer to store information + * @extack: netlink extack pointer to report errors + * + * Returns 0 in case of success or negative value otherwise + */ +static int zl3073x_devlink_info_get(struct devlink *devlink, + struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dev *zldev = devlink_priv(devlink); + u16 id, revision, fw_ver; + char buf[16]; + u32 cfg_ver; + int rc; + + guard(zl3073x)(zldev); + + rc = zl3073x_read_id(zldev, &id); + if (rc) + return rc; + + snprintf(buf, sizeof(buf), "%X", id); + rc = devlink_info_version_fixed_put(req, + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, + buf); + if (rc) + return rc; + + rc = zl3073x_read_revision(zldev, &revision); + if (rc) + return rc; + + snprintf(buf, sizeof(buf), "%X", revision); + rc = devlink_info_version_fixed_put(req, + DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, + buf); + if (rc) + return rc; + + rc = zl3073x_read_fw_ver(zldev, &fw_ver); + if (rc) + return rc; + + snprintf(buf, sizeof(buf), "%u", fw_ver); + rc = devlink_info_version_fixed_put(req, + DEVLINK_INFO_VERSION_GENERIC_FW, + buf); + if (rc) + return rc; + + rc = zl3073x_read_custom_config_ver(zldev, &cfg_ver); + if (rc) + return rc; + + /* No custom config version */ + if (cfg_ver == U32_MAX) + return rc; + + snprintf(buf, sizeof(buf), "%lu.%lu.%lu.%lu", + FIELD_GET(GENMASK(31, 24), cfg_ver), + FIELD_GET(GENMASK(23, 16), cfg_ver), + FIELD_GET(GENMASK(15, 8), cfg_ver), + FIELD_GET(GENMASK(7, 0), cfg_ver)); + + rc = devlink_info_version_running_put(req, "cfg.custom_ver", buf); + + return rc; +} + static const struct devlink_ops zl3073x_devlink_ops = { + .info_get = zl3073x_devlink_info_get, }; static void zl3073x_devlink_free(void *ptr) From patchwork Mon Apr 7 17:28:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041391 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A0B79218EBD for ; Mon, 7 Apr 2025 17:29:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046977; cv=none; b=joKYRdVHk0B0IEJucQIv/yJdgZYs+dUgfusBBJuN2vxg57HCCZS+ljGrRJokVJ3XGacoxTIj1ScdwpGj0KJm6fo0mxF7xSHw6t3OuW03cAGC0v9J9kCXhna6xCp4CctUpGcyn6owq2VtN0PyHkLjBtuloxRLOiRgG6qu696MpwQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046977; c=relaxed/simple; bh=YwQffT1aEOqjVu4z07Zs99qG9yuGlwLKY9+dxNhxdYE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Tc17oCB7p9SZ3ncJJeVGJGj+mvFNqwhV+p8GCisMzBUB4/qoRm/W5RvSCyeW2QLoGCia+B5Lip0RjUxlda5MqQCBlmASJKgQDZyY2lYeSCX7gMo5LtKWCyZwaplXKtRUKBVns/V4wYtMhpS2N+2CNBV3alxur2MEmAEcsWBSKdU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=D08m+zu6; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="D08m+zu6" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046974; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Tuo2BZQlvc9qC7nHzNWOv25fLG9mfraZRBCulBhhTKU=; b=D08m+zu6sZUOMXqW4vM5vu30wWOK+YF5Tv2/s2sUUJeE4g0d/+QmfmsklM0np/KVyJALkH Jnk2WI9K8ju/tPPbhs8L9w4mDojIs3zdzeG+sAjP3vZVce/HtYj/mu5NoATuGq31weizME XMBh8E70cXgE/0ejXIvJ0khkSAhKa3w= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-611-TTjZY9N5OYaat_BzfeyQrQ-1; Mon, 07 Apr 2025 13:29:30 -0400 X-MC-Unique: TTjZY9N5OYaat_BzfeyQrQ-1 X-Mimecast-MFC-AGG-ID: TTjZY9N5OYaat_BzfeyQrQ_1744046968 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 780A91801A1A; Mon, 7 Apr 2025 17:29:28 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C6684180A803; Mon, 7 Apr 2025 17:29:22 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 07/28] mfd: zl3073x: Add macro to wait for register value bits to be cleared Date: Mon, 7 Apr 2025 19:28:34 +0200 Message-ID: <20250407172836.1009461-8-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Sometimes in communication with the device is necessary to set certain bit(s) in certain register and then the driver has to wait until these bits are cleared by the device. Add the macro for this functionality, it will be used by later commits. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- include/linux/mfd/zl3073x.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h index 3524426f0e3ba..15dfb0d8bf3cb 100644 --- a/include/linux/mfd/zl3073x.h +++ b/include/linux/mfd/zl3073x.h @@ -143,4 +143,33 @@ int zl3073x_write_##_name(struct zl3073x_dev *zldev, unsigned int idx, \ #define ZL3073X_REG48_IDX_DEF(_name, _addr, _num, _stride) \ __ZL3073X_REG_IDX_DEF(_name, _addr, 6, u64, _num, _stride) +/** + * zl3073x_wait_clear_bits - wait for specific bits to be cleared + * _zldev: pointer to device structure + * _reg: register name + * _bits: bits that should be cleared + * _index: optional index for indexed register + * + * The macro waits up to @READ_TIMEOUT_US microseconds for @_bits in @_reg + * to be cleared. + * + * Returns: + * -ETIMEDOUT: if timeout occurred + * <0: for other errors occurred during communication + * 0: success + */ +#define READ_SLEEP_US 10 +#define READ_TIMEOUT_US 2000000 +#define zl3073x_wait_clear_bits(_zldev, _reg, _bits, _index...) \ +({ \ + zl3073x_##_reg##_t __val; \ + int __rc; \ + if (read_poll_timeout(zl3073x_read_##_reg, __rc, \ + __rc || !((_bits) & __val), \ + READ_SLEEP_US, READ_TIMEOUT_US, false, \ + _zldev, ##_index, &__val)) \ + __rc = -ETIMEDOUT; \ + __rc; \ +}) + #endif /* __LINUX_MFD_ZL3073X_H */ From patchwork Mon Apr 7 17:28:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041393 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1347219A71 for ; Mon, 7 Apr 2025 17:29:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046984; cv=none; b=FpCXPYVZff9HQbeLY/O+FHxyFPrcu+827fUdFHe9lHGwg8UlviUJVvvnHdbsfMQJWzKiXLe3VEFMHhxfMtzIg6A+adWNBDkIWqa4be5pZ4QTX2+P1npcQTyiCjY+ZfrOSNKtqkwCvJyFS7QpcpYlKjVqSgaZdXMielscUuV3Uvs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046984; c=relaxed/simple; bh=wDmeRftlsS2sqydvwRCNqk8/b4bEE1BAgviZ0NhpHSo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=e8WMOvM4KekHOvlnW9i9TRsJnwuDMaMfA6BncQWuYy4kjWIcsyXieu+4/twSztTpYAHZZg7OBN574sssFGVhAtc31qbb6I40j6JUd9dsgAR/FwzWQrhMr4sGfe1rnt2iP7hyl5SawZl8J/HGD1dJmbDyv5oJAFXqm4F7ceNsseE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=W8xww8Lh; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="W8xww8Lh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046981; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bq6Q2Xg910WZ/PMWAwQHXShcurBaXkPUyBU7V9wKSVo=; b=W8xww8LhVMEvSkk09YbAqnWrs8uKw8SHmx7DkB1S6f6SdgHYvMde3bNK5Fj9uoTVMD8MWH SPw07Mj9iBNXT42qBhwS08U8i8wU8daRXPTafjQoamJYU5l1BE9bIUA3UsxhvRVDgL7c9U SxI5Xs5A7lhZNf488yT6Dnw3Eyytt5o= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-635-QWT19wWEPYWM_ks2F_HFYA-1; Mon, 07 Apr 2025 13:29:37 -0400 X-MC-Unique: QWT19wWEPYWM_ks2F_HFYA-1 X-Mimecast-MFC-AGG-ID: QWT19wWEPYWM_ks2F_HFYA_1744046974 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 948E9180AF50; Mon, 7 Apr 2025 17:29:34 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0EDE9180A803; Mon, 7 Apr 2025 17:29:28 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 08/28] mfd: zl3073x: Add functions to work with register mailboxes Date: Mon, 7 Apr 2025 19:28:35 +0200 Message-ID: <20250407172836.1009461-9-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Registers present in page 10 and higher are organized in so-called register mailboxes. These mailboxes are used to read and write configuration of particular object (dpll, output, reference & synth). Each of these register pages contains mask register that is used by the driver to indicate an index of requested object to work with and also semaphore register to indicate what operation is requested. The rest of registers in the particular register page are latch registers that are filled by the firmware during read operation or by the driver prior write operation. For read operation the driver... 1) ... updates the mailbox mask register with index of particular object 2) ... sets the mailbox semaphore register read bit 3) ... waits for the semaphore register read bit to be cleared by FW 4) ... reads the configuration from latch registers For write operation the driver... 1) ... writes the requested configuration to latch registers 2) ... sets the mailbox mask register for the DPLL to be updated 3) ... sets the mailbox semaphore register bit for the write operation 4) ... waits for the semaphore register bit to be cleared by FW Add functions to read and write mailboxes for all supported object types. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 185 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/zl3073x.h | 12 +++ 2 files changed, 197 insertions(+) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index 33e76666e5694..feb139b550571 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -14,6 +14,47 @@ ZL3073X_REG16_DEF(revision, 0x0003); ZL3073X_REG16_DEF(fw_ver, 0x0005); ZL3073X_REG32_DEF(custom_config_ver, 0x0007); +/* + * Register Map Page 10, Ref Mailbox + */ +ZL3073X_REG16_DEF(ref_mb_mask, 0x502); +#define REF_MB_MASK GENMASK(9, 0) + +ZL3073X_REG8_DEF(ref_mb_sem, 0x504); +#define REF_MB_SEM_WR BIT(0) +#define REF_MB_SEM_RD BIT(1) + +/* + * Register Map Page 12, DPLL Mailbox + */ +ZL3073X_REG16_DEF(dpll_mb_mask, 0x602); + +ZL3073X_REG8_DEF(dpll_mb_sem, 0x604); +#define DPLL_MB_SEM_WR BIT(0) +#define DPLL_MB_SEM_RD BIT(1) + +/* + * Register Map Page 13, Synth Mailbox + */ +ZL3073X_REG16_DEF(synth_mb_mask, 0x682); + +ZL3073X_REG8_DEF(synth_mb_sem, 0x684); +#define SYNTH_MB_SEM_WR BIT(0) +#define SYNTH_MB_SEM_RD BIT(1) + +ZL3073X_REG16_DEF(synth_freq_base, 0x686); +ZL3073X_REG32_DEF(synth_freq_mult, 0x688); +ZL3073X_REG16_DEF(synth_freq_m, 0x68c); +ZL3073X_REG16_DEF(synth_freq_n, 0x68e); + +/* + * Register Map Page 14, Output Mailbox + */ +ZL3073X_REG16_DEF(output_mb_mask, 0x702); +ZL3073X_REG8_DEF(output_mb_sem, 0x704); +#define OUTPUT_MB_SEM_WR BIT(0) +#define OUTPUT_MB_SEM_RD BIT(1) + /* * Regmap ranges */ @@ -142,6 +183,150 @@ int zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, } EXPORT_SYMBOL_GPL(zl3073x_write_reg); +/** + * ZL3073X_MB_OP - perform an operation on mailbox of certain type + * @_zldev: pointer to device structure + * @_type: type of mailbox (dpll, ref or output) + * @_index: object index of given type + * @_op: operation to perform + * + * Performs the requested operation on mailbox of certain type and + * returns 0 in case of success or negative value otherwise. + */ +#define ZL3073X_MB_OP(_zldev, _type, _index, _op) \ +({ \ + struct zl3073x_dev *__zldev = (_zldev); \ + u16 __mask = BIT(_index); \ + u8 __op = (_op); \ + int __rc; \ + do { \ + /* Select requested index in mask register */ \ + __rc = zl3073x_write_##_type##_mb_mask(__zldev, __mask);\ + if (__rc) \ + break; \ + /* Select requested command */ \ + __rc = zl3073x_write_##_type##_mb_sem(__zldev, __op); \ + if (__rc) \ + break; \ + /* Wait for the command to actually finish */ \ + __rc = zl3073x_wait_clear_bits(__zldev, _type##_mb_sem, \ + __op); \ + } while (0); \ + __rc; \ +}) + +/** + * zl3073x_mb_dpll_read - read given DPLL configuration to mailbox + * @zldev: pointer to device structure + * @index: DPLL index + * + * Reads configuration of given DPLL into DPLL mailbox and returns 0 + * in case of success or negative value otherwise. + */ +int zl3073x_mb_dpll_read(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, dpll, index, DPLL_MB_SEM_RD); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_dpll_read); + +/** + * zl3073x_mb_dpll_write - write given DPLL configuration from mailbox + * @zldev: pointer to device structure + * @index: DPLL index + * + * Writes (commits) configuration of given DPLL from DPLL mailbox and + * returns 0 in case of success or negative value otherwise. + */ +int zl3073x_mb_dpll_write(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, dpll, index, DPLL_MB_SEM_WR); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_dpll_write); + +/** + * zl3073x_mb_output_read - read given output configuration to mailbox + * @zldev: pointer to device structure + * @index: output index + * + * Reads configuration of given output into output mailbox and returns 0 + * in case of success or negative value otherwise. + */ +int zl3073x_mb_output_read(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, output, index, OUTPUT_MB_SEM_RD); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_output_read); + +/** + * zl3073x_mb_output_write - write given output configuration from mailbox + * @zldev: pointer to device structure + * @index: DPLL index + * + * Writes (commits) configuration of given output from output mailbox and + * returns 0 in case of success or negative value otherwise. + */ +int zl3073x_mb_output_write(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, output, index, OUTPUT_MB_SEM_WR); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_output_write); + +/** + * zl3073x_mb_ref_read - read given reference configuration to mailbox + * @zldev: pointer to device structure + * @index: reference index + * + * Reads configuration of given reference into reference mailbox and + * returns 0 in case of success or negative value otherwise. + */ +int zl3073x_mb_ref_read(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, ref, index, REF_MB_SEM_RD); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_ref_read); + +/** + * zl3073x_mb_ref_write - write given reference configuration from mailbox + * @zldev: pointer to device structure + * @index: reference index + * + * Writes (commits) configuration of given reference from reference mailbox + * and returns 0 in case of success or negative value otherwise. + */ +int zl3073x_mb_ref_write(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, ref, index, REF_MB_SEM_WR); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_ref_write); + +/** + * zl3073x_mb_synth_read - read given synth configuration to mailbox + * @zldev: pointer to device structure + * @index: synth index + * + * Reads configuration of given synth into synth mailbox and returns 0 + * in case of success or negative value otherwise. + */ +int zl3073x_mb_synth_read(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, synth, index, SYNTH_MB_SEM_RD); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_synth_read); + +/** + * zl3073x_mb_synth_write - write given synth configuration from mailbox + * @zldev: pointer to device structure + * @index: synth index + * + * Writes (commits) configuration of given synth from reference mailbox + * and returns 0 in case of success or negative value otherwise. + */ +int zl3073x_mb_synth_write(struct zl3073x_dev *zldev, u8 index) +{ + return ZL3073X_MB_OP(zldev, synth, index, SYNTH_MB_SEM_WR); +} +EXPORT_SYMBOL_GPL(zl3073x_mb_synth_write); + /** * zl3073x_devlink_info_get - Devlink device info callback * @devlink: devlink structure pointer diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h index 15dfb0d8bf3cb..436f79f2fda63 100644 --- a/include/linux/mfd/zl3073x.h +++ b/include/linux/mfd/zl3073x.h @@ -172,4 +172,16 @@ int zl3073x_write_##_name(struct zl3073x_dev *zldev, unsigned int idx, \ __rc; \ }) +/* + * Mailbox operations + */ +int zl3073x_mb_dpll_read(struct zl3073x_dev *zldev, u8 index); +int zl3073x_mb_dpll_write(struct zl3073x_dev *zldev, u8 index); +int zl3073x_mb_output_read(struct zl3073x_dev *zldev, u8 index); +int zl3073x_mb_output_write(struct zl3073x_dev *zldev, u8 index); +int zl3073x_mb_ref_read(struct zl3073x_dev *zldev, u8 index); +int zl3073x_mb_ref_write(struct zl3073x_dev *zldev, u8 index); +int zl3073x_mb_synth_read(struct zl3073x_dev *zldev, u8 index); +int zl3073x_mb_synth_write(struct zl3073x_dev *zldev, u8 index); + #endif /* __LINUX_MFD_ZL3073X_H */ From patchwork Mon Apr 7 17:28:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041394 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3687722155B for ; Mon, 7 Apr 2025 17:29:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046988; cv=none; b=K9sfI2ZV2uyXYD8dGY+6wMzfe2XA4/iAXeTVqrOil8HTqxfCZdT77oqo+rDc+xXrzsNgNfSSaCFvyXxeGONbDpfkQx641djXbneEQ0I+hdwK6m/p0FOpP+bplbUzd/fj6WfsL3QsQS42Gg7WRbOHRo4cKafPtAWrUxcsVfAhJ/U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744046988; c=relaxed/simple; bh=IZDE0Uw0REW2EC3YQAqzGRfFqccTqKOe6rIV8GxvYuo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LSKHyb6UlIKuTYYRdxX6atNvqdLvu2fiizZs6+OPAE3ESfCi2qbpxDDmVgU/bGmxqH6jZJnNWafrRE4vjC5i8pELfLAjGA9tKUHdaPCSSr3zSqUNuFWMxCkhTua4CmGSyTj/9qfuUpewUox2SKWRH6fppWqlg3iWXFocUGa34Vg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=S++0GXc4; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="S++0GXc4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744046986; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ytfag6avHkUgxMB2gcbfrMctmdRXvNMuEhL6eCeBh8c=; b=S++0GXc4auaVluDYkUgFtA2n4XUk62l3T0ZNdNEkuKjpHbMANrAuK/6v6/+VGDk0SRrheW CwzJwjgrEZ356mYXpepSJhDSUMt2QSDvjc4YBtSWrgJpI2mYZQpDDS1QWIFIYBnNipQY59 W2ArvqXesd9jJWQF4LFX3JT6/3EqNXo= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-650-bek0G_IQM-mH5jKEpyPM1w-1; Mon, 07 Apr 2025 13:29:43 -0400 X-MC-Unique: bek0G_IQM-mH5jKEpyPM1w-1 X-Mimecast-MFC-AGG-ID: bek0G_IQM-mH5jKEpyPM1w_1744046981 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D4296195608B; Mon, 7 Apr 2025 17:29:40 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 19686180A803; Mon, 7 Apr 2025 17:29:34 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 09/28] mfd: zl3073x: Add clock_id field Date: Mon, 7 Apr 2025 19:28:36 +0200 Message-ID: <20250407172836.1009461-10-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Later commits that add support for DPLL functionality need a clock ID for DPLL device registration. To generate such ID use chip ID read during device initialization for this. For the case where are multiple zl3073x based chips the chip ID is shifted and lower bits are filled by an unique value. For I2C case it is I2C device address and for SPI case it is chip-select value. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 5 ++++- drivers/mfd/zl3073x-i2c.c | 3 ++- drivers/mfd/zl3073x-spi.c | 3 ++- drivers/mfd/zl3073x.h | 2 +- include/linux/mfd/zl3073x.h | 1 + 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index feb139b550571..5570de58c46e4 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -424,7 +424,7 @@ struct zl3073x_dev *zl3073x_dev_alloc(struct device *dev) } EXPORT_SYMBOL_NS_GPL(zl3073x_dev_alloc, "ZL3073X"); -int zl3073x_dev_init(struct zl3073x_dev *zldev) +int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id) { u16 id, revision, fw_ver; struct devlink *devlink; @@ -448,6 +448,9 @@ int zl3073x_dev_init(struct zl3073x_dev *zldev) return rc; } + /* Use chip ID and given dev ID as clock ID */ + zldev->clock_id = ((u64)id << 8) | dev_id; + dev_info(zldev->dev, "ChipID(%X), ChipRev(%X), FwVer(%u)\n", id, revision, fw_ver); dev_info(zldev->dev, "Custom config version: %lu.%lu.%lu.%lu\n", diff --git a/drivers/mfd/zl3073x-i2c.c b/drivers/mfd/zl3073x-i2c.c index 8c8b2ba176766..ae7079d9359c1 100644 --- a/drivers/mfd/zl3073x-i2c.c +++ b/drivers/mfd/zl3073x-i2c.c @@ -41,7 +41,8 @@ static int zl3073x_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, zldev); - return zl3073x_dev_init(zldev); + /* Initialize device and use I2C address as dev ID */ + return zl3073x_dev_init(zldev, client->addr); } static void zl3073x_i2c_remove(struct i2c_client *client) diff --git a/drivers/mfd/zl3073x-spi.c b/drivers/mfd/zl3073x-spi.c index a6b9a366a7585..6877ca1664111 100644 --- a/drivers/mfd/zl3073x-spi.c +++ b/drivers/mfd/zl3073x-spi.c @@ -42,7 +42,8 @@ static int zl3073x_spi_probe(struct spi_device *spidev) spi_set_drvdata(spidev, zldev); - return zl3073x_dev_init(zldev); + /* Initialize device and use SPI chip select value as dev ID */ + return zl3073x_dev_init(zldev, spi_get_chipselect(spidev, 0)); } static void zl3073x_spi_remove(struct spi_device *spidev) diff --git a/drivers/mfd/zl3073x.h b/drivers/mfd/zl3073x.h index 582cb40d681d3..04612313d32a9 100644 --- a/drivers/mfd/zl3073x.h +++ b/drivers/mfd/zl3073x.h @@ -6,7 +6,7 @@ #include struct zl3073x_dev *zl3073x_dev_alloc(struct device *dev); -int zl3073x_dev_init(struct zl3073x_dev *zldev); +int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id); void zl3073x_dev_exit(struct zl3073x_dev *zldev); const struct regmap_config *zl3073x_get_regmap_config(void); diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h index 436f79f2fda63..a18eddbc03709 100644 --- a/include/linux/mfd/zl3073x.h +++ b/include/linux/mfd/zl3073x.h @@ -9,6 +9,7 @@ struct zl3073x_dev { struct device *dev; struct regmap *regmap; + u64 clock_id; struct mutex lock; }; From patchwork Mon Apr 7 17:31:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041416 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 85E6721577A for ; Mon, 7 Apr 2025 17:32:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047122; cv=none; b=XyzqE3d5JTxlaF559uCyGmdg57Ktv/Q6/e3sEVLXEnR7a4PM70CaPovF9/Vm69og+d7d/FNKnMDsfN2QMH8E1Xr56lguodt0XWGVJuuz8Bvbt4h5IUe0VzU8qUu0CrWk5MpkjKBA2kkbnO6KF/sErMMcTKK8N9wuOxharnsPhOA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047122; c=relaxed/simple; bh=WEcD/AXqDi/lML5ocoRfoM1M6Q3z5GDI2jHwFmoZKWo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SGWUMdU7LzRlSYTiGJ/2qcjyL9/lHr2xFfhFgXGNNKNzvc6r++SDDFDlETCp41dCLSMAJbD4N7kq0iAjkhgA1bIOgBgtIeqFVWTFM/k6B1Q5qaM5aC5Y+Dhe8LYpiQ4DaKi62RGGEK950TH6SxRJjc0LcKAU4VypZ20UMQT91ho= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ZOhqT5Rq; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ZOhqT5Rq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047119; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=U6e5YEd4i8Igzt8FZC6HGuBFALFj9tH6sGb59/Wh5h4=; b=ZOhqT5RqN9KgDFLGrWitV9wLJsypfYWP/qmQCj9f2OhAnH0n3tcrGHFJ6KUEutRid2L7If pir8LrgfY0iYoEZrCtQrGgCCPMZ0qC+Zp4kkL0nKqqK07BHYcdLpTx/3YfybCOqHVQM1vd 7YSDqNAyXqg0wfR6S4Y6hOwLfVRP7OM= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-683-cNQUs-B1PqudVnQAh9X6bA-1; Mon, 07 Apr 2025 13:31:58 -0400 X-MC-Unique: cNQUs-B1PqudVnQAh9X6bA-1 X-Mimecast-MFC-AGG-ID: cNQUs-B1PqudVnQAh9X6bA_1744047116 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 53E2419560BE; Mon, 7 Apr 2025 17:31:56 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D877F1956094; Mon, 7 Apr 2025 17:31:50 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 10/28] lib: Allow modules to use strnchrnul Date: Mon, 7 Apr 2025 19:31:40 +0200 Message-ID: <20250407173149.1010216-1-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 Commit 0bee0cece2a6a ("lib/string: add strnchrnul()") added the mentioned function but did not export it so it cannot be used by modules. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera Acked-by: Kees Cook --- lib/string.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/string.c b/lib/string.c index eb4486ed40d25..824b3aac86de0 100644 --- a/lib/string.c +++ b/lib/string.c @@ -363,6 +363,7 @@ char *strnchrnul(const char *s, size_t count, int c) s++; return (char *)s; } +EXPORT_SYMBOL(strnchrnul); #ifndef __HAVE_ARCH_STRRCHR /** From patchwork Mon Apr 7 17:31:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041417 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 009512165ED for ; Mon, 7 Apr 2025 17:32:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047131; cv=none; b=j4PbLq1Y0gzoqhfb5dOy4C0mIXY0C3uuRFXXsqtryHaqnDbziNVjFwTsnqE8OW7KpeppJNDCRCIvJ5mN+OUCAMCwFB9WfO7RmCMeS9JHiwCB7IGTXOuJBXaHGB3B/X6FOkeBJoW1tG7my/IQsVypt4XMZDvwonbzpGEmL9fJ2Ng= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047131; c=relaxed/simple; bh=514kAmrhGuHv4oZb4ZbGQ+3ynXJnMvwu1BF8ij5YNts=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RAC8zHyatSzRa2rXQmCTeTSKELt29Znmp2Mm9mnEJ8PCzNdcyWty3moYdwBtGL1XLMjWZ5+JD3VQhKYzCY3tYmY7FPThn1It89xrpKdm/fcpr2ORBtyC5shOfDPOrOtDBac/NTjTLPVgdNAPpMS1ZU3kku3ByblO5gkhG9rDiZQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=LfgpScDF; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="LfgpScDF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047129; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fGIjBEcrhQWS3vGRuAYETRUbaEuHXfFrZ4Y6pHxlPf0=; b=LfgpScDFBJ84cvHbmNtcjfKR45426h/qy9TEHlCZ/JJqNxzrcAZIs1mzsRdO4IcU+kq9BS 48PtIsRIJ4ob5FXtNYkVq9o0Jvpp9b4X7uebs1YRoTs5rC1X8L0TPeIg7I+6k8GU6VsN36 /zWiO01ALP12jnnu6bH9TzHxLQpHp10= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-609-iXQzf7EmMXS-JL9YSKuBcg-1; Mon, 07 Apr 2025 13:32:05 -0400 X-MC-Unique: iXQzf7EmMXS-JL9YSKuBcg-1 X-Mimecast-MFC-AGG-ID: iXQzf7EmMXS-JL9YSKuBcg_1744047122 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9749D18001FC; Mon, 7 Apr 2025 17:32:02 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E27C91956094; Mon, 7 Apr 2025 17:31:56 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 11/28] mfd: zl3073x: Load mfg file into HW if it is present Date: Mon, 7 Apr 2025 19:31:41 +0200 Message-ID: <20250407173149.1010216-2-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 Add support for loading mfg file that can be provided by a user. The mfg file can be generated by Microchip tool and contains snippets of device configuration that is different from the one stored in the flash memory inside the chip. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 106 +++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index 5570de58c46e4..9920c5329d50f 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -424,6 +424,108 @@ struct zl3073x_dev *zl3073x_dev_alloc(struct device *dev) } EXPORT_SYMBOL_NS_GPL(zl3073x_dev_alloc, "ZL3073X"); +static int zl3073x_fw_parse_line(struct zl3073x_dev *zldev, const char *line) +{ +#define ZL3073X_FW_WHITESPACES_SIZE 3 +#define ZL3073X_FW_COMMAND_SIZE 1 + const char *ptr = line; + char *endp; + u32 delay; + u16 addr; + u8 val; + + switch (ptr[0]) { + case 'X': + /* The line looks like this: + * X , ADDR , VAL + * Where: + * - X means that is a command that needs to be executed + * - ADDR represents the addr and is always 2 bytes and the + * value is in hex, for example 0x0232 + * - VAL represents the value that is written and is always 1 + * byte and the value is in hex, for example 0x12 + */ + ptr += ZL3073X_FW_COMMAND_SIZE; + ptr += ZL3073X_FW_WHITESPACES_SIZE; + addr = simple_strtoul(ptr, &endp, 16); + + ptr = endp; + ptr += ZL3073X_FW_WHITESPACES_SIZE; + val = simple_strtoul(ptr, NULL, 16); + + /* Write requested value to given register */ + return zl3073x_write_reg(zldev, addr, 1, &val); + case 'W': + /* The line looks like this: + * W , DELAY + * Where: + * - W means that is a wait command + * - DELAY represents the delay in microseconds and the value + * is in decimal + */ + ptr += ZL3073X_FW_COMMAND_SIZE; + ptr += ZL3073X_FW_WHITESPACES_SIZE; + delay = simple_strtoul(ptr, NULL, 10); + + fsleep(delay); + break; + default: + break; + } + + return 0; +} + +#define ZL3073X_MFG_FILE "microchip/zl3073x.mfg" + +static void zl3073x_fw_load(struct zl3073x_dev *zldev) +{ + const struct firmware *fw; + const char *ptr, *end; + char buf[128]; + int rc; + + rc = firmware_request_nowarn(&fw, ZL3073X_MFG_FILE, zldev->dev); + if (rc) + return; + + dev_info(zldev->dev, "Applying mfg file %s...\n", ZL3073X_MFG_FILE); + + guard(zl3073x)(zldev); + + ptr = fw->data; + end = ptr + fw->size; + while (ptr < end) { + /* Get next end of the line or end of buffer */ + char *eol = strnchrnul(ptr, end - ptr, '\n'); + size_t len = eol - ptr; + + /* Check line length */ + if (len >= sizeof(buf)) { + dev_err(zldev->dev, "Line in firmware is too long\n"); + return; + } + + /* Copy line from buffer */ + memcpy(buf, ptr, len); + buf[len] = '\0'; + + /* Parse and process the line */ + rc = zl3073x_fw_parse_line(zldev, buf); + if (rc) { + dev_err(zldev->dev, + "Failed to parse firmware line: %pe\n", + ERR_PTR(rc)); + break; + } + + /* Move to next line */ + ptr = eol + 1; + } + + release_firmware(fw); +} + int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id) { u16 id, revision, fw_ver; @@ -451,6 +553,9 @@ int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id) /* Use chip ID and given dev ID as clock ID */ zldev->clock_id = ((u64)id << 8) | dev_id; + /* Load mfg file if present */ + zl3073x_fw_load(zldev); + dev_info(zldev->dev, "ChipID(%X), ChipRev(%X), FwVer(%u)\n", id, revision, fw_ver); dev_info(zldev->dev, "Custom config version: %lu.%lu.%lu.%lu\n", @@ -475,3 +580,4 @@ EXPORT_SYMBOL_NS_GPL(zl3073x_dev_exit, "ZL3073X"); MODULE_AUTHOR("Ivan Vecera "); MODULE_DESCRIPTION("Microchip ZL3073x core driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(ZL3073X_MFG_FILE); From patchwork Mon Apr 7 17:31:42 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041418 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DC81821B1AB for ; Mon, 7 Apr 2025 17:32:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047136; cv=none; b=L1FOIL+4sECNtnlOustmrPN8mrmw7fttNuVKS9cbM5z/ASfZsCXZWt2n3X26vM/XWPQzIqdYVSYRSNCHjX+RLhKKaHcrgfSxWLRXihKfs+Q4jRb2PRG+psKD5DQHt9cvpEZu+YcZ1u6a+emnE9AqjEL91h7bKR1piRZT6RRmh7E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047136; c=relaxed/simple; bh=e0vMF5XBbEvwyL68baY4pvsuRtPw//ZbXskekj6bNaQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qxHuGH9EJv/xkYmpMcm85zTAkm7HCt9TEzVWYZ35HJaXyxLOjSZjZJEvsvRqJtnTdftDO86y66BmejJhdZtdpm/ckLO5EYTy89asWPtQn9LjiEFhJ3avRtAaO+igA3U+UsLVMosC40Ot8w3N99ukJ4TVjCCVSRlHhud2kqU2y8I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=IXMfy/Dk; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="IXMfy/Dk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047133; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cwwDNQaG9gg5NtaHn8oXyPn+lCzMmbq2wq4r/S5IuwQ=; b=IXMfy/DkYQLyFko41zsL1VtjIfFixXHLOENNxWRIvxhgIHhWx++wO0zWnwsjtj2ZrH+TVn ykPMzU3gvGrKWzkCLu4aPrFdqvkeg86lLH7Y9VEMDDNqY7I0oPZA4V8jWMR8SFpkuwy6ID WNYH3ScQgKzyyEpxq/aX7YfijoPM7AQ= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-74-FgmN3PJ5Mc2yt08UUIltVg-1; Mon, 07 Apr 2025 13:32:11 -0400 X-MC-Unique: FgmN3PJ5Mc2yt08UUIltVg-1 X-Mimecast-MFC-AGG-ID: FgmN3PJ5Mc2yt08UUIltVg_1744047128 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B220F19560B0; Mon, 7 Apr 2025 17:32:08 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1CCD01955BC0; Mon, 7 Apr 2025 17:32:02 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 12/28] mfd: zl3073x: Fetch invariants during probe Date: Mon, 7 Apr 2025 19:31:42 +0200 Message-ID: <20250407173149.1010216-3-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 Several configuration parameters will not be changed in runtime so we can load them during probe to avoid excessive reads from the hardware. The following parameters are read and stored for later use: * synthesizers' frequencies and associated DPLL channel * input pins' enablement and type (single-ended or differential) * outputs'associated synths, signal format and enablement These parameters will be frequently read by the DPLL driver from this series and later by PHC/PTP sub-device driver. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 241 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/zl3073x.h | 142 +++++++++++++++++++++ 2 files changed, 383 insertions(+) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index 9920c5329d50f..9ed405a62fa86 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -14,6 +14,20 @@ ZL3073X_REG16_DEF(revision, 0x0003); ZL3073X_REG16_DEF(fw_ver, 0x0005); ZL3073X_REG32_DEF(custom_config_ver, 0x0007); +/* + * Register Map Page 9, Synth and Output + */ +ZL3073X_REG8_IDX_DEF(synth_ctrl, 0x480, ZL3073X_NUM_SYNTHS, 1); +#define SYNTH_CTRL_EN BIT(0) +#define SYNTH_CTRL_DPLL_SEL GENMASK(6, 4) + +ZL3073X_REG8_IDX_DEF(output_ctrl, 0x4a8, ZL3073X_NUM_OUTPUTS, 1); +#define OUTPUT_CTRL_EN BIT(0) +#define OUTPUT_CTRL_STOP BIT(1) +#define OUTPUT_CTRL_STOP_HIGH BIT(2) +#define OUTPUT_CTRL_STOP_HZ BIT(3) +#define OUTPUT_CTRL_SYNTH_SEL GENMASK(6, 4) + /* * Register Map Page 10, Ref Mailbox */ @@ -24,6 +38,10 @@ ZL3073X_REG8_DEF(ref_mb_sem, 0x504); #define REF_MB_SEM_WR BIT(0) #define REF_MB_SEM_RD BIT(1) +ZL3073X_REG8_DEF(ref_config, 0x50d); +#define REF_CONFIG_ENABLE BIT(0) +#define REF_CONFIG_DIFF_EN BIT(2) + /* * Register Map Page 12, DPLL Mailbox */ @@ -55,6 +73,9 @@ ZL3073X_REG8_DEF(output_mb_sem, 0x704); #define OUTPUT_MB_SEM_WR BIT(0) #define OUTPUT_MB_SEM_RD BIT(1) +ZL3073X_REG8_DEF(output_mode, 0x705); +#define OUTPUT_MODE_SIGNAL_FORMAT GENMASK(7, 4) + /* * Regmap ranges */ @@ -526,6 +547,219 @@ static void zl3073x_fw_load(struct zl3073x_dev *zldev) release_firmware(fw); } +/** + * zl3073x_input_state_fetch - get input state + * @zldev: pointer to zl3073x_dev structure + * @index: input pin index to fetch state for + * + * Function fetches information for the given input reference that are + * invariant and stores them for later use. + * + * Returns 0 in case of success or negative value in error case. + */ +static int +zl3073x_input_state_fetch(struct zl3073x_dev *zldev, u8 index) +{ + struct zl3073x_input *input; + u8 ref_config; + int rc; + + if (index >= ZL3073X_NUM_INPUTS) + return -EINVAL; + + input = &zldev->input[index]; + + /* If the input is differential then the configuration for N-pin + * reference is ignored and P-pin config is used for both. + */ + if (zl3073x_is_n_pin(index) && zl3073x_input_is_diff(zldev, index-1)) { + input->enabled = zl3073x_input_is_enabled(zldev, index-1); + input->diff = true; + + return 0; + } + + /* Read reference configuration into mailbox */ + rc = zl3073x_mb_ref_read(zldev, index); + if (rc) + return rc; + + /* Read reference config register */ + rc = zl3073x_read_ref_config(zldev, &ref_config); + if (rc) + return rc; + + /* Store info about input reference enablement and if it is + * configured in differential mode or not. + */ + input->enabled = FIELD_GET(REF_CONFIG_ENABLE, ref_config); + input->diff = FIELD_GET(REF_CONFIG_DIFF_EN, ref_config); + + return rc; +} + +/** + * zl3073x_output_state_fetch - get output state + * @zldev: pointer to zl3073x_dev structure + * @index: output index to fetch state for + * + * Function fetches information for the given output (not output pin) + * that are invariant and stores them for later use. + * + * Returns 0 in case of success or negative value in error case. + */ +static int +zl3073x_output_state_fetch(struct zl3073x_dev *zldev, u8 index) +{ + struct zl3073x_output *output; + u8 output_ctrl, output_mode; + int rc; + + if (index >= ZL3073X_NUM_OUTPUTS) + return -EINVAL; + + output = &zldev->output[index]; + + /* Read output control register */ + rc = zl3073x_read_output_ctrl(zldev, index, &output_ctrl); + if (rc) + return rc; + + /* Store info about output enablement and synthesizer the output + * is connected to. + */ + output->enabled = FIELD_GET(OUTPUT_CTRL_EN, output_ctrl); + output->synth = FIELD_GET(OUTPUT_CTRL_SYNTH_SEL, output_ctrl); + + /* Load given output config into mailbox */ + rc = zl3073x_mb_output_read(zldev, index); + if (rc) + return rc; + + /* Read output mode from mailbox */ + rc = zl3073x_read_output_mode(zldev, &output_mode); + if (rc) + return rc; + + /* Extract and store output signal format */ + output->signal_format = FIELD_GET(OUTPUT_MODE_SIGNAL_FORMAT, + output_mode); + + return rc; +} + +/** + * zl3073x_synth_state_fetch - get synth state + * @zldev: pointer to zl3073x_dev structure + * @index: synth index to fetch state for + * + * Function fetches information for the given synthesizer that are + * invariant and stores them for later use. + * + * Returns 0 in case of success or negative value in error case. + */ +static int +zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index) +{ + u16 base, numerator, denominator; + u8 synth_ctrl; + u32 mult; + int rc; + + /* Read synth control register */ + rc = zl3073x_read_synth_ctrl(zldev, index, &synth_ctrl); + if (rc) + return rc; + + /* Extract and store DPLL channel the synth is driven by */ + zldev->synth[index].dpll = FIELD_GET(SYNTH_CTRL_DPLL_SEL, synth_ctrl); + + dev_dbg(zldev->dev, "SYNTH%u is connected to DPLL%u\n", index, + zldev->synth[index].dpll); + + /* Read synth configuration into mailbox */ + rc = zl3073x_mb_synth_read(zldev, index); + if (rc) + return rc; + + /* The output frequency is determined by the following formula: + * base * multiplier * numerator / denominator + * + * Therefore get all this number and calculate the output frequency + */ + rc = zl3073x_read_synth_freq_base(zldev, &base); + if (rc) + return rc; + + rc = zl3073x_read_synth_freq_mult(zldev, &mult); + if (rc) + return rc; + + rc = zl3073x_read_synth_freq_m(zldev, &numerator); + if (rc) + return rc; + + rc = zl3073x_read_synth_freq_n(zldev, &denominator); + if (rc) + return rc; + + /* Check denominator for zero to avoid div by 0 */ + if (!denominator) { + dev_err(zldev->dev, + "Zero divisor for SYNTH%u retrieved from device\n", + index); + return -ENODEV; + } + + /* Compute and store synth frequency */ + zldev->synth[index].freq = mul_u64_u32_div(mul_u32_u32(base, mult), + numerator, denominator); + + dev_dbg(zldev->dev, "SYNTH%u frequency: %llu Hz\n", index, + zldev->synth[index].freq); + + return rc; +} + +static int +zl3073x_dev_state_fetch(struct zl3073x_dev *zldev) +{ + int rc; + u8 i; + + for (i = 0; i < ZL3073X_NUM_INPUTS; i++) { + rc = zl3073x_input_state_fetch(zldev, i); + if (rc) { + dev_err(zldev->dev, + "Failed to fetch input state: %pe\n", + ERR_PTR(rc)); + return rc; + } + } + + for (i = 0; i < ZL3073X_NUM_SYNTHS; i++) { + rc = zl3073x_synth_state_fetch(zldev, i); + if (rc) { + dev_err(zldev->dev, + "Failed to fetch synth state: %pe\n", + ERR_PTR(rc)); + return rc; + } + } + + for (i = 0; i < ZL3073X_NUM_OUTPUTS; i++) { + rc = zl3073x_output_state_fetch(zldev, i); + if (rc) { + dev_err(zldev->dev, + "Failed to fetch output state: %pe\n", + ERR_PTR(rc)); + return rc; + } + } + + return rc; +} + int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id) { u16 id, revision, fw_ver; @@ -556,6 +790,13 @@ int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id) /* Load mfg file if present */ zl3073x_fw_load(zldev); + /* Fetch device state */ + scoped_guard(zl3073x, zldev) { + rc = zl3073x_dev_state_fetch(zldev); + if (rc) + return rc; + } + dev_info(zldev->dev, "ChipID(%X), ChipRev(%X), FwVer(%u)\n", id, revision, fw_ver); dev_info(zldev->dev, "Custom config version: %lu.%lu.%lu.%lu\n", diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h index a18eddbc03709..825e6706dc974 100644 --- a/include/linux/mfd/zl3073x.h +++ b/include/linux/mfd/zl3073x.h @@ -6,11 +6,49 @@ #include #include +/* + * Hardware limits for ZL3073x chip family + */ +#define ZL3073X_NUM_INPUTS 10 +#define ZL3073X_NUM_OUTPUTS 10 +#define ZL3073X_NUM_SYNTHS 5 + +struct zl3073x_input { + bool enabled; + bool diff; +}; + +struct zl3073x_output { + bool enabled; + u8 synth; + u8 signal_format; +#define OUTPUT_MODE_SIGNAL_FORMAT_DISABLED 0 +#define OUTPUT_MODE_SIGNAL_FORMAT_LVDS 1 +#define OUTPUT_MODE_SIGNAL_FORMAT_DIFFERENTIAL 2 +#define OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM 3 +#define OUTPUT_MODE_SIGNAL_FORMAT_TWO 4 +#define OUTPUT_MODE_SIGNAL_FORMAT_ONE_P 5 +#define OUTPUT_MODE_SIGNAL_FORMAT_ONE_N 6 +#define OUTPUT_MODE_SIGNAL_FORMAT_TWO_INV 7 +#define OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV 12 +#define OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV 15 +}; + +struct zl3073x_synth { + u64 freq; + u8 dpll; +}; + struct zl3073x_dev { struct device *dev; struct regmap *regmap; u64 clock_id; struct mutex lock; + + /* Invariants */ + struct zl3073x_input input[ZL3073X_NUM_INPUTS]; + struct zl3073x_output output[ZL3073X_NUM_OUTPUTS]; + struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS]; }; /** @@ -185,4 +223,108 @@ int zl3073x_mb_ref_write(struct zl3073x_dev *zldev, u8 index); int zl3073x_mb_synth_read(struct zl3073x_dev *zldev, u8 index); int zl3073x_mb_synth_write(struct zl3073x_dev *zldev, u8 index); +static inline +bool zl3073x_is_n_pin(u8 index) +{ + /* P-pins indices are even while N-pins are odd */ + return index & 1; +} + +static inline +bool zl3073x_is_p_pin(u8 index) +{ + return !zl3073x_is_n_pin(index); +} + +/** + * zl3073x_input_is_diff - check if the given input ref is differential + * @zldev: device structure pointer + * @index: output index + * + * Returns true if the given input ref is differential + */ +static inline +bool zl3073x_input_is_diff(struct zl3073x_dev *zldev, u8 index) +{ + return zldev->input[index].diff; +} + +/** + * zl3073x_input_is_enabled - check if the given input ref is enabled + * @zldev: device structure pointer + * @index: output index + * + * Returns true if the given input ref is enabled + */ +static inline +bool zl3073x_input_is_enabled(struct zl3073x_dev *zldev, u8 index) +{ + return zldev->input[index].enabled; +} + +/** + * zl3073x_output_is_enabled - check if the given output is enabled + * @zldev: device structure pointer + * @index: output index + * + * Returns true if the given output is enabled + */ +static inline +u8 zl3073x_output_is_enabled(struct zl3073x_dev *zldev, u8 index) +{ + return zldev->output[index].enabled; +} + +/** + * zl3073x_output_signal_format_get - get output signal format + * @zldev: device structure pointer + * @index: output index + * + * Returns signal format of given output + */ +static inline +u8 zl3073x_output_signal_format_get(struct zl3073x_dev *zldev, u8 index) +{ + return zldev->output[index].signal_format; +} + +/** + * zl3073x_output_synth_get - get synth connected to given output + * @zldev: device structure pointer + * @index: output index + * + * Returns index of synth connected to given output. + */ +static inline +u8 zl3073x_output_synth_get(struct zl3073x_dev *zldev, u8 index) +{ + return zldev->output[index].synth; +} + +/** + * zl3073x_synth_dpll_get - get dpll id where the synth is connected to + * @zldev: device structure pointer + * @index: synth order number + * + * Returns frequency of given synthetizer + */ +static inline +u64 zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index) +{ + return zldev->synth[index].dpll; +} + +/** + * zl3073x_synth_freq_get - get synth current freq + * @zldev: device structure pointer + * @index: synth order number + * + * Returns frequency of given synthetizer + */ +static inline +u64 zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index) +{ + return zldev->synth[index].freq; +} + #endif /* __LINUX_MFD_ZL3073X_H */ From patchwork Mon Apr 7 17:31:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041419 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E51C421B91D for ; Mon, 7 Apr 2025 17:32:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047143; cv=none; b=ge+jOfSfu+/QyrgXfigr46/msJBSesuVlDHXnf9nQheiw5n80eygTw5sKchcIQ25M8PFXlJsmfalsVMNaI2VBljDI1CK2lUMRvsJck8SpMCQR7RKY/H0UhYHRNLEFTj6rM/41t6Gs9YPI1xciwAb5rru/4Zjg6HgrdcEH/pHx6Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047143; c=relaxed/simple; bh=m1sZ7qgxi4chv4YPU8hkyxOFz39bNoRwJzSDtVjQKp0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QXISYTLdRwqgj+PP2ZPj8T9rDr4G/ihRL9Lw6A+HEFwsHakRAHBJrS3cACZRQzTN4QAXrITyLDAGYuJX9UTxfIehoCCxDTlkH386L5Kina+d0iCtAONBtMZzYHRPIUSfXhenBFYmZljkWL09GbSZmyWo7KnbSvGd0TwUYtRGlPs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=UtCqcInx; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="UtCqcInx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047139; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7YGpxqzLBpyHnt/c4pOb671V2iscfF8fW2Izjlbw7rc=; b=UtCqcInxw7wV3rn27zc01+EK9eMEA6Mpc0fvCXY/55YimVFiHmGOnPZ9MeCXGszBU5KIZO bkWBzr/NvC3jbxuI67pRR9NQZwCbOqIqcKXuP6tsCT0X+EyDYt/cx+ZYNWhfdxDeZWvhKR uhE5HLFTdsq0JRcFcpt+1CCWCevPOW0= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-596-9VQx0OHWNZ2kSHIQRtitwg-1; Mon, 07 Apr 2025 13:32:17 -0400 X-MC-Unique: 9VQx0OHWNZ2kSHIQRtitwg-1 X-Mimecast-MFC-AGG-ID: 9VQx0OHWNZ2kSHIQRtitwg_1744047135 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C254A18001E1; Mon, 7 Apr 2025 17:32:15 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3F0C71955BC0; Mon, 7 Apr 2025 17:32:09 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 13/28] dpll: Add Microchip ZL3073x DPLL driver Date: Mon, 7 Apr 2025 19:31:43 +0200 Message-ID: <20250407173149.1010216-4-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 Add a DPLL driver for Microchip Azurite chip family with basic functionality where only required DPLL and pin callbacks are implemented. Other features are added by subsequent patches. The driver controls the sub-devices created by zl3073x MFD driver and each DPLL sub-device represents one of the DPLL channels that are provided by the device. For each sub-device the driver registers a DPLL device and also input and output pins. Number of registered pins depend on their configuration that is stored in flash memory inside the device. The input pins can be configured as differential or single-ended ones. If the input/output is configured as differential then P&N pins form one input/output and only 1 input/output pin is registered. For single-ended case the number of registered pins is up to 2 depending on whether the pin (P or N) is enabled or disabled in configuration. Each DPLL channel (sub-device) can drive up to 5 synthesizers whose output is connected to up to 10 output pin pairs (P & N). Because output pin pairs shares synthesizers where each is driven by different DPLL channel, the driver does not support to change state of output pins. So the output pins are registered only for DPLL device they are connected to (based on stored configuration) and are always reported as connected. This does not apply to the case of input pins where any of them can be a reference for any DPLL channel. The driver also creates a kworker task to monitor DPLL channel and input pins changes and to notify about them DPLL core. Output pins are not monitored as their parameters are not changed asynchronously by the device. Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- MAINTAINERS | 1 + drivers/dpll/Kconfig | 16 + drivers/dpll/Makefile | 2 + drivers/dpll/dpll_zl3073x.c | 1073 +++++++++++++++++++++++++++++++++++ include/linux/mfd/zl3073x.h | 5 + 5 files changed, 1097 insertions(+) create mode 100644 drivers/dpll/dpll_zl3073x.c diff --git a/MAINTAINERS b/MAINTAINERS index c69a69d862310..3d542440d0b2b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15999,6 +15999,7 @@ M: Ivan Vecera M: Prathosh Satish L: netdev@vger.kernel.org S: Supported +F: drivers/dpll/dpll_zl3073x* F: drivers/mfd/zl3073x* F: include/linux/mfd/zl3073x.h diff --git a/drivers/dpll/Kconfig b/drivers/dpll/Kconfig index 20607ed542435..efd867f338dfc 100644 --- a/drivers/dpll/Kconfig +++ b/drivers/dpll/Kconfig @@ -3,5 +3,21 @@ # Generic DPLL drivers configuration # +menu "DPLL support" + config DPLL bool + +config DPLL_ZL3073X + tristate "Microchip Azurite DPLL driver" + depends on MFD_ZL3073X_CORE + select DPLL + help + This driver adds support for DPLL exposed by Microchip Azurite + chip family. + + The devices handled by this driver are created by MFD zl3073x + driver as sub-devices for each DPLL channel that is present + in the device. + +endmenu diff --git a/drivers/dpll/Makefile b/drivers/dpll/Makefile index 2e5b278501105..9f7c99261e74d 100644 --- a/drivers/dpll/Makefile +++ b/drivers/dpll/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_DPLL) += dpll.o dpll-y += dpll_core.o dpll-y += dpll_netlink.o dpll-y += dpll_nl.o + +obj-$(CONFIG_DPLL_ZL3073X) += dpll_zl3073x.o diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c new file mode 100644 index 0000000000000..34bd6964fe001 --- /dev/null +++ b/drivers/dpll/dpll_zl3073x.c @@ -0,0 +1,1073 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include + +/* + * Register Map Page 2, Status + */ +ZL3073X_REG8_IDX_DEF(ref_mon_status, 0x102, + ZL3073X_NUM_INPUT_PINS, 1); +#define REF_MON_STATUS_LOS_FAIL BIT(0) +#define REF_MON_STATUS_SCM_FAIL BIT(1) +#define REF_MON_STATUS_CFM_FAIL BIT(2) +#define REF_MON_STATUS_GST_FAIL BIT(3) +#define REF_MON_STATUS_PFM_FAIL BIT(4) +#define REF_MON_STATUS_ESYNC_FAIL BIT(6) +#define REF_MON_STATUS_SPLIT_XO_FAIL BIT(7) +#define REF_MON_STATUS_OK 0 /* all bits zeroed */ + +ZL3073X_REG8_IDX_DEF(dpll_mon_status, 0x110, ZL3073X_NUM_CHANNELS, 1); +#define DPLL_MON_STATUS_LOCK BIT(0) +#define DPLL_MON_STATUS_HO BIT(1) +#define DPLL_MON_STATUS_HO_READY BIT(2) + +ZL3073X_REG8_IDX_DEF(dpll_refsel_status, 0x130, ZL3073X_NUM_CHANNELS, 1); +#define DPLL_REFSEL_STATUS_REFSEL GENMASK(3, 0) +#define DPLL_REFSEL_STATUS_STATE GENMASK(6, 4) +#define DPLL_REFSEL_STATUS_STATE_FREERUN 0 +#define DPLL_REFSEL_STATUS_STATE_HOLDOVER 1 +#define DPLL_REFSEL_STATUS_STATE_FASTLOCK 2 +#define DPLL_REFSEL_STATUS_STATE_ACQUIRING 3 +#define DPLL_REFSEL_STATUS_STATE_LOCK 4 + +/* + * Register Map Page 5, DPLL + */ +ZL3073X_REG8_IDX_DEF(dpll_mode_refsel, 0x284, ZL3073X_NUM_CHANNELS, 4); +#define DPLL_MODE_REFSEL_MODE GENMASK(2, 0) +#define DPLL_MODE_REFSEL_MODE_FREERUN 0 +#define DPLL_MODE_REFSEL_MODE_HOLDOVER 1 +#define DPLL_MODE_REFSEL_MODE_REFLOCK 2 +#define DPLL_MODE_REFSEL_MODE_AUTO 3 +#define DPLL_MODE_REFSEL_MODE_NCO 4 +#define DPLL_MODE_REFSEL_REF GENMASK(7, 4) + +/* + * Register Map Page 9, Synth and Output + */ +ZL3073X_REG8_DEF(synth_phase_shift_ctrl, 0x49e); +ZL3073X_REG8_DEF(synth_phase_shift_mask, 0x49f); +ZL3073X_REG8_DEF(synth_phase_shift_intvl, 0x4a0); +ZL3073X_REG16_DEF(synth_phase_shift_data, 0x4a1); + +/* + * Register Map Page 12, DPLL Mailbox + */ +ZL3073X_REG8_IDX_DEF(dpll_ref_prio, 0x652, + ZL3073X_NUM_INPUT_PINS / 2, 1); +#define DPLL_REF_PRIO_REF_P GENMASK(3, 0) +#define DPLL_REF_PRIO_REF_N GENMASK(7, 4) +#define DPLL_REF_PRIO_MAX 14 +#define DPLL_REF_PRIO_NONE 15 /* non-selectable */ + +#define ZL3073X_REF_NONE ZL3073X_NUM_INPUT_PINS +#define ZL3073X_REF_IS_VALID(_ref) ((_ref) != ZL3073X_REF_NONE) + +/** + * struct zl3073x_dpll_pin_info - DPLL pin info + * @props: DPLL core pin properties + * @package_label: pin package label + */ +struct zl3073x_dpll_pin_info { + struct dpll_pin_properties props; + char package_label[8]; +}; + +/** + * struct zl3073x_dpll_pin - DPLL pin + * @dpll_pin: pointer to registered dpll_pin + * @index: index in zl3073x_dpll.pins array + * @prio: pin priority <0, 14> + * @selectable: pin is selectable in automatic mode + * @pin_state: last saved pin state + */ +struct zl3073x_dpll_pin { + struct dpll_pin *dpll_pin; + u8 index; + u8 prio; + bool selectable; + enum dpll_pin_state pin_state; +}; + +/** + * struct zl3073x_dpll - ZL3073x DPLL sub-device structure + * @dev: device pointer + * @mfd: pointer to multi-function parent device + * @id: DPLL index + * @refsel_mode: reference selection mode + * @forced_ref: selected reference in forced reference lock mode + * @dpll_dev: pointer to registered DPLL device + * @lock_status: last saved DPLL lock status + * @pins: array of pins + * @kworker: thread for periodic work + * @work: periodic work + */ +struct zl3073x_dpll { + struct device *dev; + struct zl3073x_dev *mfd; + int id; + u8 refsel_mode; + u8 forced_ref; + struct dpll_device *dpll_dev; + enum dpll_lock_status lock_status; + struct zl3073x_dpll_pin pins[ZL3073X_NUM_PINS]; + + struct kthread_worker *kworker; + struct kthread_delayed_work work; +}; + +#define pin_to_dpll(_pin) \ + container_of((_pin), struct zl3073x_dpll, pins[(_pin)->index]) + +#define pin_to_dev(_pin) \ + pin_to_dpll(_pin)->mfd + +/** + * zl3073x_dpll_is_input_pin - check if the pin is input one + * @pin: pin to check + * + * Returns true if the pin is input or false if output one. + */ +static bool +zl3073x_dpll_is_input_pin(struct zl3073x_dpll_pin *pin) +{ + /* Output pins are stored in zl3073x_dpll.pins first and input + * pins follow. + */ + if (pin->index >= ZL3073X_NUM_OUTPUT_PINS) + return true; + + return false; +} + +/** + * zl3073x_dpll_pin_index_get - get pin HW index + * @pin: pin pointer + * + * Returns index of the pin from the HW point of view. + */ +static u8 +zl3073x_dpll_pin_index_get(struct zl3073x_dpll_pin *pin) +{ + if (zl3073x_dpll_is_input_pin(pin)) + return pin->index - ZL3073X_NUM_OUTPUT_PINS; + + return pin->index; +} + +/** + * zl3073x_dpll_is_n_pin - check if the pin is N-pin + * @pin: pin to check + * + * Returns true if the pin is N-pin or false if output one. + */ +static bool +zl3073x_dpll_is_n_pin(struct zl3073x_dpll_pin *pin) +{ + /* P-pins indices are even while N-pins are odd */ + return zl3073x_is_n_pin(zl3073x_dpll_pin_index_get(pin)); +} + +/** + * zl3073x_dpll_is_p_pin - check if the pin is P-pin + * @pin: pin to check + * + * Returns true if the pin is P-pin or false if output one. + */ +static bool +zl3073x_dpll_is_p_pin(struct zl3073x_dpll_pin *pin) +{ + return zl3073x_is_p_pin(zl3073x_dpll_pin_index_get(pin)); +} + +/** + * zl3073x_dpll_output_pin_output_get - get output index for given output pin + * @pin: pointer to pin + * + * Returns output index for the given output pin + */ +static u8 +zl3073x_dpll_output_pin_output_get(struct zl3073x_dpll_pin *pin) +{ + WARN_ON(zl3073x_dpll_is_input_pin(pin)); + + return zl3073x_dpll_pin_index_get(pin) / 2; +} + +static int +zl3073x_dpll_pin_direction_get(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll_pin *pin = pin_priv; + + if (zl3073x_dpll_is_input_pin(pin)) + *direction = DPLL_PIN_DIRECTION_INPUT; + else + *direction = DPLL_PIN_DIRECTION_OUTPUT; + + return 0; +} + +/** + * zl3073x_dpll_selected_ref_get - get currently selected reference + * @zldpll: pointer to zl3073x_dpll + * @ref: place to store selected reference + * + * Check for currently selected reference the DPLL should be locked to + * and stores its index to given @ref. + * + * Return 0 in case of success or negative value otherwise. + */ +static int +zl3073x_dpll_selected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) +{ + struct zl3073x_dev *zldev = zldpll->mfd; + u8 state, value; + int rc; + + switch (zldpll->refsel_mode) { + case DPLL_MODE_REFSEL_MODE_AUTO: + /* For automatic mode read refsel_status register */ + rc = zl3073x_read_dpll_refsel_status(zldev, zldpll->id, &value); + if (rc) + return rc; + + /* Extract reference state */ + state = FIELD_GET(DPLL_REFSEL_STATUS_STATE, value); + + /* Return the reference only if the DPLL is locked to it */ + if (state == DPLL_REFSEL_STATUS_STATE_LOCK) + *ref = FIELD_GET(DPLL_REFSEL_STATUS_REFSEL, value); + else + *ref = ZL3073X_REF_NONE; + break; + case DPLL_MODE_REFSEL_MODE_REFLOCK: + /* For manual mode return stored value */ + *ref = zldpll->forced_ref; + break; + default: + /* For other modes like NCO, freerun... there is no input ref */ + *ref = ZL3073X_REF_NONE; + break; + } + + return 0; +} + +/** + * zl3073x_dpll_connected_ref_get - get currently connected reference + * @zldpll: pointer to zl3073x_dpll + * @ref: place to store selected reference + * + * Looks for currently connected the DPLL is locked to and stores its index + * to given @ref. + * + * Return 0 in case of success or negative value otherwise. + */ +static int +zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) +{ + struct zl3073x_dev *zldev = zldpll->mfd; + int rc; + + /* Get currently selected input reference */ + rc = zl3073x_dpll_selected_ref_get(zldpll, ref); + if (rc) + return rc; + + if (ZL3073X_REF_IS_VALID(*ref)) { + u8 ref_status; + + /* Read the reference monitor status */ + rc = zl3073x_read_ref_mon_status(zldev, *ref, &ref_status); + if (rc) + return rc; + + /* If the monitor indicates an error nothing is connected */ + if (ref_status != REF_MON_STATUS_OK) + *ref = ZL3073X_REF_NONE; + } + + return 0; +} + +/** + * zl3073x_dpll_ref_prio_get - get priority for given input pin + * @pin: pointer to pin + * @prio: place to store priority + * + * Reads current priority for the given input pin and stores the value + * to @prio. + * + * Returns 0 in case of success or negative value otherwise. + */ +static int +zl3073x_dpll_ref_prio_get(struct zl3073x_dpll_pin *pin, u8 *prio) +{ + struct zl3073x_dpll *zldpll = pin_to_dpll(pin); + struct zl3073x_dev *zldev = zldpll->mfd; + u8 ref_id, ref_prio; + int rc; + + /* Read DPLL configuration into mailbox */ + rc = zl3073x_mb_dpll_read(zldev, zldpll->id); + if (rc) + return rc; + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Read ref prio nibble */ + rc = zl3073x_read_dpll_ref_prio(zldev, ref_id / 2, &ref_prio); + if (rc) + return rc; + + /* Select nibble according pin type */ + if (zl3073x_dpll_is_p_pin(pin)) + *prio = FIELD_GET(DPLL_REF_PRIO_REF_P, ref_prio); + else + *prio = FIELD_GET(DPLL_REF_PRIO_REF_N, ref_prio); + + return rc; +} + +static int +zl3073x_dpll_input_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dpll_pin *pin = pin_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + u8 ref_id, ref_conn, ref_status; + int rc; + + guard(zl3073x)(zldev); + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Get currently connected reference */ + rc = zl3073x_dpll_connected_ref_get(zldpll, &ref_conn); + if (rc) + return rc; + + if (ref_id == ref_conn) { + *state = DPLL_PIN_STATE_CONNECTED; + return 0; + } + + /* If the DPLL is running in automatic mode and the reference is + * selectable and its monitor does not report any error then report + * pin as selectable. + */ + if (zldpll->refsel_mode == DPLL_MODE_REFSEL_MODE_AUTO && + pin->selectable) { + /* Read reference monitor status */ + rc = zl3073x_read_ref_mon_status(zldev, ref_id, &ref_status); + if (rc) + return rc; + + /* If the monitor indicates errors report the reference + * as disconnected + */ + if (ref_status == REF_MON_STATUS_OK) { + *state = DPLL_PIN_STATE_SELECTABLE; + return 0; + } + } + + /* Otherwise report the pin as disconnected */ + *state = DPLL_PIN_STATE_DISCONNECTED; + + return 0; +} + +static int +zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + /* If the output pin is registered then it is always connected */ + *state = DPLL_PIN_STATE_CONNECTED; + + return 0; +} + +static int +zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + u8 mon_status; + int rc; + + guard(zl3073x)(zldev); + + rc = zl3073x_read_dpll_mon_status(zldev, zldpll->id, &mon_status); + + if (rc) + return rc; + + if (FIELD_GET(DPLL_MON_STATUS_LOCK, mon_status)) { + if (FIELD_GET(DPLL_MON_STATUS_HO_READY, mon_status)) + *status = DPLL_LOCK_STATUS_LOCKED_HO_ACQ; + else + *status = DPLL_LOCK_STATUS_LOCKED; + } else if (FIELD_GET(DPLL_MON_STATUS_HO, mon_status)) { + *status = DPLL_LOCK_STATUS_HOLDOVER; + } else { + *status = DPLL_LOCK_STATUS_UNLOCKED; + } + + return rc; +} + +static int +zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_mode *mode, struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + + switch (zldpll->refsel_mode) { + case DPLL_MODE_REFSEL_MODE_FREERUN: + case DPLL_MODE_REFSEL_MODE_HOLDOVER: + case DPLL_MODE_REFSEL_MODE_NCO: + case DPLL_MODE_REFSEL_MODE_REFLOCK: + /* Use MANUAL for device FREERUN, HOLDOVER, NCO and + * REFLOCK modes + */ + *mode = DPLL_MODE_MANUAL; + break; + case DPLL_MODE_REFSEL_MODE_AUTO: + /* Use AUTO for device AUTO mode */ + *mode = DPLL_MODE_AUTOMATIC; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { + .direction_get = zl3073x_dpll_pin_direction_get, + .state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get, +}; + +static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = { + .direction_get = zl3073x_dpll_pin_direction_get, + .state_on_dpll_get = zl3073x_dpll_output_pin_state_on_dpll_get, +}; + +static const struct dpll_device_ops zl3073x_dpll_device_ops = { + .lock_status_get = zl3073x_dpll_lock_status_get, + .mode_get = zl3073x_dpll_mode_get, +}; + +/** + * zl3073x_dpll_pin_info_package_label_set - generate package label for the pin + * @pin: pointer to pin + * @pin_info: pointer to pin info structure + * + * Generates package label string and stores it into pin info structure. + * + * Possible formats: + * REF - differential input reference + * REFP & REFN - single-ended input reference (P or N pin) + * OUT - differential output + * OUTP & OUTN - single-ended output (P or N pin) + */ +static void +zl3073x_dpll_pin_info_package_label_set(struct zl3073x_dpll_pin *pin, + struct zl3073x_dpll_pin_info *pin_info) +{ + struct zl3073x_dev *zldev = pin_to_dpll(pin)->mfd; + char suffix; + u8 idx; + + suffix = zl3073x_dpll_is_p_pin(pin) ? 'P' : 'N'; + + if (zl3073x_dpll_is_input_pin(pin)) { + idx = zl3073x_dpll_pin_index_get(pin); + + if (zl3073x_input_is_diff(zldev, idx)) + /* For differential use REF */ + snprintf(pin_info->package_label, + sizeof(pin_info->package_label), + "REF%u", idx / 2); + else + /* For single-ended use REFP/N */ + snprintf(pin_info->package_label, + sizeof(pin_info->package_label), + "REF%u%c", idx / 2, suffix); + } else { + idx = zl3073x_dpll_output_pin_output_get(pin); + + switch (zl3073x_output_signal_format_get(zldev, idx)) { + case OUTPUT_MODE_SIGNAL_FORMAT_LVDS: + case OUTPUT_MODE_SIGNAL_FORMAT_DIFFERENTIAL: + case OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM: + /* For differential use OUT */ + snprintf(pin_info->package_label, + sizeof(pin_info->package_label), "OUT%u", idx); + break; + default: + /* For single-ended use OUTP/N */ + snprintf(pin_info->package_label, + sizeof(pin_info->package_label), "OUT%u%c", + idx, suffix); + break; + } + } + + /* Set package_label pointer in DPLL core properties to generated + * string. + */ + pin_info->props.package_label = pin_info->package_label; +} + +/** + * zl3073x_dpll_pin_info_get - get pin info + * @pin: pin whose info is returned + * + * The function allocates pin info structure, generates package label + * string according pin type and its order number. + * + * Returns pointer to allocated pin info structure that has to be freed + * by @zl3073x_dpll_pin_info_put by the caller and in case of error + * then error pointer is returned. + */ +static struct zl3073x_dpll_pin_info * +zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) +{ + struct zl3073x_dpll_pin_info *pin_info; + + /* Allocate pin info structure */ + pin_info = kzalloc(sizeof(*pin_info), GFP_KERNEL); + if (!pin_info) + return ERR_PTR(-ENOMEM); + + /* Set pin type */ + if (zl3073x_dpll_is_input_pin(pin)) + pin_info->props.type = DPLL_PIN_TYPE_EXT; + else + pin_info->props.type = DPLL_PIN_TYPE_GNSS; + + pin_info->props.phase_range.min = S32_MIN; + pin_info->props.phase_range.max = S32_MAX; + + /* Generate package label for the given pin */ + zl3073x_dpll_pin_info_package_label_set(pin, pin_info); + + return pin_info; +} + +/** + * zl3073x_dpll_pin_info_put - free pin info + * @pin_info: pin info to free + * + * The function deallocates given pin info structure. + */ +static void +zl3073x_dpll_pin_info_put(struct zl3073x_dpll_pin_info *pin_info) +{ + /* Free the pin info structure itself */ + kfree(pin_info); +} + +static int +zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin) +{ + struct zl3073x_dpll *zldpll = pin_to_dpll(pin); + struct zl3073x_dpll_pin_info *pin_info; + const struct dpll_pin_ops *ops; + int rc; + + /* Get pin info */ + pin_info = zl3073x_dpll_pin_info_get(pin); + if (IS_ERR(pin_info)) + return PTR_ERR(pin_info); + + /* Create or get existing DPLL pin */ + pin->dpll_pin = dpll_pin_get(zldpll->mfd->clock_id, pin->index, + THIS_MODULE, &pin_info->props); + if (IS_ERR(pin->dpll_pin)) { + rc = PTR_ERR(pin->dpll_pin); + goto err_pin_get; + } + + if (zl3073x_dpll_is_input_pin(pin)) + ops = &zl3073x_dpll_input_pin_ops; + else + ops = &zl3073x_dpll_output_pin_ops; + + /* Register the pin */ + rc = dpll_pin_register(zldpll->dpll_dev, pin->dpll_pin, ops, pin); + if (rc) + goto err_register; + + /* Free pin info */ + zl3073x_dpll_pin_info_put(pin_info); + + return 0; + +err_register: + dpll_pin_put(pin->dpll_pin); + pin->dpll_pin = NULL; +err_pin_get: + zl3073x_dpll_pin_info_put(pin_info); + + return rc; +} + +static void +zl3073x_dpll_pin_unregister(struct zl3073x_dpll_pin *pin) +{ + struct zl3073x_dpll *zldpll = pin_to_dpll(pin); + const struct dpll_pin_ops *ops; + + if (IS_ERR_OR_NULL(pin->dpll_pin)) + return; + + if (zl3073x_dpll_is_input_pin(pin)) + ops = &zl3073x_dpll_input_pin_ops; + else + ops = &zl3073x_dpll_output_pin_ops; + + /* Unregister the pin */ + dpll_pin_unregister(zldpll->dpll_dev, pin->dpll_pin, ops, pin); + + dpll_pin_put(pin->dpll_pin); + pin->dpll_pin = NULL; +} + +static int +zl3073x_dpll_register_input_pin(struct zl3073x_dpll_pin *pin) +{ + struct zl3073x_dpll *zldpll = pin_to_dpll(pin); + struct zl3073x_dev *zldev = zldpll->mfd; + u8 ref; + + /* Get index of the pin */ + ref = zl3073x_dpll_pin_index_get(pin); + + /* If the ref is differential then register only for the P-pin */ + if (zl3073x_input_is_diff(zldev, ref) && zl3073x_dpll_is_n_pin(pin)) { + dev_dbg(zldev->dev, "INPUT%u is differential, skipping N-pin\n", + ref); + return 0; + } + + /* If the ref is disabled then skip registration */ + if (!zl3073x_input_is_enabled(zldev, ref)) { + dev_dbg(zldev->dev, "INPUT%u is disabled\n", ref); + return 0; + } + + scoped_guard(zl3073x, zldev) { + int rc; + + rc = zl3073x_dpll_ref_prio_get(pin, &pin->prio); + if (rc) + return rc; + } + + if (pin->prio == DPLL_REF_PRIO_NONE) { + /* Clamp priority to max value and make pin non-selectable */ + pin->prio = DPLL_REF_PRIO_MAX; + pin->selectable = false; + } else { + /* Mark pin as selectable */ + pin->selectable = true; + } + + /* Register the pin */ + return zl3073x_dpll_pin_register(pin); +} + +static int +zl3073x_dpll_register_output_pin(struct zl3073x_dpll_pin *pin) +{ + struct zl3073x_dpll *zldpll = pin_to_dpll(pin); + struct zl3073x_dev *zldev = zldpll->mfd; + u8 dpll, output, synth; + + /* Get output id for the pin and synth where it is connected to */ + output = zl3073x_dpll_output_pin_output_get(pin); + synth = zl3073x_output_synth_get(zldev, output); + + /* Get DPLL channel the synth is associated with */ + dpll = zl3073x_synth_dpll_get(zldev, synth); + + /* If the output's synth is connected to different DPLL channel + * then skip registration. + */ + if (dpll != zldpll->id) { + dev_dbg(zldev->dev, "OUTPUT%u is driven by different DPLL\n", + output); + return 0; + } + + /* If the output is disabled then skip registration */ + if (!zl3073x_output_is_enabled(zldev, output)) { + dev_dbg(zldev->dev, "OUTPUT%u is disabled\n", output); + return 0; + } + + /* Check ouput's signal format */ + switch (zldev->output[output].signal_format) { + case OUTPUT_MODE_SIGNAL_FORMAT_DISABLED: + /* Output is disabled, nothing to register */ + dev_dbg(zldev->dev, "OUTPUT%u is disabled by signal format\n", + output); + return 0; + + case OUTPUT_MODE_SIGNAL_FORMAT_LVDS: + case OUTPUT_MODE_SIGNAL_FORMAT_DIFFERENTIAL: + case OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM: + /* Output is differential, skip registration for N-pin */ + if (zl3073x_dpll_is_n_pin(pin)) { + dev_dbg(zldev->dev, + "OUTPUT%u is differential, skipping N-pin\n", + output); + return 0; + } + break; + + case OUTPUT_MODE_SIGNAL_FORMAT_TWO: + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_INV: + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV: + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV: + /* Output is two single ended outputs, continue with + * registration. + */ + break; + + case OUTPUT_MODE_SIGNAL_FORMAT_ONE_P: + /* Output is one single ended P-pin output */ + if (zl3073x_dpll_is_n_pin(pin)) { + dev_dbg(zldev->dev, + "OUTPUT%u is P-pin only, skipping N-pin\n", + output); + return 0; + } + break; + case OUTPUT_MODE_SIGNAL_FORMAT_ONE_N: + /* Output is one single ended N-pin output */ + if (zl3073x_dpll_is_p_pin(pin)) { + dev_dbg(zldev->dev, + "OUTPUT%u is N-pin only, skipping P-pin\n", + output); + return 0; + } + break; + default: + dev_warn(zldev->dev, "Unknown output mode signal format: %u\n", + zldev->output[output].signal_format); + return 0; + } + + /* Register the pin */ + return zl3073x_dpll_pin_register(pin); +} + +static int +zl3073x_dpll_register_pins(struct zl3073x_dpll *zldpll) +{ + int i, rc; + + for (i = 0; i < ZL3073X_NUM_PINS; i++) { + struct zl3073x_dpll_pin *pin = &zldpll->pins[i]; + + pin->index = i; + + if (zl3073x_dpll_is_input_pin(pin)) + rc = zl3073x_dpll_register_input_pin(pin); + else + rc = zl3073x_dpll_register_output_pin(pin); + + if (rc) + goto err_register; + } + + return 0; + +err_register: + while (i--) + zl3073x_dpll_pin_unregister(&zldpll->pins[i]); + + return rc; +} + +static void +zl3073x_dpll_unregister_pins(struct zl3073x_dpll *zldpll) +{ + int i; + + for (i = 0; i < ZL3073X_NUM_PINS; i++) + zl3073x_dpll_pin_unregister(&zldpll->pins[i]); +} + +static int +zl3073x_dpll_register(struct zl3073x_dpll *zldpll) +{ + struct zl3073x_dev *zldev = zldpll->mfd; + int rc; + + scoped_guard(zl3073x, zldev) { + u8 dpll_mode_refsel; + + /* Read DPLL mode and forcibly selected reference */ + rc = zl3073x_read_dpll_mode_refsel(zldev, zldpll->id, + &dpll_mode_refsel); + if (rc) + return rc; + + /* Extract mode and selected input reference */ + zldpll->refsel_mode = FIELD_GET(DPLL_MODE_REFSEL_MODE, + dpll_mode_refsel); + zldpll->forced_ref = FIELD_GET(DPLL_MODE_REFSEL_REF, + dpll_mode_refsel); + } + + zldpll->dpll_dev = dpll_device_get(zldev->clock_id, zldpll->id, + THIS_MODULE); + if (IS_ERR(zldpll->dpll_dev)) + return PTR_ERR(zldpll->dpll_dev); + + rc = dpll_device_register(zldpll->dpll_dev, DPLL_TYPE_PPS, + &zl3073x_dpll_device_ops, zldpll); + if (rc) { + dpll_device_put(zldpll->dpll_dev); + zldpll->dpll_dev = NULL; + } + + return rc; +} + +static void +zl3073x_dpll_unregister(struct zl3073x_dpll *zldpll) +{ + if (IS_ERR_OR_NULL(zldpll->dpll_dev)) + return; + + dpll_device_unregister(zldpll->dpll_dev, &zl3073x_dpll_device_ops, + zldpll); + dpll_device_put(zldpll->dpll_dev); + zldpll->dpll_dev = NULL; +} + +static int +zl3073x_dpll_init(struct zl3073x_dpll *zldpll) +{ + int rc; + + rc = zl3073x_dpll_register(zldpll); + if (rc) + return rc; + + rc = zl3073x_dpll_register_pins(zldpll); + if (rc) + zl3073x_dpll_unregister(zldpll); + + return rc; +} + +static void +zl3073x_dpll_periodic_work(struct kthread_work *work) +{ + struct zl3073x_dpll *zldpll = container_of(work, struct zl3073x_dpll, + work.work); + struct zl3073x_dev *zldev = zldpll->mfd; + enum dpll_lock_status lock_status; + int i, rc; + + /* Get current lock status for the DPLL */ + rc = zl3073x_dpll_lock_status_get(zldpll->dpll_dev, zldpll, + &lock_status, NULL, NULL); + if (rc) { + dev_err(zldpll->mfd->dev, + "Failed to get DPLL lock status: %pe", ERR_PTR(rc)); + goto out; + } + + /* If lock status was changed then notify DPLL core */ + if (zldpll->lock_status != lock_status) { + zldpll->lock_status = lock_status; + dpll_device_change_ntf(zldpll->dpll_dev); + } + + /* Output pins change checks are not necessary because output states + * are constant. + */ + for (i = 0; i < ZL3073X_NUM_INPUT_PINS; i++) { + struct zl3073x_dpll_pin *pin; + enum dpll_pin_state state; + + /* Input pins starts are stored after output pins */ + pin = &zldpll->pins[ZL3073X_NUM_OUTPUT_PINS + i]; + + /* Skip non-registered pins */ + if (!pin->dpll_pin) + continue; + + rc = zl3073x_dpll_input_pin_state_on_dpll_get(pin->dpll_pin, + pin, + zldpll->dpll_dev, + zldpll, &state, + NULL); + if (rc) + goto out; + + if (state != pin->pin_state) { + dev_dbg(zldev->dev, + "INPUT%u state changed to %u\n", + zl3073x_dpll_pin_index_get(pin), state); + pin->pin_state = state; + dpll_pin_change_ntf(pin->dpll_pin); + } + } + +out: + /* Run twice a second */ + kthread_queue_delayed_work(zldpll->kworker, &zldpll->work, + msecs_to_jiffies(500)); +} + +static int +zl3073x_dpll_init_worker(struct zl3073x_dpll *zldpll) +{ + struct kthread_worker *kworker; + + kthread_init_delayed_work(&zldpll->work, zl3073x_dpll_periodic_work); + kworker = kthread_run_worker(0, "zl3073x-%s", dev_name(zldpll->dev)); + if (IS_ERR(kworker)) + return PTR_ERR(kworker); + + zldpll->kworker = kworker; + kthread_queue_delayed_work(zldpll->kworker, &zldpll->work, 0); + + return 0; +} + +static int +zl3073x_dpll_init_fine_phase_adjust(struct zl3073x_dpll *zldpll) +{ + struct zl3073x_dev *zldev = zldpll->mfd; + int rc; + + guard(zl3073x)(zldpll->mfd); + + rc = zl3073x_write_synth_phase_shift_mask(zldev, 0x1f); + if (rc) + return rc; + + rc = zl3073x_write_synth_phase_shift_intvl(zldev, 0x01); + if (rc) + return rc; + + rc = zl3073x_write_synth_phase_shift_data(zldev, 0xffff); + if (rc) + return rc; + + rc = zl3073x_write_synth_phase_shift_ctrl(zldev, 0x01); + if (rc) + return rc; + + return rc; +} + +static int +zl3073x_dpll_probe(struct platform_device *pdev) +{ + struct zl3073x_dpll *zldpll; + int rc; + + zldpll = devm_kzalloc(&pdev->dev, sizeof(*zldpll), GFP_KERNEL); + if (!zldpll) + return -ENOMEM; + + zldpll->dev = &pdev->dev; + zldpll->mfd = dev_get_drvdata(pdev->dev.parent); + zldpll->id = pdev->mfd_cell->id; + + rc = zl3073x_dpll_init(zldpll); + if (rc) + return rc; + + rc = zl3073x_dpll_init_worker(zldpll); + if (rc) + goto err_init_worker; + + platform_set_drvdata(pdev, zldpll); + + /* Initial firmware fine phase correction */ + rc = zl3073x_dpll_init_fine_phase_adjust(zldpll); + if (rc) + goto err_init_phase_adjust; + + return rc; + +err_init_phase_adjust: + kthread_cancel_delayed_work_sync(&zldpll->work); + kthread_destroy_worker(zldpll->kworker); +err_init_worker: + zl3073x_dpll_unregister_pins(zldpll); + zl3073x_dpll_unregister(zldpll); + + return rc; +} + +static void +zl3073x_dpll_remove(struct platform_device *pdev) +{ + struct zl3073x_dpll *zldpll = platform_get_drvdata(pdev); + + /* Stop worker */ + kthread_cancel_delayed_work_sync(&zldpll->work); + kthread_destroy_worker(zldpll->kworker); + + /* Unregister all pins and dpll */ + zl3073x_dpll_unregister_pins(zldpll); + zl3073x_dpll_unregister(zldpll); +} + +static const struct platform_device_id zl3073x_dpll_platform_id[] = { + { "zl3073x-dpll", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, zl3073x_dpll_platform_id); + +static struct platform_driver zl3073x_dpll_driver = { + .driver = { + .name = "zl3073x-dpll", + }, + .probe = zl3073x_dpll_probe, + .remove = zl3073x_dpll_remove, + .id_table = zl3073x_dpll_platform_id, +}; + +module_platform_driver(zl3073x_dpll_driver); + +MODULE_AUTHOR("Ivan Vecera "); +MODULE_AUTHOR("Tariq Haddad "); +MODULE_DESCRIPTION("Microchip ZL3073x DPLL driver"); +MODULE_IMPORT_NS("ZL3073X"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h index 825e6706dc974..3eaa5d96ca9af 100644 --- a/include/linux/mfd/zl3073x.h +++ b/include/linux/mfd/zl3073x.h @@ -9,9 +9,14 @@ /* * Hardware limits for ZL3073x chip family */ +#define ZL3073X_NUM_CHANNELS 2 #define ZL3073X_NUM_INPUTS 10 #define ZL3073X_NUM_OUTPUTS 10 #define ZL3073X_NUM_SYNTHS 5 +#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_INPUTS +#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTPUTS * 2) +#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \ + ZL3073X_NUM_OUTPUT_PINS) struct zl3073x_input { bool enabled; From patchwork Mon Apr 7 17:31:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041420 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D2B00221555 for ; Mon, 7 Apr 2025 17:32:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047150; cv=none; b=M0LxkU9Hu/gkDCHlxlAYuq5kUmBJHjp2YjVlRpXPlgmmsNfHvNGvc+SevzpmzfPChzvQyz39xDTAgUfK4ZwtpBWdgWIsjCqooT61MhCAinmiGxgy2KG7wh0yVByLK/7ufqyruX5r7V069B8AhnjYzwpxRwBGwSkpya2OOkbXBTc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047150; c=relaxed/simple; bh=KemroqypPAQNOLl43rDGjpI5YHw232i4a9JYpzF0eYA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aOjCG41MCDIEfFsW1b61bwcPpoSQ3J9IlnQucnZUUFsnv5VADGwAVmy0Az1r2jU5jDelb6KkiHmyay5LDYHmCAldBiXP9GHkHL/MHdlnZkhE0hXdpWFB1NmxlnGtqemO6Krosilu+ia1nXmJmP6IVbFfX59pyY2gavPYfd9EvEo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=XI1PEqFj; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="XI1PEqFj" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047148; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=udd9a9J+XCd9rjw5P99I+tp6pt4tvqQ0bA86sip24B8=; b=XI1PEqFjn2X1SoOGqerS8uBC0Rv+uJqm4Lu9r/e8M/a3+T05JTekhQN2erltxMJ6RdlROo +lNn2bLBtETWRekWU7onSpiK0VYrdiSroleeuH4YUH65Wgs7aj5jFh1WdeMThe46pKGEMd vzoHw7BuJ0aFpt5p9RHNOpNpHmbi/MU= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-595-CyFlr7aKP6GTIsHNNPqHOw-1; Mon, 07 Apr 2025 13:32:24 -0400 X-MC-Unique: CyFlr7aKP6GTIsHNNPqHOw-1 X-Mimecast-MFC-AGG-ID: CyFlr7aKP6GTIsHNNPqHOw_1744047142 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 10D6F1809CA3; Mon, 7 Apr 2025 17:32:22 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5CF9E1956094; Mon, 7 Apr 2025 17:32:16 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 14/28] mfd: zl3073x: Register DPLL sub-device during init Date: Mon, 7 Apr 2025 19:31:44 +0200 Message-ID: <20250407173149.1010216-5-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 Register DPLL sub-devices to expose this functionality provided by ZL3073x chip family. Each sub-device represents one of the provided DPLL channels. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/mfd/zl3073x-core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c index 9ed405a62fa86..8ac59133bc54a 100644 --- a/drivers/mfd/zl3073x-core.c +++ b/drivers/mfd/zl3073x-core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include #include #include @@ -760,6 +761,11 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev) return rc; } +static const struct mfd_cell zl3073x_devs[] = { + MFD_CELL_BASIC("zl3073x-dpll", NULL, NULL, 0, 0), + MFD_CELL_BASIC("zl3073x-dpll", NULL, NULL, 0, 1), +}; + int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id) { u16 id, revision, fw_ver; @@ -805,6 +811,16 @@ int zl3073x_dev_init(struct zl3073x_dev *zldev, u8 dev_id) FIELD_GET(GENMASK(15, 8), cfg_ver), FIELD_GET(GENMASK(7, 0), cfg_ver)); + /* Add DPLL sub-device cells */ + rc = devm_mfd_add_devices(zldev->dev, PLATFORM_DEVID_AUTO, zl3073x_devs, + ARRAY_SIZE(zl3073x_devs), NULL, 0, NULL); + if (rc) { + dev_err(zldev->dev, "Failed to add sub-devices: %pe\n", + ERR_PTR(rc)); + + return rc; + } + devlink = priv_to_devlink(zldev); devlink_register(devlink); From patchwork Mon Apr 7 17:31:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041421 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CBEE0221D94 for ; Mon, 7 Apr 2025 17:32:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047156; cv=none; b=eOYpmdT8sHv4MOXIIvC31i6LMw6N1YcVMU5v3t9tQUNSkYlllK4PuKHG0G2mMq/SKZlBc7bkd5sdu0m0uB7ULFikos+wNZ1D1zb93FMjV7MhDYBsTA1bI5ffm/XCkpTBxQoWW1hUiREKw8T0wT1Sr9ST4qCzoH2TOzVV4VOLn7c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047156; c=relaxed/simple; bh=xtGqFPAJUFtpvzp2oSfpCANz6sOWKTPyRiY70KmTtNY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iL4N3RvQErIrdlrl0coE2Ccilqb8BaLN8FRE4z/0jagc8VlDNfn3HQMzsSQ2BCmiAhpe95DipxBVmhTqtcSOPCucBhoinfjO9su8V2wqHveMj0Uis3rLqOojciXtt+xU1fMAE0Bm3mojaC0UPQ3T0lOKEQeP5juzpIzE3fJGyaY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=UxO6zkky; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="UxO6zkky" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047153; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=L3vlDHc0dtAdMNjfgHWKMugj/8OJ7Tnn4x/ZQC99e8I=; b=UxO6zkkypSA0ycIdBBsBZ+RgsTroTAVGUfiKwzusYYNxgra1UicV1mM7CfuAFxfWbWzC+a w/edeMIMZaQMJKkZ4++q9KqdtE277WJPmghGWTntDif4ylGnAkgIfRth8VPqIW7EeRjRiz 27IdAMEpoc47ZXBw07ocaieD3wjcZp8= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-19-Aqsky7_nMC-P6VdwL6SPIA-1; Mon, 07 Apr 2025 13:32:30 -0400 X-MC-Unique: Aqsky7_nMC-P6VdwL6SPIA-1 X-Mimecast-MFC-AGG-ID: Aqsky7_nMC-P6VdwL6SPIA_1744047148 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9366A19560AD; Mon, 7 Apr 2025 17:32:28 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 682AD1956094; Mon, 7 Apr 2025 17:32:22 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 15/28] dt-bindings: dpll: Add device tree bindings for DPLL device and pin Date: Mon, 7 Apr 2025 19:31:45 +0200 Message-ID: <20250407173149.1010216-6-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 This adds DT bindings schema for DPLL (device phase-locked loop) device and associated pin. The schema follows existing DPLL core API and should be used to expose information that should be provided by platform firmware. The schema for DPLL device describe a DPLL chip that can contain one or more DPLLs (channels) and platform can specify their types. For now 'pps' and 'eec' types supported and these values are mapped to DPLL core's enums. The DPLL device can have optionally 'input-pins' and 'output-pins' sub-nodes that contain pin sub-nodes. These pin sub-nodes follows schema for dpll-pin and can contain information about the particular pin. The pin contains the following properties: * reg - pin HW index (physical pin number of given type) * label - string that is used as board label by DPLL core * type - string that indicates pin type (mapped to DPLL core pin type) * esync-control - boolean that indicates whether embeddded sync control is allowed for this pin * supported-frequencies - list of 64bit values that represents frequencies that are allowed to be configured for the pin Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- .../devicetree/bindings/dpll/dpll-device.yaml | 84 +++++++++++++++++++ .../devicetree/bindings/dpll/dpll-pin.yaml | 43 ++++++++++ MAINTAINERS | 2 + 3 files changed, 129 insertions(+) create mode 100644 Documentation/devicetree/bindings/dpll/dpll-device.yaml create mode 100644 Documentation/devicetree/bindings/dpll/dpll-pin.yaml diff --git a/Documentation/devicetree/bindings/dpll/dpll-device.yaml b/Documentation/devicetree/bindings/dpll/dpll-device.yaml new file mode 100644 index 0000000000000..e6c309abb857f --- /dev/null +++ b/Documentation/devicetree/bindings/dpll/dpll-device.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dpll/dpll-device.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Digital Phase-Locked Loop (DPLL) Device + +maintainers: + - Ivan Vecera + +description: | + Digital Phase-Locked Loop (DPLL) device are used for precise clock + synchronization in networking and telecom hardware. The device can + have one or more channels (DPLLs) and one or more input and output + pins. Each DPLL channel can either produce pulse-per-clock signal + or drive ethernet equipment clock. The type of each channel is + indicated by dpll-types property. + +properties: + $nodename: + pattern: "^dpll(@.*)?$" + + "#address-cells": + const: 0 + + "#size-cells": + const: 0 + + num-dplls: + description: Number of DPLL channels in this device. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + + dpll-types: + description: List of DPLL types, one per DPLL instance. + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + items: + enum: [pps, eec] + + input-pins: + type: object + description: DPLL input pins + unevaluatedProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^pin@[0-9]+$": + $ref: /schemas/dpll/dpll-pin.yaml + unevaluatedProperties: false + + required: + - "#address-cells" + - "#size-cells" + + output-pins: + type: object + description: DPLL output pins + unevaluatedProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^pin@[0-9]+$": + $ref: /schemas/dpll/dpll-pin.yaml + unevaluatedProperties: false + + required: + - "#address-cells" + - "#size-cells" + +dependentRequired: + dpll-types: [ num-dplls ] + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/dpll/dpll-pin.yaml b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml new file mode 100644 index 0000000000000..9aea8ceabb5af --- /dev/null +++ b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dpll/dpll-pin.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DPLL Pin + +maintainers: + - Ivan Vecera + +description: | + Schema for defining input and output pins of a Digital Phase-Locked Loop (DPLL). + Each pin can have a set of supported frequencies, label, type and may support + embedded sync. + +properties: + reg: + description: Hardware index of the pin. + $ref: /schemas/types.yaml#/definitions/uint32 + + esync-control: + description: Indicates whether the pin supports embedded sync functionality. + type: boolean + + label: + description: String exposed as the pin board label + $ref: /schemas/types.yaml#/definitions/string + + supported-frequencies: + description: List of supported frequencies for this pin, expressed in Hz. + $ref: /schemas/types.yaml#/definitions/uint64-array + + type: + description: Type of the pin + $ref: /schemas/types.yaml#/definitions/string + enum: [ext, gnss, int, mux, synce] + + +required: + - reg + +additionalProperties: false diff --git a/MAINTAINERS b/MAINTAINERS index 3d542440d0b2b..eaf2576a9b746 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7194,6 +7194,8 @@ M: Arkadiusz Kubalewski M: Jiri Pirko L: netdev@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/dpll/dpll-device.yaml +F: Documentation/devicetree/bindings/dpll/dpll-pin.yaml F: Documentation/driver-api/dpll.rst F: drivers/dpll/* F: include/linux/dpll.h From patchwork Mon Apr 7 17:31:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041422 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 465C321765B for ; Mon, 7 Apr 2025 17:32:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047162; cv=none; b=a+jG/q05NyDgnnKHtQAfXfEXlJnDXeKQXUdinsSFPY0XF6saaty7q2v2RpBAWINSGtJBvOz/UhZ8aFI9wxa6QrsYvC/LGAt9IoM5Y/VIWiYMk5yBbhIYMWhH2b01LipznJKXKG8HBDidhNmJRu7YkHZsvdpENKN3HoM0kkfN/98= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047162; c=relaxed/simple; bh=fUWtEZtchgf52Hg+WQ+sPgT+xDS2yWU+wTpYDGEVStY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P+8W7Ov4b+HDHMJ3EDAisXxK0C6fAJZ8S8O9IsOlnm0e0Ere4w+QQZmdK0zlPILY3tDWj1CfFLa0vyx97LwNDaZOyw6J9jMEwoAKELuzwJLW5nXG6q8A9KmLHlW6m/Wy1+TCTsNR6g2rQuTe8ZSyN+kOwbD+cHD+dyep7JLhQc0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=PNv0adHu; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="PNv0adHu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047160; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=k8RER3e3u7RBnYnapJ8mt6emEOkYYUHBX8SC+kNOU1g=; b=PNv0adHu+kxik+P45fQfvRfMd2c4aAUqKjY27V/Kf5/iw6isVjaxOEpL1cwhn0WoBmcgwp GxMyDuzYv5YOeAttPKSPf48MNeYmtXOL4GJCsSZHz9SqzXc6wUP74x/m5iCbeEosUVzzlR b1UjedmBsLLhV6JIE+zTJChnp6Ava+w= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-461-VlIneVjJOfOUZfkAFySvjg-1; Mon, 07 Apr 2025 13:32:36 -0400 X-MC-Unique: VlIneVjJOfOUZfkAFySvjg-1 X-Mimecast-MFC-AGG-ID: VlIneVjJOfOUZfkAFySvjg_1744047154 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CF60B180AF55; Mon, 7 Apr 2025 17:32:34 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2CD711956094; Mon, 7 Apr 2025 17:32:28 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 16/28] dt-bindings: dpll: Add support for Microchip Azurite chip family Date: Mon, 7 Apr 2025 19:31:46 +0200 Message-ID: <20250407173149.1010216-7-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 This adds DT bindings schema for Microchip Azurite DPLL chip family. These bindings are used by zl3073x driver and specifies this device that can be connected either to I2C or SPI bus. The schema inherits existing dpll-device and dpll-pin schemas. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- .../bindings/dpll/microchip,zl3073x.yaml | 74 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 75 insertions(+) create mode 100644 Documentation/devicetree/bindings/dpll/microchip,zl3073x.yaml diff --git a/Documentation/devicetree/bindings/dpll/microchip,zl3073x.yaml b/Documentation/devicetree/bindings/dpll/microchip,zl3073x.yaml new file mode 100644 index 0000000000000..38a6cc00bc026 --- /dev/null +++ b/Documentation/devicetree/bindings/dpll/microchip,zl3073x.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dpll/microchip,zl3073x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip Azurite DPLL device + +maintainers: + - Ivan Vecera + +properties: + compatible: + enum: + - microchip,zl3073x-i2c + - microchip,zl3073x-spi + + reg: + maxItems: 1 + +required: + - compatible + - reg + +allOf: + - $ref: /schemas/dpll/dpll-device.yaml + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + dpll@70 { + compatible = "microchip,zl3073x-i2c"; + #address-cells = <0>; + #size-cells = <0>; + reg = <0x70>; + status = "okay"; + + num-dplls = <2>; + dpll-types = "pps", "eec"; + + input-pins { + #address-cells = <1>; + #size-cells = <0>; + + pin@0 { /* REF0P */ + reg = <0>; + + label = "Input 0"; + type = "ext"; + supported-frequencies = /bits/ 64 <1 1000>; + }; + }; + + output-pins { + #address-cells = <1>; + #size-cells = <0>; + + pin@3 { /* OUT1N */ + reg = <3>; + + label = "Output 1"; + type = "gnss"; + esync-control; + supported-frequencies = /bits/ 64 <1 10000>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index eaf2576a9b746..ec86bec05c40c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16001,6 +16001,7 @@ M: Ivan Vecera M: Prathosh Satish L: netdev@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/dpll/microchip,zl3073x.yaml F: drivers/dpll/dpll_zl3073x* F: drivers/mfd/zl3073x* F: include/linux/mfd/zl3073x.h From patchwork Mon Apr 7 17:31:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041423 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A50721771C for ; Mon, 7 Apr 2025 17:32:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047170; cv=none; b=J2RSp5hLl6W8kpc2+sBs60JWa7/g97qMjGjUczxGjxKwNDKxI9Czya4B8CnW7/vKSR4zhcQeVwt9qlYk+txONWN7DpA+dBc0HU3FGMyagu60KPYwcIY+9DKNhA0BB9myXdPVx2XsSXWHKHLftLU9Kr+VS4u8uCslRNn6dibFd2k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047170; c=relaxed/simple; bh=49hqjtrj2Bm53dnC39U3a+ODcKRvAUv40cACSLYXZXU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QWUEEtW+sIxKMl+txfjvFfjxc0L88KghLJ/QoOJOvXnOoTtS+mtpK7QJO0PfIVU4wTexDGg5UMn2BJEcZR8zVlx3vpBVBLmvZWm5ot5hsITgjZ2m7GXyLRdIaRlLgSwzVU1rgZixKw+AServxURWPG/e6xOYT/MXk9o5Dwujr0w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=VYgFBOBw; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="VYgFBOBw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047167; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0A8iBQW4zRukU1o2/FvgbTyI4yoMYUNvrAw++8qJBKw=; b=VYgFBOBwtRouHHUtp6sHon4c4ZEPzZG3qgKDxl+wqtCw8Q01Bt1oNYAnQ94jAjXPNv7LHC vU71CVbeYmDk1ohqC8FMGBumFRjpSqigqXwNQTuIVSMQfnMN7aQU5WS0odI7KhSPfeizAZ 6IhXwl5QyTTZobSj+y7tPybsptL+ll8= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-327-0LC92G_1N72hV6NNAHLWeA-1; Mon, 07 Apr 2025 13:32:43 -0400 X-MC-Unique: 0LC92G_1N72hV6NNAHLWeA-1 X-Mimecast-MFC-AGG-ID: 0LC92G_1N72hV6NNAHLWeA_1744047160 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A77EC19560B3; Mon, 7 Apr 2025 17:32:40 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4FFE11956094; Mon, 7 Apr 2025 17:32:35 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 17/28] dpll: zl3073x: Read DPLL types from firmware Date: Mon, 7 Apr 2025 19:31:47 +0200 Message-ID: <20250407173149.1010216-8-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 System firmware (DT, ACPI...) can provide a type for each DPLL. The types are stored in property 'dpll-types' as string array and possible values 'pps' and 'eec' are mapped to DPLL enums DPLL_TYPE_PPS and DPLL_TYPE_EEC. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index 34bd6964fe001..3ff53a333a6e9 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -6,6 +6,7 @@ #include #include #include +#include /* * Register Map Page 2, Status @@ -825,6 +826,36 @@ zl3073x_dpll_unregister_pins(struct zl3073x_dpll *zldpll) zl3073x_dpll_pin_unregister(&zldpll->pins[i]); } +static enum dpll_type +zl3073x_dpll_type_get(struct zl3073x_dpll *zldpll) +{ + const char *types[ZL3073X_NUM_CHANNELS]; + enum dpll_type type; + int rc; + + /* Set default */ + type = DPLL_TYPE_PPS; + + /* Read dpll types property from firmware */ + rc = device_property_read_string_array(zldpll->mfd->dev, "dpll-types", + types, ARRAY_SIZE(types)); + + /* It is not present or property does not exist, use default */ + if (rc <= zldpll->id) + return type; + + if (!strcmp(types[zldpll->id], "pps")) + type = DPLL_TYPE_PPS; + else if (!strcmp(types[zldpll->id], "eec")) + type = DPLL_TYPE_EEC; + else + dev_info(zldpll->mfd->dev, + "Unknown dpll type '%s', using default\n", + types[zldpll->id]); + + return type; +} + static int zl3073x_dpll_register(struct zl3073x_dpll *zldpll) { @@ -852,7 +883,8 @@ zl3073x_dpll_register(struct zl3073x_dpll *zldpll) if (IS_ERR(zldpll->dpll_dev)) return PTR_ERR(zldpll->dpll_dev); - rc = dpll_device_register(zldpll->dpll_dev, DPLL_TYPE_PPS, + rc = dpll_device_register(zldpll->dpll_dev, + zl3073x_dpll_type_get(zldpll), &zl3073x_dpll_device_ops, zldpll); if (rc) { dpll_device_put(zldpll->dpll_dev); From patchwork Mon Apr 7 17:31:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041424 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1B902218AC7 for ; Mon, 7 Apr 2025 17:32:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047174; cv=none; b=Dpj2VPgWglv9QCGb8PP9lSUCz2sE1BPC8AMpEk8TNWOE+nFeqv2nah5MD076rLLLmm3dTz/Ot48D2e75mezXId6eOszGGsgRntbj37nAxjT/BccrafO82JyN3oojnAeubf9H7TOaCwfrPLhedJpYtJG5nbPQr8BPsHeQymC5psY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047174; c=relaxed/simple; bh=bjhEBABbFfyeL3ryhS1ZcBP1MBr6Yd+wbkegepdkE2s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iZTzJRgW3cOv2CEqpvfPOpSKI3Qlu3KOSPEE8s8awOKcoAcOGEzH+GLnTG6W2Q4NjL7uZgCbxAtGmd8/9segQxmpDs+w5F9vxwaeX6DMZvREbYrVJadReRvpXwC4SNuBlLPXpKuZS4psydWhsjxujZlEOEsAwDIE64u2uED4NNI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=VNMK/f0o; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="VNMK/f0o" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047172; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BZh2K3E3QGemkZ831hKXCiq0LiByQJrgxf/Rwqw+Kco=; b=VNMK/f0oc/rfmePja67DX0ftKBsRXd5EbTNRvVYkDseMYJzkvid5dBF27BGAkcWxGvA19K tjtpKFIusPXb0TzcBTEhamQ0TdHlW2RkBNO8J+U9JCG9gj5RAAz9cqYZjmC/xr/4Wb0Dn+ 08g3OPzHoJjFfz7g5APqMAZtrzS9sAs= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-665-8dXyNwatN2aaKvH06GtA5w-1; Mon, 07 Apr 2025 13:32:49 -0400 X-MC-Unique: 8dXyNwatN2aaKvH06GtA5w-1 X-Mimecast-MFC-AGG-ID: 8dXyNwatN2aaKvH06GtA5w_1744047166 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CE9171809CA5; Mon, 7 Apr 2025 17:32:46 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 430071955BC0; Mon, 7 Apr 2025 17:32:40 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 18/28] dpll: zl3073x: Read optional pin properties from firmware Date: Mon, 7 Apr 2025 19:31:48 +0200 Message-ID: <20250407173149.1010216-9-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 The firmware (DT, ACPI...) can specify properties for particular pins. Input pins are stored in 'input-pins' sub-node and output pins in 'output-pins'. Each pin is represented by separate node in 'input-pins' or 'output-pins'. The properties that are supported: * reg - integer that specifies pin index * label - string that is used by driver as board label * type - string that indicates pin type Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 102 ++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index 3ff53a333a6e9..cf2cdd6dec263 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -73,10 +73,12 @@ ZL3073X_REG8_IDX_DEF(dpll_ref_prio, 0x652, * struct zl3073x_dpll_pin_info - DPLL pin info * @props: DPLL core pin properties * @package_label: pin package label + * @fwnode: pin firmware node */ struct zl3073x_dpll_pin_info { struct dpll_pin_properties props; char package_label[8]; + struct fwnode_handle *fwnode; }; /** @@ -482,6 +484,62 @@ static const struct dpll_device_ops zl3073x_dpll_device_ops = { .mode_get = zl3073x_dpll_mode_get, }; +/** + * zl3073x_dpll_pin_fwnode_get - get fwnode for given pin + * pin: pointer to pin structure + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Returns the firmware node for the given pin if it is present or + * NULL if it is missing. + */ +static struct fwnode_handle * +zl3073x_dpll_pin_fwnode_get(struct zl3073x_dpll_pin *pin) +{ + struct zl3073x_dpll *zldpll = pin_to_dpll(pin); + struct fwnode_handle *pins_node, *pin_node; + const char *node_name; + u8 idx; + + if (zl3073x_dpll_is_input_pin(pin)) + node_name = "input-pins"; + else + node_name = "output-pins"; + + /* Get node containing input or output pins */ + pins_node = device_get_named_child_node(zldpll->mfd->dev, node_name); + if (!pins_node) { + dev_dbg(zldpll->mfd->dev, "'%s' sub-node is missing\n", + node_name); + return NULL; + } + + /* Get pin HW index */ + idx = zl3073x_dpll_pin_index_get(pin); + + /* Enumerate pin nodes and find the requested one */ + fwnode_for_each_child_node(pins_node, pin_node) { + u32 reg; + + if (fwnode_property_read_u32(pin_node, "reg", ®)) + continue; + + if (idx == reg) + break; + } + + /* Release pin parent node */ + fwnode_handle_put(pins_node); + + dev_dbg(zldpll->mfd->dev, "Firmware node for %s%u%c %sfound\n", + zl3073x_dpll_is_input_pin(pin) ? "REF" : "OUT", idx / 2, + zl3073x_dpll_is_p_pin(pin) ? 'P' : 'N', + pin_node ? "" : "NOT "); + + return pin_node; +} + /** * zl3073x_dpll_pin_info_package_label_set - generate package label for the pin * @pin: pointer to pin @@ -548,8 +606,10 @@ zl3073x_dpll_pin_info_package_label_set(struct zl3073x_dpll_pin *pin, * zl3073x_dpll_pin_info_get - get pin info * @pin: pin whose info is returned * - * The function allocates pin info structure, generates package label - * string according pin type and its order number. + * The function looks for firmware node for the given pin if it is provided + * by the system firmware (DT or ACPI), allocates pin info structure, + * generates package label string according pin type and its order number + * and optionally fetches board label from the firmware node if it exists. * * Returns pointer to allocated pin info structure that has to be freed * by @zl3073x_dpll_pin_info_put by the caller and in case of error @@ -558,14 +618,16 @@ zl3073x_dpll_pin_info_package_label_set(struct zl3073x_dpll_pin *pin, static struct zl3073x_dpll_pin_info * zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) { + struct zl3073x_dev *zldev = pin_to_dev(pin); struct zl3073x_dpll_pin_info *pin_info; + const char *pin_type; /* Allocate pin info structure */ pin_info = kzalloc(sizeof(*pin_info), GFP_KERNEL); if (!pin_info) return ERR_PTR(-ENOMEM); - /* Set pin type */ + /* Set default pin type */ if (zl3073x_dpll_is_input_pin(pin)) pin_info->props.type = DPLL_PIN_TYPE_EXT; else @@ -577,6 +639,34 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) /* Generate package label for the given pin */ zl3073x_dpll_pin_info_package_label_set(pin, pin_info); + /* Get firmware node for the given pin */ + pin_info->fwnode = zl3073x_dpll_pin_fwnode_get(pin); + if (!pin_info->fwnode) + /* Return if it does not exist */ + return pin_info; + + /* Look for label property and store the value as board label */ + fwnode_property_read_string(pin_info->fwnode, "label", + &pin_info->props.board_label); + + /* Look for pin type property and translate its value to DPLL + * pin type enum if it is present. + */ + if (!fwnode_property_read_string(pin_info->fwnode, "type", &pin_type)) { + if (!strcmp(pin_type, "ext")) + pin_info->props.type = DPLL_PIN_TYPE_EXT; + else if (!strcmp(pin_type, "gnss")) + pin_info->props.type = DPLL_PIN_TYPE_GNSS; + else if (!strcmp(pin_type, "int")) + pin_info->props.type = DPLL_PIN_TYPE_INT_OSCILLATOR; + else if (!strcmp(pin_type, "synce")) + pin_info->props.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; + else + dev_warn(zldev->dev, + "Unknown or unsupported pin type '%s'\n", + pin_type); + } + return pin_info; } @@ -584,11 +674,15 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) * zl3073x_dpll_pin_info_put - free pin info * @pin_info: pin info to free * - * The function deallocates given pin info structure. + * The function deallocates given pin info structure and firmware node handle. */ static void zl3073x_dpll_pin_info_put(struct zl3073x_dpll_pin_info *pin_info) { + /* Put firmware handle if it is present */ + if (pin_info->fwnode) + fwnode_handle_put(pin_info->fwnode); + /* Free the pin info structure itself */ kfree(pin_info); } From patchwork Mon Apr 7 17:31:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041425 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 44517253B56 for ; Mon, 7 Apr 2025 17:33:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047184; cv=none; b=UKKXXD0sc5pz3HahaZoNyJhkttZyb8+BKapLBlv6NNQ5EGLA15W4Ah6DYAifTcZ8Fp3ON3IykI07ayPwFRKMFnX1XJRAufWJFz/SAzx7iTIz6DyxdTan4rrJ+FSZPR1hWW5+OFXUqjRpIe5wRdl640BeGEjapybyWnAVWmIRYiI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047184; c=relaxed/simple; bh=/KCV+k19D/ZEilHrdhSH00/mLdriTfar57/idijqgys=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fbPRvsGd5vxCuL2s6YKWF1vFPLcjV7qz0Bb1xOVL64tW0PZj3h4oh0FhHAeZFmni4F4h0Ni+I/5kVxrvDuJeBG5b9g5UUu8PjjeYqVnWxXCvqrLJw8NSGHAh6jKW/SH7yk7/hkQh2i7lKgh2/GmI4Odf8t6bTrbseFKnn5tEsg0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=icWx/CAD; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="icWx/CAD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047181; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=otJF277m8loBQ1n+65+voNXR2haFn/JCnsEQVYJTyYs=; b=icWx/CADSqh0fALqyCvNEGXbd4fwuz3yrv0zB3dU4/PPVChPmWvGK/R0dZWkXy86WoK1rs FvhW/vzsLeQTSrIIn326gHgNxsBLN7/oeeuMYFn8pJUt6dvKgll+WejSErBSx+0QQ8Mknh baIgmbKqYU6Nq4oK5OoPIJX/F2U5Yk0= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-17-C64szBcENQGLYe0u3vFJoA-1; Mon, 07 Apr 2025 13:32:55 -0400 X-MC-Unique: C64szBcENQGLYe0u3vFJoA-1 X-Mimecast-MFC-AGG-ID: C64szBcENQGLYe0u3vFJoA_1744047173 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id EE3D21956050; Mon, 7 Apr 2025 17:32:52 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 636A21956094; Mon, 7 Apr 2025 17:32:47 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 19/28] dpll: zl3073x: Implement input pin selection in manual mode Date: Mon, 7 Apr 2025 19:31:49 +0200 Message-ID: <20250407173149.1010216-10-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 Implement input pin state setting if the DPLL is running in manual mode. The driver indicates manual mode if the DPLL mode is one of ref-lock, forced-holdover, freerun and NCO (numerically controlled oscillator). Use these modes to implement input pin state change between connected and disconnected states. When the user set the particular pin as connected the driver marks this input pin as forced reference and switches the DPLL mode to ref-lock. When the use set the pin as disconnected the driver switches the DPLL to freerun or forced holdover mode. The switch to holdover mode is done if the DPLL has holdover capability (e.g is currently locked with holdover acquired). Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 114 +++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index cf2cdd6dec263..ad2a8d383daaf 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -274,6 +274,68 @@ zl3073x_dpll_selected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) * * Return 0 in case of success or negative value otherwise. */ +static int +zl3073x_dpll_selected_ref_set(struct zl3073x_dpll *zldpll, u8 ref) +{ + struct zl3073x_dev *zldev = zldpll->mfd; + u8 mode, mode_refsel; + int rc; + + mode = zldpll->refsel_mode; + + switch (mode) { + case DPLL_MODE_REFSEL_MODE_REFLOCK: /* Manual mode with ref selected */ + if (ref == ZL3073X_REF_NONE) { + switch (zldpll->lock_status) { + case DPLL_LOCK_STATUS_LOCKED_HO_ACQ: + case DPLL_LOCK_STATUS_HOLDOVER: + /* Switch to forced holdover */ + mode = DPLL_MODE_REFSEL_MODE_HOLDOVER; + break; + default: + /* Switch to freerun */ + mode = DPLL_MODE_REFSEL_MODE_FREERUN; + break; + } + /* Keep selected reference */ + ref = zldpll->forced_ref; + } else if (ref == zldpll->forced_ref) { + /* No register update - same mode and same ref */ + return 0; + } + break; + case DPLL_MODE_REFSEL_MODE_FREERUN: /* Manual mode without no ref */ + case DPLL_MODE_REFSEL_MODE_HOLDOVER: + if (ref == ZL3073X_REF_NONE) + /* No register update - keep current mode */ + return 0; + + /* Switch to reflock mode and update ref selection */ + mode = DPLL_MODE_REFSEL_MODE_REFLOCK; + break; + default: + /* For other modes like automatic or NCO ref cannot be selected + * manually + */ + return -EOPNOTSUPP; + } + + /* Build mode_refsel value */ + mode_refsel = FIELD_PREP(DPLL_MODE_REFSEL_MODE, mode) | + FIELD_PREP(DPLL_MODE_REFSEL_REF, ref); + + /* Update dpll_mode_refsel register */ + rc = zl3073x_write_dpll_mode_refsel(zldev, zldpll->id, mode_refsel); + if (rc) + return rc; + + /* Store new mode and forced reference */ + zldpll->refsel_mode = mode; + zldpll->forced_ref = ref; + + return rc; +} + static int zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) { @@ -396,6 +458,48 @@ zl3073x_dpll_input_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, return 0; } +static int +zl3073x_dpll_input_pin_state_on_dpll_set(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 new_ref; + int rc; + + switch (zldpll->refsel_mode) { + case DPLL_MODE_REFSEL_MODE_REFLOCK: + case DPLL_MODE_REFSEL_MODE_FREERUN: + case DPLL_MODE_REFSEL_MODE_HOLDOVER: + if (state == DPLL_PIN_STATE_CONNECTED) { + /* Choose the pin as new selected reference */ + new_ref = zl3073x_dpll_pin_index_get(pin); + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + /* No reference */ + new_ref = ZL3073X_REF_NONE; + } else { + NL_SET_ERR_MSG_MOD(extack, + "Invalid pin state for manual mode"); + return -EINVAL; + } + + rc = zl3073x_dpll_selected_ref_set(zldpll, new_ref); + break; + default: + /* In other modes we cannot change input reference */ + NL_SET_ERR_MSG(extack, + "Pin state cannot be changed in current mode"); + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + static int zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -472,6 +576,7 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, .state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get, + .state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set, }; static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = { @@ -627,11 +732,14 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) if (!pin_info) return ERR_PTR(-ENOMEM); - /* Set default pin type */ - if (zl3073x_dpll_is_input_pin(pin)) + /* Set default pin type and capabilities */ + if (zl3073x_dpll_is_input_pin(pin)) { pin_info->props.type = DPLL_PIN_TYPE_EXT; - else + pin_info->props.capabilities = + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; + } else { pin_info->props.type = DPLL_PIN_TYPE_GNSS; + } pin_info->props.phase_range.min = S32_MIN; pin_info->props.phase_range.max = S32_MAX; From patchwork Mon Apr 7 17:32:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041426 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF1EF21A42D for ; Mon, 7 Apr 2025 17:33:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047198; cv=none; b=RgrVPwvKaOEg8xiBaK5w2dIEnKziquHmFTqpxoznX1CozR0XsrOOznM6Z03fIK5RkMHi89p+Eo1GGozRZR4PQu+IjSMR/bPAJdsxk6cNHPPLSmvheqj2n8NE0GMvKpeiEa3GA9RpJSJrTZvhfaZRah0XR1jR6f2jEuNrKl7fDIQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047198; c=relaxed/simple; bh=MC4Rn9hwRMi8qupvH99rESMEC382s5ckUG9bARpwXMc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=K2UaKb/nHs3s4zR0zNV42oge/KZ38NsL26E6VAeZD2Bw5yKxMdL5vR1J58eNwBjX2LfrWvsNKqR/OCqTCWPgRxWPY/r6btVvbdPcLUTBo91fdwaoxVCIzNVmSwS4unI14dVbFGxFmAKBfR18z/cZObUhHIe3H/4lx87MT7rYQ90= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=eNCKp/ag; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="eNCKp/ag" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047196; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Fnu8pPESdTdvc3PutAnC7EsKpV2Up/lzUFesp7gWUMs=; b=eNCKp/agFZsR/4j6lDCwW9Doc56CW6EX1k6+JZv1p+OQdyrYlg3o3iyU1dDpYVwZ1a1NT4 MEnoQQYmX5iJ1C20w3UNrbT2onqwH0PtFWpucwPtyWjFdwjj9WbWEJEwq5CpmPofh21DV+ 8NoFt2NA6bIBXD3S4ZE9SHoJFxf1Hms= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-68-pOKLM6iQMW-9Y3KmmKF-3A-1; Mon, 07 Apr 2025 13:33:12 -0400 X-MC-Unique: pOKLM6iQMW-9Y3KmmKF-3A-1 X-Mimecast-MFC-AGG-ID: pOKLM6iQMW-9Y3KmmKF-3A_1744047189 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3BF651800258; Mon, 7 Apr 2025 17:33:09 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A9882180B488; Mon, 7 Apr 2025 17:33:03 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 20/28] dpll: zl3073x: Add support to get/set priority on input pins Date: Mon, 7 Apr 2025 19:32:53 +0200 Message-ID: <20250407173301.1010462-1-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This adds support for getting and setting input pin priority. Implement required callbacks and set appropriate capability for input pins. Although the pin priority make sense only if the DPLL is running in automatic mode we have to expose this capability unconditionally because input pins (references) are shared between both DPLLs where on of them can run in automatic mode while the other one not. Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index ad2a8d383daaf..072a33ec12399 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -403,6 +403,45 @@ zl3073x_dpll_ref_prio_get(struct zl3073x_dpll_pin *pin, u8 *prio) return rc; } +static int +zl3073x_dpll_ref_prio_set(struct zl3073x_dpll_pin *pin, u8 prio) +{ + struct zl3073x_dpll *zldpll = pin_to_dpll(pin); + struct zl3073x_dev *zldev = zldpll->mfd; + u8 idx, ref_prio; + int rc; + + /* Read DPLL configuration into mailbox */ + rc = zl3073x_mb_dpll_read(zldev, zldpll->id); + if (rc) + return rc; + + /* Get index of the pin */ + idx = zl3073x_dpll_pin_index_get(pin); + + /* Read ref prio nibble */ + rc = zl3073x_read_dpll_ref_prio(zldev, idx / 2, &ref_prio); + if (rc) + return rc; + + /* Update nibble according pin type */ + if (zl3073x_dpll_is_p_pin(pin)) { + ref_prio &= ~DPLL_REF_PRIO_REF_P; + ref_prio |= FIELD_PREP(DPLL_REF_PRIO_REF_P, prio); + } else { + ref_prio &= ~DPLL_REF_PRIO_REF_N; + ref_prio |= FIELD_PREP(DPLL_REF_PRIO_REF_N, prio); + } + + /* Write the updated priority value */ + rc = zl3073x_write_dpll_ref_prio(zldev, idx / 2, ref_prio); + if (rc) + return rc; + + /* Update channel configuration from mailbox */ + return zl3073x_mb_dpll_write(zldev, zldpll->id); +} + static int zl3073x_dpll_input_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -500,6 +539,46 @@ zl3073x_dpll_input_pin_state_on_dpll_set(const struct dpll_pin *dpll_pin, return rc; } +static int +zl3073x_dpll_input_pin_prio_get(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 *prio, struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll_pin *pin = pin_priv; + + *prio = pin->prio; + + return 0; +} + +static int +zl3073x_dpll_input_pin_prio_set(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 prio, struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + int rc; + + if (prio > DPLL_REF_PRIO_MAX) + return -EINVAL; + + /* If the pin is selectable then update HW registers */ + if (pin->selectable) { + guard(zl3073x)(zldev); + + rc = zl3073x_dpll_ref_prio_set(pin, prio); + if (rc) + return rc; + } + + /* Save priority */ + pin->prio = prio; + + return 0; +} + static int zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -575,6 +654,8 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, + .prio_get = zl3073x_dpll_input_pin_prio_get, + .prio_set = zl3073x_dpll_input_pin_prio_set, .state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get, .state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set, }; @@ -736,6 +817,7 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) if (zl3073x_dpll_is_input_pin(pin)) { pin_info->props.type = DPLL_PIN_TYPE_EXT; pin_info->props.capabilities = + DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; } else { pin_info->props.type = DPLL_PIN_TYPE_GNSS; From patchwork Mon Apr 7 17:32:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041427 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9744021ABCD for ; Mon, 7 Apr 2025 17:33:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047205; cv=none; b=qzHuLJOV9OvOq0ZuGmEsVJJgmf5VfyjAiT9QwkIB8z/9uBKd6EjmJNaJVl54w5179nwT1061ySS1J5wQ7oT73wAqpdWychor+ETmwq69DdWtii0ExYCJUsaANMpOfHN/rkipFUxC16fDtCCi+Mq0cEkYVrQLxkpuZdwzQ/VUNFU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047205; c=relaxed/simple; bh=S64LLOv+phJ1sh/gyAltMslCWxzcy05FWJrzVexjXi4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IA1llYTHpb3wawj/mNGLDZ00uDXciz1PzYVV4jbMqtI+UBdk4rrsY5I9BAc8mcGSxeU0nLO2PAXNcG46CkUpxTY1OIdPdFN/KW7e/6Ceqkdn/3gXj4C+nYJheplcxC4WN0hAAzrQiXYOnPA9tzDxCka+mun21+NW3BY1DFR7qH0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Ld+y4Fng; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Ld+y4Fng" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047202; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Q+TOrZM8LS94zLOtYPy81UhS5jAQZ3/ApDxkhaAypKk=; b=Ld+y4Fngoef+VD+LgGbuHiEZ/AoAKB7DkPBEOgvUPxV90d4q1IB7P01BU6hq709nH+dgEV PLf8MFIOe7aQoKj0Wpmw3k+O0SVgYij8ABZ2dZq2srJsLmq3S58Cf79cKLbaIz+LW+PMq+ JCI/CmKa/uHZds/b/oM/21lD+2wTTSg= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-671-UFZfRjg1PfmRfueFwup7Ig-1; Mon, 07 Apr 2025 13:33:17 -0400 X-MC-Unique: UFZfRjg1PfmRfueFwup7Ig-1 X-Mimecast-MFC-AGG-ID: UFZfRjg1PfmRfueFwup7Ig_1744047195 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 369561956080; Mon, 7 Apr 2025 17:33:15 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id CC8051828AA7; Mon, 7 Apr 2025 17:33:09 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 21/28] dpll: zl3073x: Implement input pin state setting in automatic mode Date: Mon, 7 Apr 2025 19:32:54 +0200 Message-ID: <20250407173301.1010462-2-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This implements input pin state setting when the DPLL is running in automatic mode. Unlike manual mode, the DPLL mode switching is not used here and the implementation uses special priority value (15) to make the given pin non-selectable. When the user sets state of the pin as disconnected the driver internally sets its priority in HW to 15 that prevents the DPLL to choose this input pin. Conversely, if the pin status is set to selectable, the driver sets the pin priority in HW to the original saved value. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index 072a33ec12399..192e0e56fcdde 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -528,6 +528,37 @@ zl3073x_dpll_input_pin_state_on_dpll_set(const struct dpll_pin *dpll_pin, rc = zl3073x_dpll_selected_ref_set(zldpll, new_ref); break; + + case DPLL_MODE_REFSEL_MODE_AUTO: + if (state == DPLL_PIN_STATE_SELECTABLE) { + if (pin->selectable) + return 0; /* Pin is already selectable */ + + /* Restore pin priority in HW */ + rc = zl3073x_dpll_ref_prio_set(pin, pin->prio); + if (rc) + return rc; + + /* Mark pin as selectable */ + pin->selectable = true; + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + if (!pin->selectable) + return 0; /* Pin is already disconnected */ + + /* Set pin priority to none in HW */ + rc = zl3073x_dpll_ref_prio_set(pin, DPLL_REF_PRIO_NONE); + if (rc) + return rc; + + /* Mark pin as non-selectable */ + pin->selectable = false; + } else { + NL_SET_ERR_MSG(extack, + "Invalid pin state for automatic mode"); + return -EINVAL; + } + break; + default: /* In other modes we cannot change input reference */ NL_SET_ERR_MSG(extack, From patchwork Mon Apr 7 17:32:55 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041428 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D6DBE253F35 for ; Mon, 7 Apr 2025 17:33:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047208; cv=none; b=drTHmwPWbz8q3YBsGIf2+FthHqUzcGuZA1Mr6rpqYKRrUlST6PykczLDfMqUPQc/L72p2/iEz0MBow87cyt1MEwDSyqTwAjHUVNlCYsbxvMY9gowcIWfLldqsW4tl04g+Gm92cV38pUyfgCwxgScCkPry4ZJ4du1Eugq9CbJ/jQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047208; c=relaxed/simple; bh=fOinvVF4zjc5mAIV5+YxY0DBJZSXdcUH4zkv4GiwKIA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bEq0B0j1gGtt/vSVOS5bBP1b4WIul+NpowMCKSp4Ia/BVNwOC/f7qmRcyo26/+YBGQ1+dpvWAlVEqmpovsEqDW2jelHuwk2FanVdlv1h0bd79OqoxOHKpMN/HynR2cOGL8bQGCyK8bfPaeE2JdfgPgKfG0y/nWhbAlwtDAaPkec= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=DHv6iTZT; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="DHv6iTZT" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047206; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Zv+1ZBatY0TmzFGyhm3TfhAvf1Rfkq6eLjmy+v+sptY=; b=DHv6iTZTW7kvEq4QVfOsvMsZqKXBGXf//bOSrRuUkz8yugycjIsdbq33L2Pk2bwl6q7vWq ViME+tJfq2SaT0o5txdDHSkYCuMh4qrcA2pgmfpt1Uf3XabWv8UYXQeOrjdkocjQVVCr3T s40Qac1QGaX5/mDqmW7ydMAYG4TJSXA= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-652-h0TdVLfoPYyS7zgSHc5bNw-1; Mon, 07 Apr 2025 13:33:24 -0400 X-MC-Unique: h0TdVLfoPYyS7zgSHc5bNw-1 X-Mimecast-MFC-AGG-ID: h0TdVLfoPYyS7zgSHc5bNw_1744047201 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5170B180AF52; Mon, 7 Apr 2025 17:33:21 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BDAB7180B488; Mon, 7 Apr 2025 17:33:15 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 22/28] dpll: zl3073x: Add support to get/set frequency on input pins Date: Mon, 7 Apr 2025 19:32:55 +0200 Message-ID: <20250407173301.1010462-3-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Add support to get/set frequency from/to input pins. The frequency for input pins (references) is computed in the device according this formula: freq = base_freq * multiplier * (nominator / denominator) where the base_freq comes from the list of supported base frequencies and other parameters are arbitrary numbers. All these parameters are 16-bit unsigned integers. Implement necessary callbacks for input pins and helper function to factorize a frequency into a base frequency and a multiplier (nominator and denominator are used as 1 for now). Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 179 ++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index 192e0e56fcdde..965664da9371d 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -56,6 +56,14 @@ ZL3073X_REG8_DEF(synth_phase_shift_mask, 0x49f); ZL3073X_REG8_DEF(synth_phase_shift_intvl, 0x4a0); ZL3073X_REG16_DEF(synth_phase_shift_data, 0x4a1); +/* + * Register Map Page 10, Ref Mailbox + */ +ZL3073X_REG16_DEF(ref_freq_base, 0x505); +ZL3073X_REG16_DEF(ref_freq_mult, 0x507); +ZL3073X_REG16_DEF(ref_ratio_m, 0x509); +ZL3073X_REG16_DEF(ref_ratio_n, 0x50b); + /* * Register Map Page 12, DPLL Mailbox */ @@ -218,6 +226,175 @@ zl3073x_dpll_pin_direction_get(const struct dpll_pin *dpll_pin, void *pin_priv, return 0; } +/** + * zl3073x_dpll_input_ref_frequency_factorize - factorize given frequency + * @freq: input frequency + * @base_freq: base frequency + * @mult: multiplier + * + * Checks if the given frequency can be factorized using one of the + * supported base frequencies. If so the base frequency and multiplier + * are stored into appropriate parameters if they are not NULL and + * returns 0. If the frequency cannot be factorized then the function + * returns -EINVAL. + */ +static int +zl3073x_dpll_input_ref_frequency_factorize(u64 freq, u16 *base, u16 *mult) +{ + static const u16 base_freqs[] = { + 1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, + 128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000, + 1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250, + 6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250, + 32000, 40000, 50000, 62500, + }; + u32 div, rem; + int i; + + for (i = 0; i < ARRAY_SIZE(base_freqs); i++) { + div = div_u64_rem(freq, base_freqs[i], &rem); + if (!rem && div <= U16_MAX) { + if (base) + *base = base_freqs[i]; + if (mult) + *mult = div; + + return 0; + } + } + + return -EINVAL; +} + +/** + * zl3073x_dpll_input_ref_frequency_get - get input reference frequency + * zldev: pointer to device structure + * ref_id: reference id + * frequency: pointer to variable to store frequency + * + * Context: zl3073x_dev.lock has to be held + * + * Reads frequency of given input reference. + * + * Returns 0 in case of success or negative value if error occurred + */ +static int +zl3073x_dpll_input_ref_frequency_get(struct zl3073x_dev *zldev, u8 ref_id, + u64 *frequency) +{ + u16 base_freq, mult, num, denom; + int rc; + + /* Read reference configuration into mailbox */ + rc = zl3073x_mb_ref_read(zldev, ref_id); + if (rc) + return rc; + + /* Read base frequency */ + rc = zl3073x_read_ref_freq_base(zldev, &base_freq); + if (rc) + return rc; + + /* Read multiplier */ + rc = zl3073x_read_ref_freq_mult(zldev, &mult); + if (rc) + return rc; + + /* Write numerator */ + rc = zl3073x_read_ref_ratio_m(zldev, &num); + if (rc) + return rc; + + /* Write denominator */ + rc = zl3073x_read_ref_ratio_n(zldev, &denom); + if (rc) + return rc; + + /* Sanity check that HW has not returned zero denominator */ + if (!denom) { + dev_err(zldev->dev, + "Zero divisor for ref %u frequency got from device\n", + ref_id); + return -EINVAL; + } + + *frequency = mul_u64_u32_div(base_freq * mult, num, denom); + + return rc; +} + +static int +zl3073x_dpll_input_pin_frequency_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 *frequency, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 ref_id; + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Read and return ref frequency */ + return zl3073x_dpll_input_ref_frequency_get(zldev, ref_id, frequency); +} + +static int +zl3073x_dpll_input_pin_frequency_set(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 frequency, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u16 base_freq, mult; + u8 ref_id; + int rc; + + /* Get base frequency and multiplier for the requested frequency */ + rc = zl3073x_dpll_input_ref_frequency_factorize(frequency, &base_freq, + &mult); + if (rc) + return rc; + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Write base frequency */ + rc = zl3073x_write_ref_freq_base(zldev, base_freq); + if (rc) + return rc; + + /* Write multiplier */ + rc = zl3073x_write_ref_freq_mult(zldev, mult); + if (rc) + return rc; + + /* Write numerator */ + rc = zl3073x_write_ref_ratio_m(zldev, 1); + if (rc) + return rc; + + /* Write denominator */ + rc = zl3073x_write_ref_ratio_n(zldev, 1); + if (rc) + return rc; + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Update reference configuration from mailbox */ + return zl3073x_mb_ref_write(zldev, ref_id); +} + /** * zl3073x_dpll_selected_ref_get - get currently selected reference * @zldpll: pointer to zl3073x_dpll @@ -685,6 +862,8 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, + .frequency_get = zl3073x_dpll_input_pin_frequency_get, + .frequency_set = zl3073x_dpll_input_pin_frequency_set, .prio_get = zl3073x_dpll_input_pin_prio_get, .prio_set = zl3073x_dpll_input_pin_prio_set, .state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get, From patchwork Mon Apr 7 17:32:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041429 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6CB4D219A7D for ; Mon, 7 Apr 2025 17:33:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047218; cv=none; b=J5RhB7CVz+dVoTNyih3tj8/rIOqiVj5WJEimmku/4QgDZalZqBOV7t1+igtvMV5hy7RP8jHBXgaQNxVTZH9PAmh1Q9WxgJ/z8C9ewyYqyEvo4kY4iX4ydt8vc5BCDUGqdRf3QpnCQXOER+Ol2vZp+5fvqyk9RmDd3qtmzlnx6oA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047218; c=relaxed/simple; bh=9tEV12iT+lk/TQbKifPeVzB73FC77sRewfBk494d0R4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eg1MOHABHe9WZ3k6wujcdexAYdFBI/NKym8kUzetThomKCnNFdvGAsWoKJcsCQxOwcuxgfobdeMdkChDsykzRT2YijF1+iQ+GoKh/wEa+BiKowz06gHph7wzCMk5FLlaJz3fU7Y2Dc+FeChem7PTxx6gFym25V8U9Hip2aMURSI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=f36/GH3c; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="f36/GH3c" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047214; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nyJ7SczzSvPBvcmVSXKy9h7tEHe7K41VOZ4HgFb0Xyk=; b=f36/GH3cXHYKxu1F7S9tsXcExdRgEu111HEVGwzHQg40qKGrI2/OeScsE417m1FAwFuOLF izX2bQ+dwIm0FuLc2EPDW45biTq470kDLiLgqvhx7MdEg1bIXoQ+N6Qz7nbIgGMyBnJkjL jfAC2mhtgpLAyoth9AGph2eL+sYKb4g= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-312-r7q0JEySM8i0VCg5F-ehuA-1; Mon, 07 Apr 2025 13:33:29 -0400 X-MC-Unique: r7q0JEySM8i0VCg5F-ehuA-1 X-Mimecast-MFC-AGG-ID: r7q0JEySM8i0VCg5F-ehuA_1744047207 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 61CB31801A1A; Mon, 7 Apr 2025 17:33:27 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E126C180B488; Mon, 7 Apr 2025 17:33:21 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 23/28] dpll: zl3073x: Add support to get/set frequency on output pins Date: Mon, 7 Apr 2025 19:32:56 +0200 Message-ID: <20250407173301.1010462-4-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This adds support to get/set frequencies for output pins. The frequency for output pin is determined by the frequency of synthesizer the output pin is connected to and divisor of the output to which is the given pin belongs. The resulting frequency of the P-pin and the N-pin from this output pair depends on the signal format of this output pair. The device supports so-called N-divided signal formats where for the N-pin there is an additional divisor. The frequencies for both pins from such output pair are computed: P-pin-freq = synth_freq / output_div N-pin-freq = synth_freq / output_div / n_div For other signal-format types both P and N pin have the same frequency based only synth frequency and output divisor. Implement output pin callbacks to get and set frequency. The frequency setting for the output non-N-divided signal format is simple as we have to compute just new output divisor. For N-divided formats it is more complex because by changing of output divisor we change frequency for both P and N pins. In this case if we are changing frequency for P-pin we have to compute also new N-divisor for N-pin to keep its current frequency. From this and the above it follows that the frequency of the N-pin cannot be higher than the frequency of the P-pin and the callback must take this limitation into account. Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 248 ++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index 965664da9371d..07a547aaee0f1 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -74,6 +74,14 @@ ZL3073X_REG8_IDX_DEF(dpll_ref_prio, 0x652, #define DPLL_REF_PRIO_MAX 14 #define DPLL_REF_PRIO_NONE 15 /* non-selectable */ +/* + * Register Map Page 14, Output Mailbox + */ +ZL3073X_REG32_DEF(output_div, 0x70c); +ZL3073X_REG32_DEF(output_width, 0x710); +ZL3073X_REG32_DEF(output_ndiv_period, 0x714); +ZL3073X_REG32_DEF(output_ndiv_width, 0x718); + #define ZL3073X_REF_NONE ZL3073X_NUM_INPUT_PINS #define ZL3073X_REF_IS_VALID(_ref) ((_ref) != ZL3073X_REF_NONE) @@ -787,6 +795,244 @@ zl3073x_dpll_input_pin_prio_set(const struct dpll_pin *dpll_pin, void *pin_priv, return 0; } +static u8 +zl3073x_dpll_pin_synth_get(struct zl3073x_dpll_pin *pin) +{ + u8 output = zl3073x_dpll_output_pin_output_get(pin); + + return zl3073x_output_synth_get(pin_to_dev(pin), output); +} + +static int +zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 *frequency, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 output, signal_format, synth; + u64 synth_freq; + u32 output_div; + int rc; + + guard(zl3073x)(zldev); + + output = zl3073x_dpll_output_pin_output_get(pin); + synth = zl3073x_dpll_pin_synth_get(pin); + synth_freq = zl3073x_synth_freq_get(zldev, synth); + + /* Read output configuration into mailbox */ + rc = zl3073x_mb_output_read(zldev, output); + if (rc) + return rc; + + /* Get divisor */ + rc = zl3073x_read_output_div(zldev, &output_div); + if (rc) + return rc; + + /* Check output divisor for zero */ + if (!output_div) { + dev_err(zldev->dev, + "Zero divisor for output %u got from device\n", + output); + return -EINVAL; + } + + /* Read used signal format for the given output */ + signal_format = zl3073x_output_signal_format_get(zldev, output); + + switch (signal_format) { + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV: + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV: + /* In case of divided format we have to distiguish between + * given output pin type. + */ + if (zl3073x_dpll_is_p_pin(pin)) { + /* For P-pin the resulting frequency is computed as + * simple division of synth frequency and output + * divisor. + */ + *frequency = div_u64(synth_freq, output_div); + } else { + /* For N-pin we have to divide additionally by + * divisor stored in output_ndiv_period register + * that is used as N-pin divisor for these modes. + */ + u64 divisor; + u32 ndiv; + + rc = zl3073x_read_output_ndiv_period(zldev, &ndiv); + if (rc) + return rc; + + /* Check N-pin divisor for zero */ + if (!ndiv) { + dev_err(zldev->dev, + "Zero N-pin divisor for output %u got from device\n", + output); + return -EINVAL; + } + + /* Compute final divisor for N-pin */ + divisor = mul_u32_u32(output_div, ndiv); + *frequency = div64_u64(synth_freq, divisor); + } + break; + default: + /* In other modes the resulting frequency is computed as + * division of synth frequency and output divisor. + */ + *frequency = div_u64(synth_freq, output_div); + break; + } + + return rc; +} + +static int +zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 frequency, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u32 output_n_freq, output_p_freq; + u8 output, signal_format, synth; + u32 cur_div, new_div, n_div; + u64 rem, synth_freq; + int rc; + + output = zl3073x_dpll_output_pin_output_get(pin); + synth = zl3073x_dpll_pin_synth_get(pin); + synth_freq = zl3073x_synth_freq_get(zldev, synth); + + /* Compute new divisor and check the remainder to be zero as + * the requested frequency has to divide synthesizer frequency + */ + new_div = (u32)div64_u64_rem(synth_freq, frequency, &rem); + if (rem) { + dev_err(zldev->dev, + "The requested frequency must divide %llu Hz\n", + synth_freq); + return -EINVAL; + } + + guard(zl3073x)(zldev); + + /* Read output configuration into mailbox */ + rc = zl3073x_mb_output_read(zldev, output); + if (rc) + return rc; + + /* Get used signal format for the given output */ + signal_format = zl3073x_output_signal_format_get(zldev, output); + + /* Check signal format */ + if (signal_format != OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV && + signal_format != OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV) { + /* For non N-divided signal formats the frequency is computed + * as division of synth frequency and output divisor. + */ + rc = zl3073x_write_output_div(zldev, new_div); + if (rc) + return rc; + + /* For 50/50 duty cycle the divisor is equal to width */ + rc = zl3073x_write_output_width(zldev, new_div); + if (rc) + return rc; + + /* Update output configuration from mailbox */ + return zl3073x_mb_output_write(zldev, output); + } + + /* For N-divided signal format get current divisor */ + rc = zl3073x_read_output_div(zldev, &cur_div); + if (rc) + return rc; + + /* Check output divisor for zero */ + if (!cur_div) { + dev_err(zldev->dev, + "Zero divisor for output %u got from device\n", + output); + return -EINVAL; + } + + /* Compute current output frequency for P-pin */ + output_p_freq = (u32)div_u64(synth_freq, cur_div); + + /* Get N-pin divisor */ + rc = zl3073x_read_output_ndiv_period(zldev, &n_div); + if (rc) + return rc; + + /* Check N-pin divisor for zero */ + if (!n_div) { + dev_err(zldev->dev, + "Zero N-pin divisor for output %u got from device\n", + output); + return -EINVAL; + } + + /* Compute current N-pin frequency */ + output_n_freq = output_p_freq / n_div; + + if (zl3073x_dpll_is_p_pin(pin)) { + /* We are going to change output frequency for P-pin but + * if the requested frequency is less than current N-pin + * frequency then indicate a failure as we are not able + * to compute N-pin divisor to keep its frequency unchanged. + */ + if (frequency <= output_n_freq) + return -EINVAL; + + /* Update the register with new divisor */ + rc = zl3073x_write_output_div(zldev, new_div); + if (rc) + return rc; + + /* For 50/50 duty cycle the divisor is equal to width */ + rc = zl3073x_write_output_width(zldev, new_div); + if (rc) + return rc; + + /* Compute new divisor for N-pin */ + n_div = (u32)div_u64(frequency, output_n_freq); + } else { + /* We are going to change frequency of N-pin but if + * the requested freq is greater or equal than freq of P-pin + * in the output pair we cannot compute divisor for the N-pin. + * In this case indicate a failure. + */ + if (output_p_freq <= frequency) + return -EINVAL; + + /* Compute new divisor for N-pin */ + n_div = output_p_freq / (u32)frequency; + } + + /* Update divisor for the N-pin */ + rc = zl3073x_write_output_ndiv_period(zldev, n_div); + if (rc) + return rc; + + /* For 50/50 duty cycle the divisor is equal to width */ + rc = zl3073x_write_output_ndiv_width(zldev, n_div); + if (rc) + return rc; + + /* Update output configuration from mailbox */ + return zl3073x_mb_output_write(zldev, output); +} + static int zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -872,6 +1118,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, + .frequency_get = zl3073x_dpll_output_pin_frequency_get, + .frequency_set = zl3073x_dpll_output_pin_frequency_set, .state_on_dpll_get = zl3073x_dpll_output_pin_state_on_dpll_get, }; From patchwork Mon Apr 7 17:32:57 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041430 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 89D81254B12 for ; Mon, 7 Apr 2025 17:33:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047222; cv=none; b=cqv9dSh9eL35Uw5o7eGPtPQcnhJC+yfQQf7QaQcAzvt6jEXO99v1+4/ldze8xalINKQN0Dsi10pp52uTjtkRXU/X5PaheHdUGZRwDfkzfEziuYXOfG/6yyEb9h9kkQxjg3vU/TryNWwPev8lRSLjZhzxm/s7mIWDUTXT9DoZD6I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047222; c=relaxed/simple; bh=DRCfWmbveIiLL0d5tqLyI8lBbAe/vx7B4mNE/zCKgCA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kqLwL80uVHqoenuMMosauABIKlXnJU2KJq/7c+mm7+IdoyWmVfgQ6bMEcCSqGxh2QkzWU7GMlyzZs0jCr/iIkOnsg5sZ379il8GILLmczO19kYuo1sh1sWef1BcqKB6Kk3T/iZ2JVw+EIIPQt50EgVjHpeJSdCKQMmPIP/YMwHw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=L8DPFXY/; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="L8DPFXY/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047219; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yc4/9CW3rJH+yqhkuOfWo/UTCk+B5f4doeNIHMtXuqY=; b=L8DPFXY/oCRfjaoPuY/1xuvLVDJG7s+ppFOBOxE34EjMu6KnNAikj4U66py6lfrFZQQrGR 37lH8RBIq8w8uIpXt14kz+/acKFazxw2O0mwSJItsgcya/aDI9+GY7xrYFME/iguQ1imaB kuKGNd1Xde57Kw0apoIyoAdIcTnQwlg= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-230-AeDdyyApPemMDy3V-V-27g-1; Mon, 07 Apr 2025 13:33:36 -0400 X-MC-Unique: AeDdyyApPemMDy3V-V-27g-1 X-Mimecast-MFC-AGG-ID: AeDdyyApPemMDy3V-V-27g_1744047213 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B8C11180AF65; Mon, 7 Apr 2025 17:33:33 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EAF131828A80; Mon, 7 Apr 2025 17:33:27 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Prathosh Satish , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 24/28] dpll: zl3073x: Read pin supported frequencies from firmware Date: Mon, 7 Apr 2025 19:32:57 +0200 Message-ID: <20250407173301.1010462-5-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 The firmware (DT, ACPI...) can specify what frequencies are supported for particular pins. Load the frequencies from the appropriate property and use them during pin registation. The unsupported frequencies that cannot be represented in device are filtered out. Reviewed-by: Michal Schmidt Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 113 +++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index 07a547aaee0f1..c920904008e22 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -1246,6 +1246,50 @@ zl3073x_dpll_pin_info_package_label_set(struct zl3073x_dpll_pin *pin, pin_info->props.package_label = pin_info->package_label; } +/** + * zl3073x_dpll_check_frequency - verify frequency for given pin + * @pin: pointer to pin + * @freq: frequency to check + * + * The function checks the given frequency is valid for the device. For input + * pins it checks that the frequency can be factorized using supported base + * frequencies. For output pins it checks that the frequency divides connected + * synth frequency without remainder. + * + * Returns true if the frequency is valid or false if not. + */ +static bool +zl3073x_dpll_check_frequency(struct zl3073x_dpll_pin *pin, u64 freq) +{ + if (zl3073x_dpll_is_input_pin(pin)) { + u16 base, mult; + int rc; + + /* Check if the frequency can be factorized */ + rc = zl3073x_dpll_input_ref_frequency_factorize(freq, &base, + &mult); + if (!rc) + return true; + } else { + struct zl3073x_dev *zldev = pin_to_dev(pin); + u64 synth_freq, rem; + u8 synth; + + /* Get output pin synthesizer */ + synth = zl3073x_dpll_pin_synth_get(pin); + + /* Get synth frequency */ + synth_freq = zl3073x_synth_freq_get(zldev, synth); + + /* Check the frequency divides synth frequency */ + div64_u64_rem(synth_freq, freq, &rem); + if (!rem) + return true; + } + + return false; +} + /** * zl3073x_dpll_pin_info_get - get pin info * @pin: pin whose info is returned @@ -1253,7 +1297,8 @@ zl3073x_dpll_pin_info_package_label_set(struct zl3073x_dpll_pin *pin, * The function looks for firmware node for the given pin if it is provided * by the system firmware (DT or ACPI), allocates pin info structure, * generates package label string according pin type and its order number - * and optionally fetches board label from the firmware node if it exists. + * and optionally fetches board label and supported frequencies from + * the firmware node if they exist. * * Returns pointer to allocated pin info structure that has to be freed * by @zl3073x_dpll_pin_info_put by the caller and in case of error @@ -1264,7 +1309,10 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) { struct zl3073x_dev *zldev = pin_to_dev(pin); struct zl3073x_dpll_pin_info *pin_info; + struct dpll_pin_frequency *ranges; + int i, j, num_freqs, rc; const char *pin_type; + u64 *freqs; /* Allocate pin info structure */ pin_info = kzalloc(sizeof(*pin_info), GFP_KERNEL); @@ -1315,7 +1363,67 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) pin_type); } + /* Read supported frequencies property if it is specified */ + num_freqs = fwnode_property_count_u64(pin_info->fwnode, + "supported-frequencies"); + if (num_freqs <= 0) + /* Return if the property does not exist or number is 0 */ + return pin_info; + + /* The firmware node specifies list of supported frequencies while + * DPLL core pin properties requires list of frequency ranges. + * So read the frequency list into temporary array. + */ + freqs = kcalloc(num_freqs, sizeof(*freqs), GFP_KERNEL); + if (!freqs) { + rc = -ENOMEM; + goto err_alloc_freqs; + } + + /* Read frequencies list from firmware node */ + fwnode_property_read_u64_array(pin_info->fwnode, + "supported-frequencies", freqs, + num_freqs); + + /* Allocate frequency ranges list and fill it */ + ranges = kcalloc(num_freqs, sizeof(*ranges), GFP_KERNEL); + if (!ranges) { + rc = -ENOMEM; + goto err_alloc_ranges; + } + + /* Convert list of frequencies to list of frequency ranges but + * filter-out frequencies that are not representable by device + */ + for (i = 0, j = 0; i < num_freqs; i++) { + struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]); + + if (zl3073x_dpll_check_frequency(pin, freqs[i])) { + ranges[j] = freq; + j++; + } else { + dev_warn(zldev->dev, + "Unsupported frequency %llu Hz in firmware node\n", + freqs[i]); + } + } + + /* Save number of freq ranges and pointer to them into pin properties */ + pin_info->props.freq_supported = ranges; + pin_info->props.freq_supported_num = j; + + /* Free temporary array */ + kfree(freqs); + return pin_info; + +err_alloc_ranges: + kfree(freqs); +err_alloc_freqs: + fwnode_handle_put(pin_info->fwnode); + kfree(pin_info); + + return ERR_PTR(rc); } /** @@ -1327,6 +1435,9 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) static void zl3073x_dpll_pin_info_put(struct zl3073x_dpll_pin_info *pin_info) { + /* Free supported frequency ranges list if it is present */ + kfree(pin_info->props.freq_supported); + /* Put firmware handle if it is present */ if (pin_info->fwnode) fwnode_handle_put(pin_info->fwnode); From patchwork Mon Apr 7 17:32:58 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041431 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7FB2821C9E0 for ; Mon, 7 Apr 2025 17:33:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047231; cv=none; b=AAnIknS/Lo1F2sxPaxJBJ9UWhZ98j5jdk8Dev24wZkA+t5wiMrUeA4/3LhIrlLmW68ZfTcYrDWyRhxUZrlbSVzZ0x9pLljycelL3x83ydw6PsWG3PNyqCLoRn1F9zH/ObTDkSrHRXK1NAD4fCMMU1Zn+4RPyG64NX4VpmcP7Fzw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047231; c=relaxed/simple; bh=OVj9Ib21dXimZLr1073/sKR4D7bcHA8iGi2AcUi8iiQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=t56F4obRhwi24IP2JxWdrPsnZR9AHzvvJRDAJmyLTQ4wqDqLR9t4c9Nzu3eF5eDhGwmnb1zCU7sOtF+ka5x4NDy/MBM1DameJibPisFE6e2g1fnbPzD0oYtyHKCqTAW6lOUq0HKqQMSbxE4159RLdD4paHhyrF7j6Z5eHOZpYE4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=NNPe+AFf; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="NNPe+AFf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047228; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nPKTO/lkAm23+jGXrw/+m68oGTpukXV85p9697O5xzI=; b=NNPe+AFfLwz+9OpN/9t3iNsc72qWPzohQROAmMMCbtKasfSYArfBsrRFNDv8u/mpLGnQfu Kt8jqiX61xne3ltV5kiGdwVu7joZjmV3nS9MaEsKfpTAeSK+5y5VUrjditAnzwA6xfOyYK mEOEksXtewEGYCSusCxDDibFKN9jBn8= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-84-J8Mg4pjHMaWQLk82l9cgyw-1; Mon, 07 Apr 2025 13:33:44 -0400 X-MC-Unique: J8Mg4pjHMaWQLk82l9cgyw-1 X-Mimecast-MFC-AGG-ID: J8Mg4pjHMaWQLk82l9cgyw_1744047219 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A0F851801A07; Mon, 7 Apr 2025 17:33:39 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4C524180B488; Mon, 7 Apr 2025 17:33:33 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 25/28] dpll: zl3073x: Add support to get phase offset on input pins Date: Mon, 7 Apr 2025 19:32:58 +0200 Message-ID: <20250407173301.1010462-6-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This adds support to get phase offset for the input pins. Implement the appropriate callback that performs DPLL to reference phase error measurement and reports the measured value. If the DPLL is currently locked to different reference with higher frequency then the phase offset is modded to the period of the signal the DPLL is locked to. Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 156 +++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index c920904008e22..3b28d229dd4be 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -36,6 +36,15 @@ ZL3073X_REG8_IDX_DEF(dpll_refsel_status, 0x130, ZL3073X_NUM_CHANNELS, 1); #define DPLL_REFSEL_STATUS_STATE_ACQUIRING 3 #define DPLL_REFSEL_STATUS_STATE_LOCK 4 +/* + * Register Map Page 4, Ref + */ +ZL3073X_REG8_DEF(ref_phase_err_read_rqst, 0x20f); +#define REF_PHASE_ERR_READ_RQST_RD BIT(0) + +ZL3073X_REG48_IDX_DEF(ref_phase, 0x220, + ZL3073X_NUM_INPUT_PINS, 6); + /* * Register Map Page 5, DPLL */ @@ -48,6 +57,13 @@ ZL3073X_REG8_IDX_DEF(dpll_mode_refsel, 0x284, ZL3073X_NUM_CHANNELS, 4); #define DPLL_MODE_REFSEL_MODE_NCO 4 #define DPLL_MODE_REFSEL_REF GENMASK(7, 4) +ZL3073X_REG8_DEF(dpll_meas_ctrl, 0x2d0); +#define DPLL_MEAS_CTRL_EN BIT(0) +#define DPLL_MEAS_CTRL_AVG_FACTOR GENMASK(7, 4) + +ZL3073X_REG8_DEF(dpll_meas_idx, 0x2d1); +#define DPLL_MEAS_IDX_IDX GENMASK(2, 0) + /* * Register Map Page 9, Synth and Output */ @@ -104,6 +120,7 @@ struct zl3073x_dpll_pin_info { * @prio: pin priority <0, 14> * @selectable: pin is selectable in automatic mode * @pin_state: last saved pin state + * @phase_offset: last saved pin phase offset */ struct zl3073x_dpll_pin { struct dpll_pin *dpll_pin; @@ -111,6 +128,7 @@ struct zl3073x_dpll_pin { u8 prio; bool selectable; enum dpll_pin_state pin_state; + s64 phase_offset; }; /** @@ -558,6 +576,120 @@ zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) * * Returns 0 in case of success or negative value otherwise. */ +static int +zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, s64 *phase_offset, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 dpll_meas_ctrl, dpll_meas_idx; + u8 conn_ref, ref_id, ref_status; + s64 ref_phase; + int rc; + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Wait for reading to be ready */ + rc = zl3073x_wait_clear_bits(zldev, ref_phase_err_read_rqst, + REF_PHASE_ERR_READ_RQST_RD); + if (rc) + return rc; + + /* Read measurement control register */ + rc = zl3073x_read_dpll_meas_ctrl(zldev, &dpll_meas_ctrl); + if (rc) + return rc; + + /* Enable measurement */ + dpll_meas_ctrl |= DPLL_MEAS_CTRL_EN; + + /* Update measurement control register with new values */ + rc = zl3073x_write_dpll_meas_ctrl(zldev, dpll_meas_ctrl); + if (rc) + return rc; + + /* Set measurement index to channel index */ + dpll_meas_idx = FIELD_PREP(DPLL_MEAS_IDX_IDX, zldpll->id); + rc = zl3073x_write_dpll_meas_idx(zldev, dpll_meas_idx); + if (rc) + return rc; + + /* Request read of the current phase error measurements */ + rc = zl3073x_write_ref_phase_err_read_rqst(zldev, + REF_PHASE_ERR_READ_RQST_RD); + if (rc) + return rc; + + /* Wait for confirmation from the device */ + rc = zl3073x_wait_clear_bits(zldev, ref_phase_err_read_rqst, + REF_PHASE_ERR_READ_RQST_RD); + if (rc) + return rc; + + /* Read DPLL-to-REF phase measurement */ + rc = zl3073x_read_ref_phase(zldev, ref_id, &ref_phase); + if (rc) + return rc; + + /* Perform sign extension for 48bit signed value */ + ref_phase = sign_extend64(ref_phase, 47); + + /* Register units are 0.01 ps -> convert it to ps */ + ref_phase = div_s64(ref_phase, 100); + + /* Get currently connected reference */ + rc = zl3073x_dpll_connected_ref_get(zldpll, &conn_ref); + if (rc) + return rc; + + /* Get this pin monitor status */ + rc = zl3073x_read_ref_mon_status(zldev, ref_id, &ref_status); + if (rc) + return rc; + + /* The DPLL being locked to a higher freq than the current ref + * the phase offset is modded to the period of the signal + * the dpll is locked to. + */ + if (ZL3073X_REF_IS_VALID(conn_ref) && conn_ref != ref_id && + ref_status == REF_MON_STATUS_OK) { + u64 conn_freq, ref_freq; + + /* Get frequency of connected ref */ + rc = zl3073x_dpll_input_ref_frequency_get(zldev, conn_ref, + &conn_freq); + if (rc) + return rc; + + /* Get frequency of given ref */ + rc = zl3073x_dpll_input_ref_frequency_get(zldev, ref_id, + &ref_freq); + if (rc) + return rc; + + if (conn_freq > ref_freq) { + s64 conn_period; + int div_factor; + + conn_period = (s64)div_u64(PSEC_PER_SEC, conn_freq); + div_factor = div64_s64(ref_phase, conn_period); + ref_phase -= conn_period * div_factor; + } + } + + *phase_offset = ref_phase; + + return rc; +} + static int zl3073x_dpll_ref_prio_get(struct zl3073x_dpll_pin *pin, u8 *prio) { @@ -1110,6 +1242,7 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, .frequency_get = zl3073x_dpll_input_pin_frequency_get, .frequency_set = zl3073x_dpll_input_pin_frequency_set, + .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get, .prio_get = zl3073x_dpll_input_pin_prio_get, .prio_set = zl3073x_dpll_input_pin_prio_set, .state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get, @@ -1805,6 +1938,8 @@ zl3073x_dpll_periodic_work(struct kthread_work *work) for (i = 0; i < ZL3073X_NUM_INPUT_PINS; i++) { struct zl3073x_dpll_pin *pin; enum dpll_pin_state state; + s64 phase_offset; + bool pin_changed; /* Input pins starts are stored after output pins */ pin = &zldpll->pins[ZL3073X_NUM_OUTPUT_PINS + i]; @@ -1821,13 +1956,32 @@ zl3073x_dpll_periodic_work(struct kthread_work *work) if (rc) goto out; + rc = zl3073x_dpll_input_pin_phase_offset_get(pin->dpll_pin, + pin, + zldpll->dpll_dev, + zldpll, + &phase_offset, + NULL); + if (rc) + goto out; + if (state != pin->pin_state) { dev_dbg(zldev->dev, "INPUT%u state changed to %u\n", zl3073x_dpll_pin_index_get(pin), state); pin->pin_state = state; - dpll_pin_change_ntf(pin->dpll_pin); + pin_changed = true; } + if (phase_offset != pin->phase_offset) { + dev_dbg(zldev->dev, + "INPUT%u phase offset changed to %llu\n", + pin->index, phase_offset); + pin->phase_offset = phase_offset; + pin_changed = true; + } + + if (pin_changed) + dpll_pin_change_ntf(pin->dpll_pin); } out: From patchwork Mon Apr 7 17:32:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041432 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB8E92550D2 for ; Mon, 7 Apr 2025 17:33:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047234; cv=none; b=c9COc7xxd82+Q594Gv5RDFNEpdadU4WMXfAH37F20GotPOo19VBpUCTmo2ItEM8Q9dXqwpHKN6bD8VWOeV+E6Lhpvh+w9/+I3wHaSOa+g9LTJq5GeijlYStwtRtbOvnbKcl0A4qQQz1FnZnGt/HfIkZWzab0CrHtN88HD9c3VKs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047234; c=relaxed/simple; bh=5U093kAY3hoxDsZMSwlw+0r/goDrQdnI3Vv4TryWwjs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g10g8MSzAEM+FwqOVfxHDrtqY2ZdX8OFzrT1js/9VDImJdCs4ONzVHOH2an4fmaR6OHhyTrh/CkAzyFBf2UPOpYVoIhG1ujpChRlitkUH0VStxVZPfMtYTHDohBGUCtIz5f7BNZkYKZkEaYnRGIehqr72L7Ppv0fKp2pshTZbxM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=C/TM5uis; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="C/TM5uis" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047232; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FwU+hrjd2qkJ6gHJBxOGGNS7xPX2aUI8bJ62fHCyzOw=; b=C/TM5uisnQBw3cHC0vzyirMjGxynQ0OxVvK7Iff0mToBxt4e6qn4ktG9PlT3XqeYuk1Avh jGX9mX4Pdd81QJINhZ6nmXi67WlWEqrjs397FjwVVMO5V+4NNDkZorb228wnMTwYtCq0tU V1/W7xVzIdP70thySGN++qY319+HSns= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-570-c_A4qxucOme73u5Ag1nZcg-1; Mon, 07 Apr 2025 13:33:48 -0400 X-MC-Unique: c_A4qxucOme73u5Ag1nZcg-1 X-Mimecast-MFC-AGG-ID: c_A4qxucOme73u5Ag1nZcg_1744047225 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B3279180025B; Mon, 7 Apr 2025 17:33:45 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2DA0D1828A80; Mon, 7 Apr 2025 17:33:39 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 26/28] dpll: zl3073x: Add support to get/set phase adjust on pins Date: Mon, 7 Apr 2025 19:32:59 +0200 Message-ID: <20250407173301.1010462-7-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This adds support to get/set phase adjustment for both input and output pins. The phase adjustment is implemented using reference and output phase offset compensation registers. For input pins the adjustment value can be arbitrary number but for outputs the value has to be a multiple of half synthesizer clock cycles. Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 182 ++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index 3b28d229dd4be..b1f38f000899b 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -79,6 +79,7 @@ ZL3073X_REG16_DEF(ref_freq_base, 0x505); ZL3073X_REG16_DEF(ref_freq_mult, 0x507); ZL3073X_REG16_DEF(ref_ratio_m, 0x509); ZL3073X_REG16_DEF(ref_ratio_n, 0x50b); +ZL3073X_REG48_DEF(ref_phase_compensation, 0x528); /* * Register Map Page 12, DPLL Mailbox @@ -98,6 +99,8 @@ ZL3073X_REG32_DEF(output_width, 0x710); ZL3073X_REG32_DEF(output_ndiv_period, 0x714); ZL3073X_REG32_DEF(output_ndiv_width, 0x718); +ZL3073X_REG32_DEF(output_phase_compensation, 0x720); + #define ZL3073X_REF_NONE ZL3073X_NUM_INPUT_PINS #define ZL3073X_REF_IS_VALID(_ref) ((_ref) != ZL3073X_REF_NONE) @@ -690,6 +693,85 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin, return rc; } +static int +zl3073x_dpll_input_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + s32 *phase_adjust, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + s64 phase_comp; + u8 ref_id; + int rc; + + guard(zl3073x)(zldev); + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Read reference configuration into mailbox */ + rc = zl3073x_mb_ref_read(zldev, ref_id); + if (rc) + return rc; + + /* Read current phase offset compensation */ + rc = zl3073x_read_ref_phase_compensation(zldev, &phase_comp); + if (rc) + return rc; + + /* Perform sign extension for 48bit signed value */ + phase_comp = sign_extend64(phase_comp, 47); + + /* Reverse two's complement negation applied during set and convert + * to 32bit signed int + */ + *phase_adjust = (s32) -phase_comp; + + return rc; +} + +static int +zl3073x_dpll_input_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + s32 phase_adjust, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + s64 phase_comp; + u8 ref_id; + int rc; + + guard(zl3073x)(zldev); + + /* The value in the register is stored as two's complement negation + * of requested value. + */ + phase_comp = (s64) -phase_adjust; + + /* Write the requested value into the compensation register */ + rc = zl3073x_write_ref_phase_compensation(zldev, phase_comp); + if (rc) + return rc; + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Update reference configuration from mailbox */ + rc = zl3073x_mb_ref_write(zldev, ref_id); + if (rc) + return rc; + + return rc; +} + static int zl3073x_dpll_ref_prio_get(struct zl3073x_dpll_pin *pin, u8 *prio) { @@ -1165,6 +1247,102 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin, return zl3073x_mb_output_write(zldev, output); } +static int +zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + s32 *phase_adjust, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 output, synth; + u64 synth_freq; + s32 phase_comp; + int rc; + + guard(zl3073x)(zldev); + + output = zl3073x_dpll_output_pin_output_get(pin); + synth = zl3073x_dpll_pin_synth_get(pin); + synth_freq = zl3073x_synth_freq_get(zldev, synth); + + /* Read output configuration into mailbox */ + rc = zl3073x_mb_output_read(zldev, output); + if (rc) + return rc; + + /* Read current output phase compensation */ + rc = zl3073x_read_output_phase_compensation(zldev, &phase_comp); + if (rc) + return rc; + + /* Value in register is expressed in half synth clock cycles */ + phase_comp *= (int)div_u64(PSEC_PER_SEC, 2 * synth_freq); + + /* Reverse two's complement negation applied during 'set' */ + *phase_adjust = -phase_comp; + + return rc; +} + +static int +zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + s32 phase_adjust, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + int half_synth_cycle; + u8 output, synth; + u64 synth_freq; + int phase_comp; + int rc; + + /* Get attached synth */ + synth = zl3073x_dpll_pin_synth_get(pin); + + /* Get synth's frequency */ + synth_freq = zl3073x_synth_freq_get(zldev, synth); + + /* Value in register is expressed in half synth clock cycles so + * the given phase adjustment a multiple of half synth clock. + */ + half_synth_cycle = (int)div_u64(PSEC_PER_SEC, 2 * synth_freq); + + if ((phase_adjust % half_synth_cycle) != 0) { + NL_SET_ERR_MSG_FMT(extack, + "Phase adjustment value has to be multiple of %d", + half_synth_cycle); + return -EINVAL; + } + phase_adjust /= half_synth_cycle; + + guard(zl3073x)(zldev); + + /* The value in the register is stored as two's complement negation + * of requested value. + */ + phase_comp = -phase_adjust; + + /* Write the requested value into the compensation register */ + rc = zl3073x_write_output_phase_compensation(zldev, phase_comp); + if (rc) + return rc; + + /* Update output configuration from mailbox */ + output = zl3073x_dpll_output_pin_output_get(pin); + rc = zl3073x_mb_output_write(zldev, output); + + return rc; +} + static int zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -1243,6 +1421,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .frequency_get = zl3073x_dpll_input_pin_frequency_get, .frequency_set = zl3073x_dpll_input_pin_frequency_set, .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get, + .phase_adjust_get = zl3073x_dpll_input_pin_phase_adjust_get, + .phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set, .prio_get = zl3073x_dpll_input_pin_prio_get, .prio_set = zl3073x_dpll_input_pin_prio_set, .state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get, @@ -1253,6 +1433,8 @@ static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, .frequency_get = zl3073x_dpll_output_pin_frequency_get, .frequency_set = zl3073x_dpll_output_pin_frequency_set, + .phase_adjust_get = zl3073x_dpll_output_pin_phase_adjust_get, + .phase_adjust_set = zl3073x_dpll_output_pin_phase_adjust_set, .state_on_dpll_get = zl3073x_dpll_output_pin_state_on_dpll_get, }; From patchwork Mon Apr 7 17:33:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041433 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5D9ED255229 for ; Mon, 7 Apr 2025 17:33:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047241; cv=none; b=mQtORf9EgWHXTnspVJ2wGeZsm2nu6Mo1j0Ka3wFiUnQ7OywJTLlrAoQ2abANeoz69wPTk8FBoQGpQt4VQKURIH+UQYIyeqtO6DoXQeWck21iCbVLorDTf4uOFGLem2VyafEGnM5Cyd6qCtDjKAYRYBrgQdU/B12p026sqnwt7a4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047241; c=relaxed/simple; bh=yLTHJ05ygRIZZ5iwUiKUKh0Cm43hl1zFVEBf723h+S4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iIpAG7G9v2UKlawpIfbLZBdsjn4XYUqRXGJl+Vb7rrcUOR92xfzoLWqoGu0Q+Yn1236rW1lZiE0YFe8+jin7QfuZl1Ek74w471AoEE4r6pHioE4vpRmv0IDu7SWLE2+N7Prrufg1iqiERpEOzQEheBa74y/U9TzOy441ZkBgW2s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ICzYlwAJ; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ICzYlwAJ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047238; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=palQv57hQTCne25I0QNHI4EgnBuV8W5p0oe7j/ULdJ4=; b=ICzYlwAJrQWqTiN9Lj8JWgeNRXXUwFHiPyMTKk8Qm7rAmgX9jk8xKvtbPAF2MZc4Smroyz tFgXTAWSRjReDIcpw5FOo+ajxNdv+q0VM3VtS6Pg7mjzB6ezdHVY5zkm7ZhvkbZsx8Ldg+ Zvb5t13v+xzRtQzOWTmxnmdAldg4hnc= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-261-9rKRSkUjP-C4FuEln5yjVQ-1; Mon, 07 Apr 2025 13:33:54 -0400 X-MC-Unique: 9rKRSkUjP-C4FuEln5yjVQ-1 X-Mimecast-MFC-AGG-ID: 9rKRSkUjP-C4FuEln5yjVQ_1744047231 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B642B1800267; Mon, 7 Apr 2025 17:33:51 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4743F180B488; Mon, 7 Apr 2025 17:33:45 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 27/28] dpll: zl3073x: Add support to get/set esync on pins Date: Mon, 7 Apr 2025 19:33:00 +0200 Message-ID: <20250407173301.1010462-8-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This adds support to get/set embedded sync for both input and output pins. The DPLL is able to lock on input reference when the embedded sync frequency is 1 PPS and pulse width 25%. The esync on outputs are more versatille and theoretically supports any esync frequency that divides current output frequency but for now support the same that supported on input pins (1 PPS & 25% pulse). Note that for the output pins the esync divisor shares the same register used for N-divided signal formats. Due to this the esync cannot be enabled on outputs configured with one of the N-divided signal formats. Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 370 +++++++++++++++++++++++++++++++++++- 1 file changed, 368 insertions(+), 2 deletions(-) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index b1f38f000899b..e1d7f6d4c3d57 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -81,6 +81,14 @@ ZL3073X_REG16_DEF(ref_ratio_m, 0x509); ZL3073X_REG16_DEF(ref_ratio_n, 0x50b); ZL3073X_REG48_DEF(ref_phase_compensation, 0x528); +ZL3073X_REG8_DEF(ref_sync_ctrl, 0x52e); +#define REF_SYNC_CTRL_MODE GENMASK(2, 0) +#define REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0 +#define REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75 2 + +ZL3073X_REG32_DEF(ref_esync_div, 0x530); +#define REF_ESYNC_DIV_1HZ 0 + /* * Register Map Page 12, DPLL Mailbox */ @@ -94,10 +102,17 @@ ZL3073X_REG8_IDX_DEF(dpll_ref_prio, 0x652, /* * Register Map Page 14, Output Mailbox */ +ZL3073X_REG8_DEF(output_mode, 0x705); +#define OUTPUT_MODE_CLOCK_TYPE GENMASK(2, 0) +#define OUTPUT_MODE_CLOCK_TYPE_NORMAL 0 +#define OUTPUT_MODE_CLOCK_TYPE_ESYNC 1 + ZL3073X_REG32_DEF(output_div, 0x70c); ZL3073X_REG32_DEF(output_width, 0x710); -ZL3073X_REG32_DEF(output_ndiv_period, 0x714); -ZL3073X_REG32_DEF(output_ndiv_width, 0x718); +ZL3073X_REG32_DEF(output_esync_period, 0x714); +ZL3073X_REG32_DEF(output_ndiv_period, 0x714); /* alias for previous */ +ZL3073X_REG32_DEF(output_esync_width, 0x718); +ZL3073X_REG32_DEF(output_ndiv_width, 0x718); /* alias for previous */ ZL3073X_REG32_DEF(output_phase_compensation, 0x720); @@ -122,6 +137,7 @@ struct zl3073x_dpll_pin_info { * @index: index in zl3073x_dpll.pins array * @prio: pin priority <0, 14> * @selectable: pin is selectable in automatic mode + * @esync_control: embedded sync is controllable * @pin_state: last saved pin state * @phase_offset: last saved pin phase offset */ @@ -130,6 +146,7 @@ struct zl3073x_dpll_pin { u8 index; u8 prio; bool selectable; + bool esync_control; enum dpll_pin_state pin_state; s64 phase_offset; }; @@ -213,6 +230,13 @@ zl3073x_dpll_is_n_pin(struct zl3073x_dpll_pin *pin) return zl3073x_is_n_pin(zl3073x_dpll_pin_index_get(pin)); } +/* + * Supported esync ranges for input and for output per output pair type + */ +static const struct dpll_pin_frequency esync_freq_ranges[] = { + DPLL_PIN_FREQUENCY_RANGE(0, 1), +}; + /** * zl3073x_dpll_is_p_pin - check if the pin is P-pin * @pin: pin to check @@ -352,6 +376,128 @@ zl3073x_dpll_input_ref_frequency_get(struct zl3073x_dev *zldev, u8 ref_id, return rc; } +static int +zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + struct dpll_pin_esync *esync, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 sync_mode, ref_id, ref_sync_ctrl; + u32 esync_div; + u64 ref_freq; + int rc; + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Get reference frequency */ + rc = zl3073x_dpll_input_ref_frequency_get(zldev, ref_id, &ref_freq); + if (rc) + return rc; + + /* Get ref sync mode */ + rc = zl3073x_read_ref_sync_ctrl(zldev, &ref_sync_ctrl); + if (rc) + return rc; + + sync_mode = FIELD_GET(REF_SYNC_CTRL_MODE, ref_sync_ctrl); + + /* Get esync divisor */ + rc = zl3073x_read_ref_esync_div(zldev, &esync_div); + if (rc) + return rc; + + switch (sync_mode) { + case REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75: + esync->freq = (esync_div == REF_ESYNC_DIV_1HZ) ? 1 : 0; + esync->pulse = 25; + break; + default: + esync->freq = 0; + esync->pulse = 50; + break; + } + + /* If the pin supports esync control expose its range but only + * if the current reference frequency is > 1 Hz. + */ + if (pin->esync_control && ref_freq > 1) { + esync->range = esync_freq_ranges; + esync->range_num = ARRAY_SIZE(esync_freq_ranges); + } else { + esync->range = NULL; + esync->range_num = 0; + } + + return rc; +} + +static int +zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 freq, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 ref_id, ref_sync_ctrl, sync_mode; + int rc; + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Read reference configuration into mailbox */ + rc = zl3073x_mb_ref_read(zldev, ref_id); + if (rc) + return rc; + + /* Read ref sync control */ + rc = zl3073x_read_ref_sync_ctrl(zldev, &ref_sync_ctrl); + if (rc) + return rc; + + /* Use freq == 0 to disable esync */ + if (!freq) + sync_mode = REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF; + else + sync_mode = REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75; + + ref_sync_ctrl &= REF_SYNC_CTRL_MODE; + ref_sync_ctrl |= FIELD_PREP(REF_SYNC_CTRL_MODE, sync_mode); + + /* Update ref sync control register */ + rc = zl3073x_write_ref_sync_ctrl(zldev, ref_sync_ctrl); + if (rc) + return rc; + + if (freq) { + /* 1 Hz is only supported frequnecy currently */ + rc = zl3073x_write_ref_esync_div(zldev, REF_ESYNC_DIV_1HZ); + if (rc) + return rc; + } + + /* Update reference configuration from mailbox */ + rc = zl3073x_mb_ref_write(zldev, ref_id); + if (rc) + return rc; + + return rc; +} + static int zl3073x_dpll_input_pin_frequency_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -1017,6 +1163,218 @@ zl3073x_dpll_pin_synth_get(struct zl3073x_dpll_pin *pin) return zl3073x_output_synth_get(pin_to_dev(pin), output); } +static int +zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + struct dpll_pin_esync *esync, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u32 esync_period, esync_width, output_div; + u8 clock_type, output, output_mode, synth; + u64 synth_freq; + int rc; + + output = zl3073x_dpll_output_pin_output_get(pin); + + /* If N-division is enabled, esync is not supported. The register used + * for N-division is also used for the esync divider so both cannot + * be used. + */ + switch (zl3073x_output_signal_format_get(zldev, output)) { + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV: + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV: + return -EOPNOTSUPP; + default: + break; + } + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Read output configuration into mailbox */ + rc = zl3073x_mb_output_read(zldev, output); + if (rc) + return rc; + + /* Read output mode */ + rc = zl3073x_read_output_mode(zldev, &output_mode); + if (rc) + return rc; + + /* Read output divisor */ + rc = zl3073x_read_output_div(zldev, &output_div); + if (rc) + return rc; + + /* Check output divisor for zero */ + if (!output_div) { + dev_err(zldev->dev, + "Zero divisor for OUTPUT%u got from device\n", + output); + return -EINVAL; + } + + /* Get synth attached to output pin */ + synth = zl3073x_dpll_pin_synth_get(pin); + + /* Get synth frequency */ + synth_freq = zl3073x_synth_freq_get(zldev, synth); + + clock_type = FIELD_GET(OUTPUT_MODE_CLOCK_TYPE, output_mode); + if (clock_type != OUTPUT_MODE_CLOCK_TYPE_ESYNC) { + /* No need to read esync data if it is not enabled */ + esync->freq = 0; + esync->pulse = 50; + + goto finish; + } + + /* Read esync period */ + rc = zl3073x_read_output_esync_period(zldev, &esync_period); + if (rc) + return rc; + + /* Check esync divisor for zero */ + if (!esync_period) { + dev_err(zldev->dev, + "Zero esync divisor for OUTPUT%u got from device\n", + output); + return -EINVAL; + } + + /* Get esync pulse width in units of half synth cycles */ + rc = zl3073x_read_output_esync_width(zldev, &esync_width); + if (rc) + return rc; + + /* Compute esync frequency: + * esync_freq = synth_freq / output_div / esync_period; + * ... = synth_freq / (output_div * esync_period); + */ + esync->freq = div64_u64(synth_freq, + mul_u32_u32(output_div, esync_period)); + + /* By comparing the esync_pulse_width to the half of the pulse width + * the esync pulse percentage can be determined. + * Note that half pulse width is in units of half synth cycles, which + * is why it reduces down to be output_div. + */ + esync->pulse = (50 * esync_width) / output_div; + +finish: + /* Set supported esync ranges if the pin supports esync control and + * if the output frequency is > 1 Hz. + */ + if (pin->esync_control && div_u64(synth_freq, output_div) > 1) { + esync->range = esync_freq_ranges; + esync->range_num = ARRAY_SIZE(esync_freq_ranges); + } else { + esync->range = NULL; + esync->range_num = 0; + } + + return 0; +} + +static int +zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 freq, + struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u32 esync_period, esync_width, output_div; + u8 clock_type, output, output_mode, synth; + u64 synth_freq; + int rc; + + output = zl3073x_dpll_output_pin_output_get(pin); + + /* If N-division is enabled, esync is not supported. The register used + * for N-division is also used for the esync divider so both cannot + * be used. + */ + switch (zl3073x_output_signal_format_get(zldev, output)) { + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV: + case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV: + return -EOPNOTSUPP; + default: + break; + } + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Read output configuration into mailbox */ + rc = zl3073x_mb_output_read(zldev, output); + if (rc) + return rc; + + /* Read output mode */ + rc = zl3073x_read_output_mode(zldev, &output_mode); + if (rc) + return rc; + + /* Select clock type */ + if (freq) + clock_type = OUTPUT_MODE_CLOCK_TYPE_ESYNC; + else + clock_type = OUTPUT_MODE_CLOCK_TYPE_NORMAL; + + /* Update clock type in ref sync control */ + output_mode &= ~OUTPUT_MODE_CLOCK_TYPE; + output_mode |= FIELD_PREP(OUTPUT_MODE_CLOCK_TYPE, clock_type); + rc = zl3073x_write_output_mode(zldev, output_mode); + if (rc) + return rc; + + /* If esync is being disabled just write mailbox and finish */ + if (!freq) + goto write_mailbox; + + /* Read output divisor */ + rc = zl3073x_read_output_div(zldev, &output_div); + if (rc) + return rc; + + /* Get synth attached to output pin */ + synth = zl3073x_dpll_pin_synth_get(pin); + + /* Get synth frequency */ + synth_freq = zl3073x_synth_freq_get(zldev, synth); + + /* Compute and update esync period */ + esync_period = (u32)div64_u64(synth_freq, freq * output_div); + rc = zl3073x_write_output_esync_period(zldev, esync_period); + if (rc) + return rc; + + /* Half of the period in units of 1/2 synth cycle can be represented by + * the output_div. To get the supported esync pulse width of 25% of the + * period the output_div can just be divided by 2. Note that this + * assumes that output_div is even, otherwise some resolution will be + * lost. + */ + esync_width = output_div / 2; + rc = zl3073x_write_output_esync_width(zldev, esync_width); + if (rc) + return rc; + +write_mailbox: + /* Update output configuration from mailbox */ + rc = zl3073x_mb_output_write(zldev, output); + + return rc; +} + static int zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -1418,6 +1776,8 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, + .esync_get = zl3073x_dpll_input_pin_esync_get, + .esync_set = zl3073x_dpll_input_pin_esync_set, .frequency_get = zl3073x_dpll_input_pin_frequency_get, .frequency_set = zl3073x_dpll_input_pin_frequency_set, .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get, @@ -1431,6 +1791,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, + .esync_get = zl3073x_dpll_output_pin_esync_get, + .esync_set = zl3073x_dpll_output_pin_esync_set, .frequency_get = zl3073x_dpll_output_pin_frequency_get, .frequency_set = zl3073x_dpll_output_pin_frequency_set, .phase_adjust_get = zl3073x_dpll_output_pin_phase_adjust_get, @@ -1678,6 +2040,10 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin) pin_type); } + /* Check if the pin supports embedded sync control */ + pin->esync_control = fwnode_property_read_bool(pin_info->fwnode, + "esync-control"); + /* Read supported frequencies property if it is specified */ num_freqs = fwnode_property_count_u64(pin_info->fwnode, "supported-frequencies"); From patchwork Mon Apr 7 17:33:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Vecera X-Patchwork-Id: 14041434 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE1F322154D for ; Mon, 7 Apr 2025 17:34:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047245; cv=none; b=Z6zB1Z1XIAo9T9ZteHTKrglWT1qPvgi755jI3uGVfza3bqgcULZb14bjvDUQYuLwTrPDQKJADF/pBfLJgV4o7KM2sUb9kvTad/IGb6uxhzIzmxoVxXJjRUd3L3ie7O2OnXbVUxc4jUvmZgeoqZ6hC4G+6giTLW5I0UkF2JFb10Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744047245; c=relaxed/simple; bh=0eoyesuUJ7nZXFehU0rjs/Slq1sdsdIs1Ek+4VMektQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Vuk3R3EDQpHWuAgZOZ8hiaVsPAaw+7L6f4uvjU9lwAa9YhidZDLrC1rXIK8rrUXiFLgFfM6uhpdPNaIfeoHw7RBg9E5rNDtYFNK79NS/eacrcXu74/HzhDUkbsr/x1dPj0Rieptuty8hMDS9ArxzTkq+CDdFDfBpMq5h0CS2HIU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=L7pU01Im; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="L7pU01Im" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744047242; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ixTjOYCWUZvSMYGAAMcSYpU49kgLEmCLWZmPx1x/04U=; b=L7pU01ImdFPuzFribJHFNllwuKFPcce9G5g48MCLEHnCV4BeQZuMCEVMVZ7RjxmxP84Xyk TPjcx5sJ93o6vEKCvNXzrP1C5ovCbxlCtWC7eqO4cwgWx8qiC6LeLYrGWO6OtGoqLxUHhk SMINw3ZxpBNYprkr5i2FK3/9yJ7lFhs= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-591-aWG3WrrmMMebsZvXhkGbgg-1; Mon, 07 Apr 2025 13:33:59 -0400 X-MC-Unique: aWG3WrrmMMebsZvXhkGbgg-1 X-Mimecast-MFC-AGG-ID: aWG3WrrmMMebsZvXhkGbgg_1744047237 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7388018001F8; Mon, 7 Apr 2025 17:33:57 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.44.32.4]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 51F9F180B488; Mon, 7 Apr 2025 17:33:52 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Michal Schmidt , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Kees Cook , Andy Shevchenko , Andrew Morton , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH 28/28] dpll: zl3073x: Add support to get fractional frequency offset on input pins Date: Mon, 7 Apr 2025 19:33:01 +0200 Message-ID: <20250407173301.1010462-9-ivecera@redhat.com> In-Reply-To: <20250407172836.1009461-1-ivecera@redhat.com> References: <20250407172836.1009461-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-hardening@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 This adds support to get fractional frequency offset for input pins. Implement the appropriate callback that performs reference frequency measurement and reports the frequency offset between the DPLL and the reference. Reviewed-by: Michal Schmidt Co-developed-by: Prathosh Satish Signed-off-by: Prathosh Satish Signed-off-by: Ivan Vecera --- drivers/dpll/dpll_zl3073x.c | 110 +++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c index e1d7f6d4c3d57..f5a58c3bab382 100644 --- a/drivers/dpll/dpll_zl3073x.c +++ b/drivers/dpll/dpll_zl3073x.c @@ -36,12 +36,31 @@ ZL3073X_REG8_IDX_DEF(dpll_refsel_status, 0x130, ZL3073X_NUM_CHANNELS, 1); #define DPLL_REFSEL_STATUS_STATE_ACQUIRING 3 #define DPLL_REFSEL_STATUS_STATE_LOCK 4 +ZL3073X_REG32_IDX_DEF(ref_freq, 0x144, + ZL3073X_NUM_INPUT_PINS, 4); + /* * Register Map Page 4, Ref */ ZL3073X_REG8_DEF(ref_phase_err_read_rqst, 0x20f); #define REF_PHASE_ERR_READ_RQST_RD BIT(0) +ZL3073X_REG8_DEF(ref_freq_meas_ctrl, 0x21c); +#define REF_FREQ_MEAS_CTRL_LATCH GENMASK(1, 0) +#define REF_FREQ_MEAS_CTRL_LATCH_REF_FREQ 1 +#define REF_FREQ_MEAS_CTRL_LATCH_REF_FREQ_OFF 2 +#define REF_FREQ_MEAS_CTRL_LATCH_DPLL_FREQ_OFF 3 + +ZL3073X_REG8_DEF(ref_freq_meas_mask_3_0, 0x21d); +#define REF_FREQ_MEAS_MASK_3_0(_ref) BIT(_ref) + +ZL3073X_REG8_DEF(ref_freq_meas_mask_4, 0x21e); +#define REF_FREQ_MEAS_MASK_4(_ref) BIT((_ref) - 8) + +ZL3073X_REG8_DEF(dpll_meas_ref_freq_ctrl, 0x21f); +#define DPLL_MEAS_REF_FREQ_CTRL_EN BIT(0) +#define DPLL_MEAS_REF_FREQ_CTRL_IDX GENMASK(6, 4) + ZL3073X_REG48_IDX_DEF(ref_phase, 0x220, ZL3073X_NUM_INPUT_PINS, 6); @@ -140,6 +159,7 @@ struct zl3073x_dpll_pin_info { * @esync_control: embedded sync is controllable * @pin_state: last saved pin state * @phase_offset: last saved pin phase offset + * @freq_offset: last saved fractional frequency offset */ struct zl3073x_dpll_pin { struct dpll_pin *dpll_pin; @@ -149,6 +169,7 @@ struct zl3073x_dpll_pin { bool esync_control; enum dpll_pin_state pin_state; s64 phase_offset; + s64 freq_offset; }; /** @@ -498,6 +519,79 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin, return rc; } +static int +zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + s64 *ffo, struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->mfd; + struct zl3073x_dpll_pin *pin = pin_priv; + u8 dpll_meas_ref_freq_ctrl, ref_id; + u8 ref_freq_meas_ctrl, ref_mask; + s32 freq_offset; + int rc; + + /* Take device lock */ + guard(zl3073x)(zldev); + + /* Get index of the pin */ + ref_id = zl3073x_dpll_pin_index_get(pin); + + /* Wait for being ready */ + rc = zl3073x_wait_clear_bits(zldev, ref_freq_meas_ctrl, + REF_FREQ_MEAS_CTRL_LATCH); + if (rc) + return rc; + + /* Select channel index in the mask and enable freq measurement */ + dpll_meas_ref_freq_ctrl = + DPLL_MEAS_REF_FREQ_CTRL_EN | + FIELD_PREP(DPLL_MEAS_REF_FREQ_CTRL_IDX, zldpll->id); + + rc = zl3073x_write_dpll_meas_ref_freq_ctrl(zldev, + dpll_meas_ref_freq_ctrl); + if (rc) + return rc; + + /* Set reference mask + * REF0P,REF0N..REF3P,REF3N are set in ref_freq_meas_mask_3_0 register + * REF4P and REF4N are set in ref_freq_meas_mask_4 register + */ + if (ref_id < 8) { + ref_mask = REF_FREQ_MEAS_MASK_3_0(ref_id); + rc = zl3073x_write_ref_freq_meas_mask_3_0(zldev, ref_mask); + } else { + ref_mask = REF_FREQ_MEAS_MASK_4(ref_id); + rc = zl3073x_write_ref_freq_meas_mask_4(zldev, ref_mask); + } + if (rc) + return rc; + + /* Request a reading of the frequency offset between the DPLL and + * the reference + */ + ref_freq_meas_ctrl = REF_FREQ_MEAS_CTRL_LATCH_DPLL_FREQ_OFF; + rc = zl3073x_write_ref_freq_meas_ctrl(zldev, ref_freq_meas_ctrl); + if (rc) + return rc; + + /* Wait for the command to actually finish */ + rc = zl3073x_wait_clear_bits(zldev, ref_freq_meas_ctrl, + REF_FREQ_MEAS_CTRL_LATCH); + if (rc) + return rc; + + /* Read the frequency offset between DPLL and reference */ + rc = zl3073x_read_ref_freq(zldev, ref_id, &freq_offset); + if (rc) + return rc; + + *ffo = freq_offset; + + return rc; +} + static int zl3073x_dpll_input_pin_frequency_get(const struct dpll_pin *dpll_pin, void *pin_priv, @@ -1778,6 +1872,7 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .direction_get = zl3073x_dpll_pin_direction_get, .esync_get = zl3073x_dpll_input_pin_esync_get, .esync_set = zl3073x_dpll_input_pin_esync_set, + .ffo_get = zl3073x_dpll_input_pin_ffo_get, .frequency_get = zl3073x_dpll_input_pin_frequency_get, .frequency_set = zl3073x_dpll_input_pin_frequency_set, .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get, @@ -2484,9 +2579,9 @@ zl3073x_dpll_periodic_work(struct kthread_work *work) * are constant. */ for (i = 0; i < ZL3073X_NUM_INPUT_PINS; i++) { + s64 freq_offset, phase_offset; struct zl3073x_dpll_pin *pin; enum dpll_pin_state state; - s64 phase_offset; bool pin_changed; /* Input pins starts are stored after output pins */ @@ -2513,6 +2608,12 @@ zl3073x_dpll_periodic_work(struct kthread_work *work) if (rc) goto out; + rc = zl3073x_dpll_input_pin_ffo_get(pin->dpll_pin, pin, + zldpll->dpll_dev, zldpll, + &freq_offset, NULL); + if (rc) + goto out; + if (state != pin->pin_state) { dev_dbg(zldev->dev, "INPUT%u state changed to %u\n", @@ -2527,6 +2628,13 @@ zl3073x_dpll_periodic_work(struct kthread_work *work) pin->phase_offset = phase_offset; pin_changed = true; } + if (freq_offset != pin->freq_offset) { + dev_dbg(zldev->dev, + "INPUT%u frequency offset changed to %llu\n", + pin->index, freq_offset); + pin->freq_offset = freq_offset; + pin_changed = true; + } if (pin_changed) dpll_pin_change_ntf(pin->dpll_pin);