From patchwork Tue Mar 28 10:01:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 667931 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 555E4C761A6 for ; Tue, 28 Mar 2023 10:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230047AbjC1KCh (ORCPT ); Tue, 28 Mar 2023 06:02:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232701AbjC1KCL (ORCPT ); Tue, 28 Mar 2023 06:02:11 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9F48B6A4E; Tue, 28 Mar 2023 03:02:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997729; x=1711533729; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=013xeHnW9lttA/KQdmfxgHU0jNti/+KDIk0yVRBwKSQ=; b=aImN0zA1BU3dYio8rOQ2YxwdYzmIeF130SdpYSznYXwHhGP3x4RHqxYW TsA4OZZhYOPdCRcJLVZW++MS4wot3YptX70T5TZyDKv1g1o9bs8UJiXZ8 qfYS707RgJrPxByHX8rpZ5eCeqrrQt2F3nuM8UO9546Y7jQV8zd3U54yt Qd9OnfW5zNWILEVXDa0t+dCnd3L2eAAsKs6jwTM8EDwlrM5kUjRHW0yYt 0AZ4r77xY4qO/RZ2Wl1R/2xqjoPtmlE7LNFcDwpMHKrW6XtDiVeu2P65y SlYtAAK66R6Gf/Fw8uIt/M3BZaKOaxLC4apfkbJGAtGDEOHkDyGIC65dV Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324419979" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324419979" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078499" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078499" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:03 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 1BC3112243C; Tue, 28 Mar 2023 13:02:01 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 01/10] ACPI: scan: Remove the second DSDT traversal Date: Tue, 28 Mar 2023 13:01:49 +0300 Message-Id: <20230328100159.1457160-2-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Collect the devices with _DEP into a list and continue processing them after a full traversal, instead of doing a full second traversal of the tree. This makes the second DSDT traversal pass unnecessary as we already have the nodes we're interested in in a linked list. Signed-off-by: Sakari Ailus --- drivers/acpi/scan.c | 125 ++++++++++++++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 33 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0c6f06abe3f4..df97c2babf39 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2029,10 +2029,52 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) return count; } -static bool acpi_bus_scan_second_pass; +/** + * struct acpi_postponed_handle - A postponed ACPI handle + * @handle: The postponed handle + * @list: Entry in a postponed list + * + * One such entry represents an ACPI handle the scanning of which has been + * postponed. + */ +struct acpi_postponed_handle { + acpi_handle handle; + struct list_head list; +}; + +/** + * struct acpi_scan_context - Context for scanning ACPI devices + * @device: The first encountered device, typically the root of the scanned tree + * @postponed_head: The list head of the postponed ACPI handles + */ +struct acpi_scan_context { + struct acpi_device *device; + struct list_head postponed_head; +}; + +/** + * acpi_bus_handle_postpone - Add an ACPI handle to a given postponed list + * @handle: The ACPI handle + * @head: Postponed list head + * + * Add a given ACPI handle to a list of ACPI objects for which the creation + * of the device objects is to be postponed. + */ +static void acpi_bus_handle_postpone(acpi_handle handle, + struct list_head *head) +{ + struct acpi_postponed_handle *ph; + + ph = kzalloc(sizeof(*ph), GFP_KERNEL); + if (!ph) + return; + + ph->handle = handle; + list_add(&ph->list, head); +} static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, - struct acpi_device **adev_p) + struct acpi_scan_context *ctx) { struct acpi_device *device = acpi_fetch_acpi_dev(handle); acpi_object_type acpi_type; @@ -2051,7 +2093,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, /* Bail out if there are dependencies. */ if (acpi_scan_check_dep(handle, check_dep) > 0) { - acpi_bus_scan_second_pass = true; + acpi_bus_handle_postpone(handle, &ctx->postponed_head); return AE_CTRL_DEPTH; } @@ -2086,22 +2128,22 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, acpi_scan_init_hotplug(device); out: - if (!*adev_p) - *adev_p = device; + if (!ctx->device) + ctx->device = device; return AE_OK; } static acpi_status acpi_bus_check_add_1(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_p) + void *ctx, void **unused) { - return acpi_bus_check_add(handle, true, (struct acpi_device **)ret_p); + return acpi_bus_check_add(handle, true, (struct acpi_scan_context *)ctx); } static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_p) + void *ctx, void **device) { - return acpi_bus_check_add(handle, false, (struct acpi_device **)ret_p); + return acpi_bus_check_add(handle, false, (struct acpi_scan_context *)ctx); } static void acpi_default_enumeration(struct acpi_device *device) @@ -2422,37 +2464,54 @@ EXPORT_SYMBOL_GPL(acpi_dev_get_next_consumer_dev); */ int acpi_bus_scan(acpi_handle handle) { - struct acpi_device *device = NULL; - - acpi_bus_scan_second_pass = false; - - /* Pass 1: Avoid enumerating devices with missing dependencies. */ + struct acpi_scan_context ctx = { + .postponed_head = LIST_HEAD_INIT(ctx.postponed_head), + }; + struct acpi_postponed_handle *ph, *tmp_ph; + int ret = 0; - if (ACPI_SUCCESS(acpi_bus_check_add(handle, true, &device))) + if (ACPI_SUCCESS(acpi_bus_check_add(handle, true, &ctx))) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_check_add_1, NULL, NULL, - (void **)&device); - - if (!device) - return -ENODEV; - - acpi_bus_attach(device, (void *)true); + acpi_bus_check_add_1, NULL, (void *)&ctx, + NULL); - if (!acpi_bus_scan_second_pass) - return 0; - - /* Pass 2: Enumerate all of the remaining devices. */ + if (!ctx.device) { + ret = -ENODEV; + goto out_release; + } - device = NULL; + acpi_bus_attach(ctx.device, (void *)true); - if (ACPI_SUCCESS(acpi_bus_check_add(handle, false, &device))) - acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_check_add_2, NULL, NULL, - (void **)&device); + /* + * Proceed to register ACPI devices that were postponed due to _DEP + * objects during the namespace walk. + */ + list_for_each_entry_safe(ph, tmp_ph, &ctx.postponed_head, list) { + list_del(&ph->list); + /* Set device NULL here to obtain the root for this sub-tree. */ + ctx.device = NULL; + /* + * Do this manually, as the namespace walk will only include + * sub-nodes, not the node itself. ctx.device is set to the + * ACPI device corresponding ph->handle. + */ + acpi_bus_check_add_2(ph->handle, 0, &ctx, NULL); + /* Walk the rest of the sub-namespace. */ + acpi_walk_namespace(ACPI_TYPE_ANY, ph->handle, ACPI_UINT32_MAX, + acpi_bus_check_add_2, NULL, (void *)&ctx, + NULL); + if (ctx.device) + acpi_bus_attach(ctx.device, NULL); + kfree(ph); + } - acpi_bus_attach(device, NULL); +out_release: + list_for_each_entry_safe(ph, tmp_ph, &ctx.postponed_head, list) { + list_del(&ph->list); + kfree(ph); + } - return 0; + return ret; } EXPORT_SYMBOL(acpi_bus_scan); From patchwork Tue Mar 28 10:01:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 668170 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D06FC77B60 for ; Tue, 28 Mar 2023 10:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230128AbjC1KCh (ORCPT ); Tue, 28 Mar 2023 06:02:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53096 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232719AbjC1KCL (ORCPT ); Tue, 28 Mar 2023 06:02:11 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A9D6555B4; Tue, 28 Mar 2023 03:02:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997729; x=1711533729; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=aMaKHZ+sOaceKGE77joDQX5kyAJ9jYBW7/J7dxvAchw=; b=h5JuJkQQ4mzmiBHGRtyIpOekqIbv5XAiSMglwZ98ehe6A6oMycXicCJi GRVu98ujaTc2rD5g1jvSQ/VYDSIPRaSMjtK7kG3jD+BH8ObArlun9ZIQe 3F6TShGmwY6Qfp4vGLMv8XlBRXqNQGT803fstSl5b6fpnO/tmKx4Xr8Ek 9GSBai30mdVhemwaGnCiBxWH2fCrXhM1ncOWv5lX2+fEbaFyH44vH11Ar TUlLv186xPpoUznCz50wD5CPVV5pNBXXKpdG5PfNyB/urgho9/kLDf6Bq D7dfkiyQnZTDxetm8crHsGMSxRvqBF5eIC9aoIkegVF/m6Dw5M5LkOihd w==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324419981" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324419981" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078508" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078508" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:04 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id EFD8E122499; Tue, 28 Mar 2023 13:02:01 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 02/10] ACPI: property: Parse data node string references in properties Date: Tue, 28 Mar 2023 13:01:50 +0300 Message-Id: <20230328100159.1457160-3-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Add support for parsing property references using strings, besides reference objects that were previously supported. This allows also referencing data nodes which was not possible with reference objects. Also add pr_fmt() macro to prefix printouts. While at it, update copyright. Signed-off-by: Sakari Ailus --- drivers/acpi/property.c | 110 ++++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index b8d9eb9a433e..08831ffba26c 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -2,14 +2,17 @@ /* * ACPI device specific properties support. * - * Copyright (C) 2014, Intel Corporation + * Copyright (C) 2014-2023, Intel Corporation * All rights reserved. * * Authors: Mika Westerberg - * Darren Hart - * Rafael J. Wysocki + * Darren Hart + * Rafael J. Wysocki + * Sakari Ailus */ +#define pr_fmt(fmt) "ACPI: " fmt + #include #include #include @@ -795,7 +798,8 @@ acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, static int acpi_get_ref_args(struct fwnode_reference_args *args, struct fwnode_handle *ref_fwnode, const union acpi_object **element, - const union acpi_object *end, size_t num_args) + const union acpi_object *end, size_t num_args, + bool subnode_string) { u32 nargs = 0, i; @@ -803,13 +807,16 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args, * Find the referred data extension node under the * referred device node. */ - for (; *element < end && (*element)->type == ACPI_TYPE_STRING; - (*element)++) { - const char *child_name = (*element)->string.pointer; - - ref_fwnode = acpi_fwnode_get_named_child_node(ref_fwnode, child_name); - if (!ref_fwnode) - return -EINVAL; + if (subnode_string) { + for (; *element < end && (*element)->type == ACPI_TYPE_STRING; + (*element)++) { + const char *child_name = (*element)->string.pointer; + + ref_fwnode = acpi_fwnode_get_named_child_node(ref_fwnode, + child_name); + if (!ref_fwnode) + return -EINVAL; + } } /* @@ -820,7 +827,8 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args, for (i = 0; (*element) + i < end && i < num_args; i++) { acpi_object_type type = (*element)[i].type; - if (type == ACPI_TYPE_LOCAL_REFERENCE) + if (type == ACPI_TYPE_LOCAL_REFERENCE || + (!subnode_string && type == ACPI_TYPE_STRING)) break; if (type == ACPI_TYPE_INTEGER) @@ -844,6 +852,43 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args, return 0; } +static struct fwnode_handle * +acpi_parse_string_ref(const struct fwnode_handle *fwnode, const char *refstring) +{ + acpi_handle scope, handle; + struct acpi_data_node *dn; + struct acpi_device *device; + acpi_status status; + + if (is_acpi_device_node(fwnode)) { + scope = to_acpi_device_node(fwnode)->handle; + } else if (is_acpi_data_node(fwnode)) { + scope = to_acpi_data_node(fwnode)->handle; + } else { + pr_debug("bad node type for node %pfw\n", fwnode); + return ERR_PTR(-EINVAL); + } + + status = acpi_get_handle(scope, refstring, &handle); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(scope, "can't get handle for %s", refstring); + return ERR_PTR(-EINVAL); + } + + device = acpi_fetch_acpi_dev(handle); + if (device) + return acpi_fwnode_handle(device); + + status = acpi_get_data_full(handle, acpi_nondev_subnode_tag, + (void **)&dn, NULL); + if (ACPI_FAILURE(status) || !dn) { + acpi_handle_debug(handle, "can't find subnode"); + return ERR_PTR(-EINVAL); + } + + return &dn->fwnode; +} + /** * __acpi_node_get_property_reference - returns handle to the referenced object * @fwnode: Firmware node to get the property from @@ -886,6 +931,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, const union acpi_object *element, *end; const union acpi_object *obj; const struct acpi_device_data *data; + struct fwnode_handle *ref_fwnode; struct acpi_device *device; int ret, idx = 0; @@ -909,16 +955,29 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, args->fwnode = acpi_fwnode_handle(device); args->nargs = 0; + return 0; + case ACPI_TYPE_STRING: + if (index) + return -ENOENT; + + ref_fwnode = acpi_parse_string_ref(fwnode, obj->string.pointer); + if (IS_ERR(ref_fwnode)) + return PTR_ERR(ref_fwnode); + + args->fwnode = ref_fwnode; + args->nargs = 0; + return 0; case ACPI_TYPE_PACKAGE: /* * If it is not a single reference, then it is a package of - * references followed by number of ints as follows: + * references, followed by number of ints as follows: * * Package () { REF, INT, REF, INT, INT } * - * The index argument is then used to determine which reference - * the caller wants (along with the arguments). + * Here, REF may be either a local reference or a string. The + * index argument is then used to determine which reference the + * caller wants (along with the arguments). */ break; default: @@ -942,7 +1001,26 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, ret = acpi_get_ref_args(idx == index ? args : NULL, acpi_fwnode_handle(device), - &element, end, num_args); + &element, end, num_args, true); + if (ret < 0) + return ret; + + if (idx == index) + return 0; + + break; + case ACPI_TYPE_STRING: + ref_fwnode = + acpi_parse_string_ref(fwnode, + element->string.pointer); + if (IS_ERR(ref_fwnode)) + return PTR_ERR(ref_fwnode); + + element++; + + ret = acpi_get_ref_args(idx == index ? args : NULL, + ref_fwnode, &element, end, + num_args, false); if (ret < 0) return ret; From patchwork Tue Mar 28 10:01:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 668166 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E27CEC77B70 for ; Tue, 28 Mar 2023 10:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230515AbjC1KCk (ORCPT ); Tue, 28 Mar 2023 06:02:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232839AbjC1KCM (ORCPT ); Tue, 28 Mar 2023 06:02:12 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E9D685BAE; Tue, 28 Mar 2023 03:02:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997729; x=1711533729; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=/+sS2b+dgkP//cFDbe4YO72zbziuEeW/HhMKgSymv5k=; b=J26WlepnPBwi7+94kqMYvOdDwwEESVCXslbPUAPJ4DK/MzDYSeDHdcz3 i3SukAKOJvpor2MDjK/9xR+DvtRMFVPPXshrhevHWr4z1l9gR3Pieg43e hMb0Hl+6RAsI7scZ/duHuTUe4ZOMOBBG+j3yOF04fyIQz/QrffbA2ehrJ DMHPOvccN08StyzeVnZCthhCh8gjQ4cBMFA4l8DU4WMl9w4RUkbOzyRf6 AHz3ku0ygQZZKpyV3F+TWu62UjP5vstzB0ZJaw0fj302pnPHs2L1cd9ao cBzKsy6tes983qqNdhoHniQfE6icNLQma0orGBCshcuviUpWJts4LIhYv w==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324419991" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324419991" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:07 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078517" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078517" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:05 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id C2D1E12249A; Tue, 28 Mar 2023 13:02:02 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 03/10] ACPI: property: Parse _CRS CSI-2 descriptor Date: Tue, 28 Mar 2023 13:01:51 +0300 Message-Id: <20230328100159.1457160-4-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Parse newly added ACPI _CRS CSI-2 descriptor for CSI-2 and camera configuration, associate it with appropriate devices and allocate memory for software nodes needed to create a DT-like data structure for drivers. Signed-off-by: Sakari Ailus --- drivers/acpi/Makefile | 2 +- drivers/acpi/internal.h | 26 +++ drivers/acpi/mipi.c | 345 ++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 46 ++++-- include/acpi/acpi_bus.h | 11 ++ 5 files changed, 415 insertions(+), 15 deletions(-) create mode 100644 drivers/acpi/mipi.c diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index a5b649e71ab1..a98fa1bc1554 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -37,7 +37,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o # ACPI Bus and Device Drivers # acpi-y += bus.o glue.o -acpi-y += scan.o +acpi-y += scan.o mipi.o acpi-y += resource.o acpi-y += acpi_processor.o acpi-y += processor_core.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ec584442fb29..9db8b2e2730a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -102,6 +102,24 @@ struct acpi_device_bus_id { struct list_head node; }; +/* Context for scanning ACPI device nodes for _CRS CSI2 resource descriptors */ +struct acpi_scan_context_csi2 { + struct list_head crs_csi2_head; + size_t handle_count; +}; + +/** + * struct acpi_scan_context - Context for scanning ACPI devices + * @device: The first encountered device, typically the root of the scanned tree + * @postponed_head: The list head of the postponed ACPI handles + * @csi2: Context for scanning _CRS CSI2 resource descriptors + */ +struct acpi_scan_context { + struct acpi_device *device; + struct list_head postponed_head; + struct acpi_scan_context_csi2 csi2; +}; + void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, int type, void (*release)(struct device *)); int acpi_tie_acpi_dev(struct acpi_device *adev); @@ -282,4 +300,12 @@ void acpi_init_lpit(void); static inline void acpi_init_lpit(void) { } #endif +/*-------------------------------------------------------------------------- + ACPI _CRS CSI2 and MIPI DisCo for Imaging conversion + -------------------------------------------------------------------------- */ + +void acpi_crs_csi2_swnodes_del_free(void); +void acpi_bus_scan_check_crs_csi2(acpi_handle handle, struct acpi_scan_context *ctx); +void acpi_bus_scan_crs_csi2(struct acpi_scan_context_csi2 *ctx); + #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/mipi.c b/drivers/acpi/mipi.c new file mode 100644 index 000000000000..ffc1768f86ed --- /dev/null +++ b/drivers/acpi/mipi.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MIPI DisCo for Imaging support. + * + * Support MIPI DisCo for Imaging by parsing ACPI _CRS CSI2 records and DisCo + * for Imaging data structures. + * + * Also see . + * + * Copyright (C) 2023 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +/* Temporary ACPI device handle to software node data structure mapping */ +struct crs_csi2_swnodes { + struct list_head list; + acpi_handle handle; + struct acpi_device_software_nodes *ads; +}; + +static LIST_HEAD(crs_csi2_swnodes); + +static void crs_csi2_swnode_del_free(struct crs_csi2_swnodes *swnodes) +{ + list_del(&swnodes->list); + kfree(swnodes); +} + +void acpi_crs_csi2_swnodes_del_free(void) +{ + struct crs_csi2_swnodes *swnodes, *swnodes_tmp; + + list_for_each_entry_safe(swnodes, swnodes_tmp, &crs_csi2_swnodes, list) + crs_csi2_swnode_del_free(swnodes); +} + +/* + * Description of a _CRS CSI2 resource descriptor before software node creation + */ +struct crs_csi2_instance { + struct list_head list; + struct acpi_resource_csi2_serialbus csi2; + acpi_handle remote_handle; + char remote_name[]; +}; + +/* Temporary list of ACPI device nodes with _CRS CSI2 resource descriptors */ +struct crs_csi2 { + struct list_head list; + acpi_handle handle; + struct list_head buses; +}; + +/* + * Context for collecting _CRS CSI2 resource descriptors during ACPI namespace + * walk + */ +struct scan_check_crs_csi2_context { + struct list_head res_head; + acpi_handle handle; + size_t handle_count; +}; + +/* Scan a single CSI2 resource descriptor in _CRS. */ +static acpi_status scan_check_crs_csi2_instance(struct acpi_resource *res, + void *context) +{ + struct scan_check_crs_csi2_context *inst_context = context; + struct acpi_resource_csi2_serialbus *csi2; + struct crs_csi2_instance *inst; + acpi_handle remote_handle; + + if (res->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return AE_OK; + + csi2 = &res->data.csi2_serial_bus; + + if (csi2->type != ACPI_RESOURCE_SERIAL_TYPE_CSI2) + return AE_OK; + + if (!csi2->resource_source.string_length) { + acpi_handle_debug(inst_context->handle, + "invalid resource source string length\n"); + return AE_OK; + } + + if (ACPI_FAILURE(acpi_get_handle(NULL, csi2->resource_source.string_ptr, + &remote_handle))) { + acpi_handle_warn(inst_context->handle, + "cannot get handle for %s\n", + csi2->resource_source.string_ptr); + return AE_OK; + } + + /* + * Allocate space to store the _CRS CSI2 entry and its data and add it + * to the list. + */ + inst = kmalloc(struct_size(inst, remote_name, csi2->resource_source.string_length), + GFP_KERNEL); + if (!inst) + return AE_OK; + + inst->csi2 = *csi2; + strscpy(inst->remote_name, csi2->resource_source.string_ptr, + csi2->resource_source.string_length); + inst->csi2.resource_source.string_ptr = inst->remote_name; + inst->remote_handle = remote_handle; + + list_add(&inst->list, &inst_context->res_head); + + inst_context->handle_count++; + + return AE_OK; +} + +/* + * Find all devices with _CRS CSI2 resource descriptors and collect them + * into a list for later use. + */ +void acpi_bus_scan_check_crs_csi2(acpi_handle handle, struct acpi_scan_context *ctx) +{ + struct scan_check_crs_csi2_context inst_context = { + .handle = handle, + .res_head = LIST_HEAD_INIT(inst_context.res_head), + }; + struct crs_csi2 *csi2; + + acpi_walk_resources(handle, METHOD_NAME__CRS, + scan_check_crs_csi2_instance, &inst_context); + + if (list_empty(&inst_context.res_head)) + return; + + /* + * Found entry, so allocate memory for it, fill it and add it to the + * list. + */ + csi2 = kmalloc(sizeof(*csi2), GFP_KERNEL); + if (!csi2) + return; /* There's nothing we really can do about this. */ + + csi2->handle = handle; + list_replace(&inst_context.res_head, &csi2->buses); + list_add(&csi2->list, &ctx->csi2.crs_csi2_head); + + /* This handle plus remote handles in _CRS CSI2 resource descriptors */ + ctx->csi2.handle_count += 1 + inst_context.handle_count; +} + +struct acpi_handle_ref { + acpi_handle handle; + unsigned int count; +}; + +#define NO_CSI2_PORT (UINT_MAX - 1) + +static int crs_handle_cmp(const void *__a, const void *__b) +{ + const struct acpi_handle_ref *a = __a, *b = __b; + + return a->handle < b->handle ? -1 : a->handle > b->handle; +} + +/* + * Release entries in temporary storage of ACPI device nodes with _CRS CSI2 + * resource descriptors. + */ +static void crs_csi2_release(struct list_head *crs_csi2_handles) +{ + struct crs_csi2 *csi2, *csi2_tmp; + + list_for_each_entry_safe(csi2, csi2_tmp, crs_csi2_handles, list) { + struct crs_csi2_instance *inst, *inst_tmp; + + list_for_each_entry_safe(inst, inst_tmp, &csi2->buses, list) { + list_del(&inst->list); + kfree(inst); + } + + list_del(&csi2->list); + kfree(csi2); + } +} + +/* + * Allocate memory and set up software nodes for an ACPI device with given + * number of CSI-2 ports. + */ +static void acpi_crs_csi2_alloc_fill_swnodes(size_t ports_count, acpi_handle handle) +{ + struct acpi_device_software_nodes *ads; + struct crs_csi2_swnodes *swnodes; + size_t alloc_size; + unsigned int i; + bool overflow; + void *end; + + /* + * Allocate memory for ports, node pointers (number of nodes + + * 1 (guardian), nodes (root + number of ports * 2 (for for + * every port there is an endpoint)). + */ + overflow = check_mul_overflow(sizeof(*ads->ports) + + sizeof(*ads->nodes) * 2 + + sizeof(*ads->nodeptrs) * 2, + ports_count, &alloc_size); + overflow = overflow || + check_add_overflow(sizeof(*ads) + sizeof(*ads->nodes) + + sizeof(*ads->nodeptrs) * 2, + alloc_size, &alloc_size); + if (overflow) { + acpi_handle_warn(handle, + "too many _CRS CSI2 resource handles (%zu)", + ports_count); + return; + } + + swnodes = kzalloc(sizeof(*swnodes), GFP_KERNEL); + ads = kmalloc(alloc_size, GFP_KERNEL); + if (!swnodes || !ads) + goto out_free; + + ads->ports = (void *)(ads + 1); + ads->nodes = (void *)(ads->ports + ports_count); + ads->nodeptrs = (void *)(ads->nodes + ports_count * 2 + 1); + end = ads->nodeptrs + ports_count * 2 + 2; + if (WARN_ON((void *)ads + alloc_size != end)) + goto out_free; + + ads->num_ports = ports_count; + for (i = 0; i < ports_count * 2 + 1; i++) + ads->nodeptrs[i] = &ads->nodes[i]; + ads->nodeptrs[i] = NULL; + for (i = 0; i < ports_count; i++) + ads->ports[i].port_nr = NO_CSI2_PORT; + swnodes->handle = handle; + swnodes->ads = ads; + list_add(&swnodes->list, &crs_csi2_swnodes); + + return; + +out_free: + kfree(swnodes); + kfree(ads); + acpi_handle_debug(handle, "cannot allocate for %zu software nodes\n", + ports_count); +} + +/** + * acpi_bus_scan_crs_csi2 - Construct software nodes out of ACPI _CRS CSI2 + * resource descriptors + * @ctx: ACPI _CRS CSI2 context, gathered during tree walk earlier + * + * This function does a number of things: + * + * 1. Count how many references to other devices _CRS CSI-2 instances have in + * total. + * + * 2. Count the number of references to other devices for each _CRS CSI-2 + * instance. + * + * 3. Allocate memory for swnodes each ACPI device requires later on, and + * generate a list of such allocations. + * + * Note that struct acpi_device may not be available yet at this time. + * + * acpi_scan_lock in scan.c must be held when calling this function. + */ +void acpi_bus_scan_crs_csi2(struct acpi_scan_context_csi2 *ctx) +{ + struct acpi_handle_ref *handle_refs; + struct acpi_handle_ref *this = NULL; + size_t this_count; + unsigned int curr = 0; + struct crs_csi2 *csi2; + + /* No handles? Bail out here. */ + if (!ctx->handle_count) + return; + + handle_refs = kcalloc(ctx->handle_count + 1, sizeof(*handle_refs), + GFP_KERNEL); + if (!handle_refs) { + pr_debug("no memory for %zu handle refs\n", + ctx->handle_count + 1); + return; + } + + /* Associate handles to the number of references. */ + list_for_each_entry(csi2, &ctx->crs_csi2_head, list) { + struct crs_csi2_instance *inst; + struct acpi_handle_ref *handle_ref; + + handle_ref = &handle_refs[curr++]; + handle_ref->handle = csi2->handle; + + list_for_each_entry(inst, &csi2->buses, list) { + handle_refs[curr].handle = inst->remote_handle; + handle_refs[curr].count = 1; + handle_ref->count++; + curr++; + } + } + + handle_refs[curr].handle = NULL; + + /* Sort the handles by remote so duplicates canbe easily found. */ + sort(handle_refs, ctx->handle_count, sizeof(*handle_refs), crs_handle_cmp, NULL); + + /* + * Finally count references in each handle, allocate space for device + * specific ports, properties and fill the _CRS CSI2 descriptor + * originated data. + */ + this = handle_refs; + this_count = this->count; + for (curr = 1; curr < ctx->handle_count + 1; curr++) { + /* Weed out duplicate receiver devices. */ + if (this->handle == handle_refs[curr].handle) { + this_count += handle_refs[curr].count; + continue; + } + + acpi_crs_csi2_alloc_fill_swnodes(this_count, this->handle); + + this = &handle_refs[curr]; + this_count = this->count; + } + + kfree(handle_refs); + + crs_csi2_release(&ctx->crs_csi2_head); +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index df97c2babf39..4f4f6b0db0a9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2042,16 +2042,6 @@ struct acpi_postponed_handle { struct list_head list; }; -/** - * struct acpi_scan_context - Context for scanning ACPI devices - * @device: The first encountered device, typically the root of the scanned tree - * @postponed_head: The list head of the postponed ACPI handles - */ -struct acpi_scan_context { - struct acpi_device *device; - struct list_head postponed_head; -}; - /** * acpi_bus_handle_postpone - Add an ACPI handle to a given postponed list * @handle: The ACPI handle @@ -2073,7 +2063,7 @@ static void acpi_bus_handle_postpone(acpi_handle handle, list_add(&ph->list, head); } -static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, +static acpi_status acpi_bus_check_add(acpi_handle handle, bool first_pass, struct acpi_scan_context *ctx) { struct acpi_device *device = acpi_fetch_acpi_dev(handle); @@ -2091,8 +2081,11 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, if (acpi_device_should_be_hidden(handle)) return AE_OK; + if (first_pass) + acpi_bus_scan_check_crs_csi2(handle, ctx); + /* Bail out if there are dependencies. */ - if (acpi_scan_check_dep(handle, check_dep) > 0) { + if (acpi_scan_check_dep(handle, first_pass) > 0) { acpi_bus_handle_postpone(handle, &ctx->postponed_head); return AE_CTRL_DEPTH; } @@ -2118,10 +2111,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, } /* - * If check_dep is true at this point, the device has no dependencies, + * If first_pass is true at this point, the device has no dependencies, * or the creation of the device object would have been postponed above. */ - acpi_add_single_object(&device, handle, type, !check_dep); + acpi_add_single_object(&device, handle, type, !first_pass); if (!device) return AE_CTRL_DEPTH; @@ -2146,6 +2139,14 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, return acpi_bus_check_add(handle, false, (struct acpi_scan_context *)ctx); } +static acpi_status acpi_bus_check_csi2(acpi_handle handle, u32 lvl_not_used, + void *ctx, void **unused) +{ + acpi_bus_scan_check_crs_csi2(handle, ctx); + + return AE_OK; +} + static void acpi_default_enumeration(struct acpi_device *device) { /* @@ -2466,6 +2467,7 @@ int acpi_bus_scan(acpi_handle handle) { struct acpi_scan_context ctx = { .postponed_head = LIST_HEAD_INIT(ctx.postponed_head), + .csi2.crs_csi2_head = LIST_HEAD_INIT(ctx.csi2.crs_csi2_head), }; struct acpi_postponed_handle *ph, *tmp_ph; int ret = 0; @@ -2480,6 +2482,20 @@ int acpi_bus_scan(acpi_handle handle) goto out_release; } + /* + * Check _CRS CSI2 resource descriptors for devices that were not + * traversed during the previous pass. + */ + list_for_each_entry_safe(ph, tmp_ph, &ctx.postponed_head, list) { + acpi_bus_check_csi2(ph->handle, 0, &ctx, NULL); + acpi_walk_namespace(ACPI_TYPE_DEVICE, ph->handle, ACPI_UINT32_MAX, + acpi_bus_check_csi2, NULL, (void *)&ctx, + NULL); + } + + /* Construct software nodes out of _CRS CSI2 records */ + acpi_bus_scan_crs_csi2(&ctx.csi2); + acpi_bus_attach(ctx.device, (void *)true); /* @@ -2511,6 +2527,8 @@ int acpi_bus_scan(acpi_handle handle) kfree(ph); } + acpi_crs_csi2_swnodes_del_free(); + return ret; } EXPORT_SYMBOL(acpi_bus_scan); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e44be31115a6..a05fe22c1175 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -360,6 +360,17 @@ struct acpi_device_data { struct acpi_gpio_mapping; +struct acpi_device_software_node_port { + unsigned int port_nr; +}; + +struct acpi_device_software_nodes { + struct acpi_device_software_node_port *ports; + struct software_node *nodes; + const struct software_node **nodeptrs; + unsigned int num_ports; +}; + /* Device */ struct acpi_device { u32 pld_crc; From patchwork Tue Mar 28 10:01:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 667929 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 442C7C77B74 for ; Tue, 28 Mar 2023 10:03:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231757AbjC1KCl (ORCPT ); Tue, 28 Mar 2023 06:02:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53068 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232832AbjC1KCM (ORCPT ); Tue, 28 Mar 2023 06:02:12 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 354BA55B8; Tue, 28 Mar 2023 03:02:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997731; x=1711533731; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nQjAfaD5hKwVtKx91g9YmLGgoqW2l5NzACGAL0F8b40=; b=RHT90DIKgSefp1atwBeGNwzu4Pw0rWmWMbWNS/WEBNL0GnuoSRX9DvHP hs60LMRQ/3IomfhZ8ayYwullgrHk9Pglq7F+7nti+Wto4lkebnjN8/VVG RF+i3zEHGNZjK8TD0kBADYPmaXj6F+VlwgI3zh+8nRW4D1zclMkMD56gy y3bUwuPMRZK3NJ4yxZpv5Jz001gKJJxrKLoKIJJGUlsQ3/VFeDB+4HrzU zZXLNXlWN6mWY0ONR3bz/bfTYynIm37ZyDXEk+VuiHpAzIyr5TJ38wtsB 29CJVeP0t2QRbsCBD1SoOs5Ro6He/e0S9afeZ37nTAi4hncuISxhIRLZG g==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324419996" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324419996" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:08 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078522" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078522" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:06 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id D4DF81224A7; Tue, 28 Mar 2023 13:02:03 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 04/10] device property: Add SOFTWARE_NODE() macro for defining software nodes Date: Tue, 28 Mar 2023 13:01:52 +0300 Message-Id: <20230328100159.1457160-5-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Add SOFTWARE_NODE() macro in order to make defining software nodes look nicer. This is analogous to different PROPERTY_ENTRY_*() macros for defining properties. Signed-off-by: Sakari Ailus Reviewed-by: Andy Shevchenko Reviewed-by: Heikki Krogerus --- include/linux/property.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/property.h b/include/linux/property.h index 37179e3abad5..6745a86bc9b9 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -477,6 +477,13 @@ struct software_node { const struct property_entry *properties; }; +#define SOFTWARE_NODE(_name_, _properties_, _parent_) \ + (struct software_node) { \ + .name = _name_, \ + .properties = _properties_, \ + .parent = _parent_, \ + } + bool is_software_node(const struct fwnode_handle *fwnode); const struct software_node * to_software_node(const struct fwnode_handle *fwnode); From patchwork Tue Mar 28 10:01:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 668167 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D19FDC77B71 for ; Tue, 28 Mar 2023 10:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231374AbjC1KCk (ORCPT ); Tue, 28 Mar 2023 06:02:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53070 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232853AbjC1KCN (ORCPT ); Tue, 28 Mar 2023 06:02:13 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 73BDF6180; Tue, 28 Mar 2023 03:02:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997731; x=1711533731; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eUPJCLEE7rEbHPhREmYDD9H21a5kCqFmndwm3Rid1SE=; b=hY7x2o+7812CHON7V+Ojx2fT354rRqUkryScqTDZvdculFz9em/7p7+d wKfyllKd0YLvlFYztdxnNB/V0sQ8PNoXl3I8rNSjiYvkD+SEtNdunijaP Q2DEVx3c2WJaAonMQSeLmCo4UZD5OwKH56H2oFULIx1cUHh2/b9mG7R6I fOyOuIEiVZkkbq4QRMmMi4DipNrDlzMJgYfsPsnf0N9t43eZre8pM8BMs IvwyGQw5IRypco0/qMw0nvASqEeFhX6OljJFkvHt0/Pf3EJJGaOZUzXWt Aa/tACE3G0TDSOkAy4buysoS6OtmEn4zzpv+cuvmAE5TUR2gNH6TBSXrE A==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324420000" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324420000" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078532" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078532" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:07 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id C867F120243; Tue, 28 Mar 2023 13:02:04 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 05/10] ACPI: property: Prepare generating swnodes for ACPI and DisCo for Imaging Date: Tue, 28 Mar 2023 13:01:53 +0300 Message-Id: <20230328100159.1457160-6-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Prepare generating software nodes for information parsed from ACPI _CRS for CSI-2 as well as MIPI DisCo for Imaging spec. The software nodes are compliant with existing ACPI or DT definitions and are parsed by relevant drivers without changes. Signed-off-by: Sakari Ailus --- drivers/acpi/internal.h | 1 + drivers/acpi/mipi.c | 359 +++++++++++++++++++++++++++++++++++++++- drivers/acpi/scan.c | 18 ++ include/acpi/acpi_bus.h | 70 ++++++++ 4 files changed, 447 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 9db8b2e2730a..4723690d0117 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -307,5 +307,6 @@ static inline void acpi_init_lpit(void) { } void acpi_crs_csi2_swnodes_del_free(void); void acpi_bus_scan_check_crs_csi2(acpi_handle handle, struct acpi_scan_context *ctx); void acpi_bus_scan_crs_csi2(struct acpi_scan_context_csi2 *ctx); +void acpi_init_swnodes(struct acpi_device *device); #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/mipi.c b/drivers/acpi/mipi.c index ffc1768f86ed..5d05d899bede 100644 --- a/drivers/acpi/mipi.c +++ b/drivers/acpi/mipi.c @@ -3,7 +3,8 @@ * MIPI DisCo for Imaging support. * * Support MIPI DisCo for Imaging by parsing ACPI _CRS CSI2 records and DisCo - * for Imaging data structures. + * for Imaging data structures and generating nodes and properties using + * software nodes compliant with DT definitions of the similar scope. * * Also see . * @@ -20,6 +21,8 @@ #include #include +#include + #include "internal.h" /* Temporary ACPI device handle to software node data structure mapping */ @@ -31,6 +34,18 @@ struct crs_csi2_swnodes { static LIST_HEAD(crs_csi2_swnodes); +/* Obtain pre-allocated software nodes for an ACPI device handle */ +static struct acpi_device_software_nodes *crs_csi2_swnode_get(acpi_handle handle) +{ + struct crs_csi2_swnodes *swnodes; + + list_for_each_entry(swnodes, &crs_csi2_swnodes, list) + if (swnodes->handle == handle) + return swnodes->ads; + + return NULL; +} + static void crs_csi2_swnode_del_free(struct crs_csi2_swnodes *swnodes) { list_del(&swnodes->list); @@ -166,6 +181,35 @@ struct acpi_handle_ref { #define NO_CSI2_PORT (UINT_MAX - 1) +/* + * Return next free entry in ports array of a software nodes related to an ACPI + * device. + */ +static unsigned int next_csi2_port_index(struct acpi_device_software_nodes *ads, + unsigned int port_nr) +{ + unsigned int i; + + for (i = 0; i < ads->num_ports; i++) { + struct acpi_device_software_node_port *port = &ads->ports[i]; + + if (port->port_nr == port_nr) + return i; + + if (port->port_nr == NO_CSI2_PORT) { + port->port_nr = port_nr; + return i; + } + } + + return NO_CSI2_PORT; +} + +/* Print graph port name into a buffer, return non-zero if failed. */ +#define GRAPH_PORT_NAME(var, num) \ + (snprintf((var), sizeof(var), SWNODE_GRAPH_PORT_NAME_FMT, (num)) >= \ + sizeof(var)) + static int crs_handle_cmp(const void *__a, const void *__b) { const struct acpi_handle_ref *a = __a, *b = __b; @@ -258,6 +302,9 @@ static void acpi_crs_csi2_alloc_fill_swnodes(size_t ports_count, acpi_handle han ports_count); } +#define ACPI_CRS_CSI2_PHY_TYPE_C 0 +#define ACPI_CRS_CSI2_PHY_TYPE_D 1 + /** * acpi_bus_scan_crs_csi2 - Construct software nodes out of ACPI _CRS CSI2 * resource descriptors @@ -274,6 +321,8 @@ static void acpi_crs_csi2_alloc_fill_swnodes(size_t ports_count, acpi_handle han * 3. Allocate memory for swnodes each ACPI device requires later on, and * generate a list of such allocations. * + * 4. Set up properties for software nodes. + * * Note that struct acpi_device may not be available yet at this time. * * acpi_scan_lock in scan.c must be held when calling this function. @@ -339,7 +388,315 @@ void acpi_bus_scan_crs_csi2(struct acpi_scan_context_csi2 *ctx) this_count = this->count; } + /* + * Allocate and set up necessary software nodes for each device and set + * up properties from _CRS CSI2 descriptor. + */ + list_for_each_entry(csi2, &ctx->crs_csi2_head, list) { + struct acpi_device_software_nodes *local_swnodes; + struct crs_csi2_instance *inst; + + local_swnodes = crs_csi2_swnode_get(csi2->handle); + if (WARN_ON_ONCE(!local_swnodes)) + continue; + + list_for_each_entry(inst, &csi2->buses, list) { + struct acpi_device_software_nodes *remote_swnodes; + struct acpi_device_software_node_port *local_port; + struct acpi_device_software_node_port *remote_port; + struct software_node *local_node, *remote_node; + unsigned int local_index, remote_index; + unsigned int bus_type; + + remote_swnodes = crs_csi2_swnode_get(inst->remote_handle); + if (WARN_ON_ONCE(!remote_swnodes)) + continue; + + local_index = next_csi2_port_index(local_swnodes, inst->csi2.local_port_instance); + remote_index = next_csi2_port_index(remote_swnodes, inst->csi2.resource_source.index); + + if (WARN_ON_ONCE(local_index >= local_swnodes->num_ports) || + WARN_ON_ONCE(remote_index >= remote_swnodes->num_ports)) + goto out_free; + + switch (inst->csi2.phy_type) { + case ACPI_CRS_CSI2_PHY_TYPE_C: + bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_CPHY; + break; + case ACPI_CRS_CSI2_PHY_TYPE_D: + bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_DPHY; + break; + default: + acpi_handle_info(csi2->handle, + "ignoring CSI-2 PHY type %u\n", + inst->csi2.phy_type); + continue; + } + + local_port = &local_swnodes->ports[local_index]; + local_node = &local_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(local_index)]; + local_port->remote_ep_ref[0] = SOFTWARE_NODE_REFERENCE(local_node); + local_port->crs_csi2_local = true; + + remote_port = &remote_swnodes->ports[remote_index]; + remote_node = &remote_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(remote_index)]; + remote_port->remote_ep_ref[0] = SOFTWARE_NODE_REFERENCE(remote_node); + + local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] = + PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", + remote_port->remote_ep_ref); + local_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] = + PROPERTY_ENTRY_U32("bus-type", bus_type); + local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] = + PROPERTY_ENTRY_U32("reg", 0); + local_port->port_props[ACPI_DEVICE_SWNODE_PRT_REG] = + PROPERTY_ENTRY_U32("reg", inst->csi2.local_port_instance); + if (GRAPH_PORT_NAME(local_port->port_name, + inst->csi2.local_port_instance)) + acpi_handle_warn(csi2->handle, + "name for local port %u too long", + inst->csi2.local_port_instance); + + remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] = + PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", local_port->remote_ep_ref); + remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] = + PROPERTY_ENTRY_U32("bus-type", bus_type); + remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] = + PROPERTY_ENTRY_U32("reg", 0); + remote_port->port_props[ACPI_DEVICE_SWNODE_PRT_REG] = + PROPERTY_ENTRY_U32("reg", + inst->csi2.resource_source.index); + if (GRAPH_PORT_NAME(remote_port->port_name, + inst->csi2.resource_source.index)) + acpi_handle_warn(csi2->handle, + "name for remote port %u too long", + inst->csi2.resource_source.index); + } + } + +out_free: kfree(handle_refs); crs_csi2_release(&ctx->crs_csi2_head); } + +/* + * Get the index of the next property in the property array, with a given + * maximum values. + */ +#define NEXT_PROPERTY(index, max) \ + (WARN_ON(++(index) > ACPI_DEVICE_SWNODE_##max + 1) ? \ + ACPI_DEVICE_SWNODE_##max : (index) - 1) + +static struct fwnode_handle *get_mipi_port_handle(struct acpi_device *device, + unsigned int port) +{ + static const char mipi_port_prefix[] = "mipi-img-port-"; + char mipi_port_name[sizeof(mipi_port_prefix) + 2]; + + if (snprintf(mipi_port_name, sizeof(mipi_port_name), "%s%u", + mipi_port_prefix, port) >= sizeof(mipi_port_name)) { + acpi_handle_info(acpi_device_handle(device), + "mipi port name too long for port %u\n", port); + return NULL; + } + + return fwnode_get_named_child_node(acpi_fwnode_handle(device), + mipi_port_name); +} + +static void init_port_csi2_common(struct acpi_device *device, + struct fwnode_handle *mipi_port_fwnode, + unsigned int *ep_prop_index, + unsigned int port_nr) +{ + unsigned int port_index = next_csi2_port_index(device->swnodes, port_nr); + struct acpi_device_software_nodes *ads = device->swnodes; + struct acpi_device_software_node_port *port = &ads->ports[port_index]; + unsigned int num_lanes = 0; + u8 val[ARRAY_SIZE(port->data_lanes)]; + int ret; + + *ep_prop_index = ACPI_DEVICE_SWNODE_EP_CLOCK_LANES; + + if (GRAPH_PORT_NAME(port->port_name, port_nr)) + return; + + ads->nodes[ACPI_DEVICE_SWNODE_PRT(port_index)] = + SOFTWARE_NODE(port->port_name, port->port_props, + &ads->nodes[ACPI_DEVICE_SWNODE_ROOT]); + + ret = fwnode_property_read_u8(mipi_port_fwnode, "mipi-img-clock-lane", val); + if (!ret) { + port->ep_props[NEXT_PROPERTY(*ep_prop_index, EP_CLOCK_LANES)] = + PROPERTY_ENTRY_U32("clock-lanes", *val); + } + ret = fwnode_property_count_u8(mipi_port_fwnode, "mipi-img-data-lanes"); + if (ret > 0) { + num_lanes = ret; + + if (num_lanes > ARRAY_SIZE(port->data_lanes)) { + acpi_handle_warn(acpi_device_handle(device), + "too many data lanes (%u)\n", + num_lanes); + num_lanes = ARRAY_SIZE(port->data_lanes); + } + + ret = fwnode_property_read_u8_array(mipi_port_fwnode, "mipi-img-data-lanes", + val, num_lanes); + if (!ret) { + unsigned int i; + + for (i = 0; i < num_lanes; i++) + port->data_lanes[i] = val[i]; + + port->ep_props[NEXT_PROPERTY(*ep_prop_index, EP_DATA_LANES)] = + PROPERTY_ENTRY_U32_ARRAY_LEN("data-lanes", port->data_lanes, + num_lanes); + } + } + + ret = fwnode_property_count_u8(mipi_port_fwnode, "mipi-img-lane-polarities"); + if (ret > 0) { + unsigned int bytes = min_t(unsigned int, ret, sizeof(val)); + + fwnode_property_read_u8_array(mipi_port_fwnode, + "mipi-img-lane-polarities", + val, bytes); + + /* Total number of lanes here is clock lane + data lanes */ + if (bytes * BITS_PER_TYPE(u8) >= 1 + num_lanes) { + unsigned int i; + + /* Move polarity bits to the lane polarity u32 array */ + for (i = 0; i < 1 + num_lanes; i++) + port->lane_polarities[i] = + (bool)(val[i >> 3] & (1 << (i & 7))); + + port->ep_props[NEXT_PROPERTY(*ep_prop_index, EP_LANE_POLARITIES)] = + PROPERTY_ENTRY_U32_ARRAY_LEN("lane-polarities", + port->lane_polarities, + 1 + num_lanes); + } else { + acpi_handle_warn(acpi_device_handle(device), + "too few lane polarity bytes (%u)\n", + bytes); + } + } + + ads->nodes[ACPI_DEVICE_SWNODE_EP(port_index)] = + SOFTWARE_NODE("endpoint@0", ads->ports[port_index].ep_props, + &ads->nodes[ACPI_DEVICE_SWNODE_PRT(port_index)]); +} + +static void init_port_csi2_local(struct acpi_device *device, + unsigned int port_nr) +{ + unsigned int port_index = next_csi2_port_index(device->swnodes, port_nr); + struct fwnode_handle *mipi_port_fwnode = + get_mipi_port_handle(device, port_nr); + struct acpi_device_software_node_port *port = + &device->swnodes->ports[port_index]; + unsigned int ep_prop_index; + int ret; + + init_port_csi2_common(device, mipi_port_fwnode, &ep_prop_index, port_nr); + + ret = fwnode_property_count_u64(mipi_port_fwnode, "mipi-img-link-frequencies"); + if (ret > 0) { + unsigned int num_link_freqs = ret; + + if (num_link_freqs > ARRAY_SIZE(port->link_frequencies)) { + acpi_handle_info(acpi_device_handle(device), + "too many link frequencies %u\n", + num_link_freqs); + num_link_freqs = ARRAY_SIZE(port->link_frequencies); + } + + ret = fwnode_property_read_u64_array(mipi_port_fwnode, + "mipi-img-link-frequencies", + port->link_frequencies, + num_link_freqs); + if (!ret) + port->ep_props[NEXT_PROPERTY(ep_prop_index, EP_LINK_FREQUENCIES)] = + PROPERTY_ENTRY_U64_ARRAY_LEN("link-frequencies", + port->link_frequencies, + num_link_freqs); + else + acpi_handle_info(acpi_device_handle(device), + "can't get link frequencies (%d)\n", + ret); + } + + fwnode_handle_put(mipi_port_fwnode); +} + +static void init_port_csi2_remote(struct acpi_device *device, + unsigned int port_nr) +{ + struct fwnode_handle *mipi_port_fwnode = get_mipi_port_handle(device, port_nr); + unsigned int ep_prop_index; + + init_port_csi2_common(device, mipi_port_fwnode, &ep_prop_index, port_nr); + + fwnode_handle_put(mipi_port_fwnode); +} + +/** + * acpi_init_swnodes - Set up software nodes for properties gathered elsewhere + * + * @device: ACPI device for which the software nodes are initialised + * + * Initialise and register software nodes for properties for which the data is + * gathered elsewhere, e.g. _CRS CSI-2 descriptors. The process itself takes + * place before this function is called. + * + * acpi_scan_lock in scan.c must be held when calling this function. + */ +void acpi_init_swnodes(struct acpi_device *device) +{ + struct acpi_device_software_nodes *ads; + struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER }; + acpi_handle handle = acpi_device_handle(device); + struct fwnode_handle *primary; + acpi_status status; + unsigned int i; + int ret; + + device->swnodes = ads = crs_csi2_swnode_get(handle); + if (!ads) + return; + + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + acpi_handle_warn(handle, "cannot get path name\n"); + return; + } + + ads->nodes[ACPI_DEVICE_SWNODE_ROOT] = + SOFTWARE_NODE(buffer.pointer, ads->dev_props, NULL); + + for (i = 0; i < ads->num_ports; i++) { + struct acpi_device_software_node_port *port = &ads->ports[i]; + + if (port->crs_csi2_local) + init_port_csi2_local(device, port->port_nr); + else + init_port_csi2_remote(device, port->port_nr); + } + + ret = software_node_register_node_group(ads->nodeptrs); + if (ret < 0) { + acpi_handle_warn(handle, + "cannot register software nodes (%d)!\n", ret); + device->swnodes = NULL; + return; + } + + /* + * Note we can't use set_secondary_fwnode() here as the device's + * primary fwnode hasn't been set yet. + */ + primary = acpi_fwnode_handle(device); + primary->secondary = software_node_fwnode(ads->nodes); +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4f4f6b0db0a9..c21e5dedc5f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -449,10 +449,28 @@ static void acpi_free_power_resources_lists(struct acpi_device *device) } } +static void acpi_free_swnodes(struct acpi_device *device) +{ + struct acpi_device_software_nodes *ads = device->swnodes; + struct fwnode_handle *primary; + + if (!ads) + return; + + software_node_unregister_node_group(ads->nodeptrs); + primary = acpi_fwnode_handle(device); + primary->secondary = NULL; + kfree(ads->nodes[ACPI_DEVICE_SWNODE_ROOT].name); + kfree(ads); + + device->swnodes = NULL; +} + static void acpi_device_release(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); + acpi_free_swnodes(acpi_dev); acpi_free_properties(acpi_dev); acpi_free_pnp_ids(&acpi_dev->pnp); acpi_free_power_resources_lists(acpi_dev); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a05fe22c1175..e05d1c1f6ac2 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -360,15 +360,84 @@ struct acpi_device_data { struct acpi_gpio_mapping; +enum acpi_device_swnode_dev_props { + ACPI_DEVICE_SWNODE_DEV_NUM_OF, + ACPI_DEVICE_SWNODE_DEV_NUM_ENTRIES +}; + +enum acpi_device_swnode_port_props { + ACPI_DEVICE_SWNODE_PRT_REG, + ACPI_DEVICE_SWNODE_PRT_NUM_OF, + ACPI_DEVICE_SWNODE_PRT_NUM_ENTRIES +}; + +enum acpi_device_swnode_ep_props { + ACPI_DEVICE_SWNODE_EP_REMOTE_EP, + ACPI_DEVICE_SWNODE_EP_BUS_TYPE, + ACPI_DEVICE_SWNODE_EP_REG, + ACPI_DEVICE_SWNODE_EP_CLOCK_LANES, + ACPI_DEVICE_SWNODE_EP_DATA_LANES, + ACPI_DEVICE_SWNODE_EP_LANE_POLARITIES, + /* TX only */ + ACPI_DEVICE_SWNODE_EP_LINK_FREQUENCIES, + ACPI_DEVICE_SWNODE_EP_NUM_OF, + ACPI_DEVICE_SWNODE_EP_NUM_ENTRIES +}; + +#define ACPI_DEVICE_SWNODE_ROOT 0 +/* + * Each device has a root swnode plus two times as many nodes as the + * number of CSI-2 ports. + */ +#define ACPI_DEVICE_SWNODE_PRT(port) (1 + 2 * (port)) +#define ACPI_DEVICE_SWNODE_EP(endpoint) \ + (ACPI_DEVICE_SWNODE_PRT(endpoint) + 1) + +#define ACPI_DEVICE_SWNODE_CSI2_DATA_LANES 4 + +/** + * struct acpi_device_software_node_port: Software nodes for MIPI DisCo for + * Imaging support + * @port_name: the name of the port + * @data_lanes: "data-lanes" property values + * @lane_polarities: "lane-polarities" property values + * @link_frequencies: "link_frequencies" property values + * @port_nr: the number of the port + * @crs_crs2_local: whether the _CRS CSI2 record is local to the port (i.e. the + * port is a transmitter port) + * port_props: the port properties + * ep_props: the endpoint properties + * remote_ep_ref: reference to the remote endpoint + */ struct acpi_device_software_node_port { + char port_name[8]; + u32 data_lanes[ACPI_DEVICE_SWNODE_CSI2_DATA_LANES]; + u32 lane_polarities[1 /* clock lane */ + + ACPI_DEVICE_SWNODE_CSI2_DATA_LANES]; + u64 link_frequencies[4]; unsigned int port_nr; + bool crs_csi2_local; + + struct property_entry port_props[ACPI_DEVICE_SWNODE_PRT_NUM_ENTRIES]; + struct property_entry ep_props[ACPI_DEVICE_SWNODE_EP_NUM_ENTRIES]; + + struct software_node_ref_args remote_ep_ref[1]; }; +/** + * struct acpi_device_software_nodes - Software nodes for an ACPI device + * @ports: information related to each port and endpoint within a port + * @nodes: software nodes for root as well as ports and endpoints + * @nodeprts: array of software node pointers, for (un)registering them + * @num_ports: the number of ports + */ struct acpi_device_software_nodes { struct acpi_device_software_node_port *ports; struct software_node *nodes; const struct software_node **nodeptrs; unsigned int num_ports; + + struct property_entry dev_props[ACPI_DEVICE_SWNODE_DEV_NUM_ENTRIES]; }; /* Device */ @@ -377,6 +446,7 @@ struct acpi_device { int device_type; acpi_handle handle; /* no handle for fixed hardware */ struct fwnode_handle fwnode; + struct acpi_device_software_nodes *swnodes; struct list_head wakeup_list; struct list_head del_list; struct acpi_device_status status; From patchwork Tue Mar 28 10:01:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 668168 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BF502C77B6E for ; Tue, 28 Mar 2023 10:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230497AbjC1KCj (ORCPT ); Tue, 28 Mar 2023 06:02:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232854AbjC1KCO (ORCPT ); Tue, 28 Mar 2023 06:02:14 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 30CEA59D4; Tue, 28 Mar 2023 03:02:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997732; x=1711533732; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HB0FVEF2poQXTqGYDhbsHeqUzCIBYvqQG3DyPmHOE8Q=; b=iPr979hn6MmC/EhtL3rcvPKG1bdoBIbr05dEmAMtOgLDITrCoYnCeyCo zMwG0jRWCBfUIvBA6tCoBt5FzSVNVU7Kje6bkbK4d7y+jcfTebAZTwLeq YcDRFlnankEm3drIsl8PQt0XWengRugCi+lEQq75MJDGNbOQGmvcVZgO6 Wrntg9YaFagTYqoDtDWFzXoBPoYKGc3XdHl4lMaFl4H7ASixb/mgvBJaa vbGnYGXPed+fl8K6hjP5GsVamdmSVbVU0Xi9pa6kCzR7LXqrpO+BEoSI6 Ck1LDZi/XgyP1TeRZvlBJJp1po0+QVkb140FuUUgAtPYtmk1h86FrKiZR w==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324420007" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324420007" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078544" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078544" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:08 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id ED17511F937; Tue, 28 Mar 2023 13:02:05 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 06/10] ACPI: scan: Generate software nodes based on MIPI DisCo for Imaging Date: Tue, 28 Mar 2023 13:01:54 +0300 Message-Id: <20230328100159.1457160-7-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Generate software nodes for driver use, based on MIPI DisCo for Imaging definitions. During the (sub-)namespace walk, ACPI device nodes are created but the drivers aren't probed for the devices yet. A convenient way to determine which ACPI devices this applies to is to find a hierarchical data node that begins with "mipi-img-port-". These devices need software nodes that need to be present before probing, and can only be constructed once the related _CRS CSI2 records have been parsed. Signed-off-by: Sakari Ailus --- drivers/acpi/internal.h | 13 ++++++- drivers/acpi/mipi.c | 5 +-- drivers/acpi/power.c | 2 +- drivers/acpi/property.c | 48 +++++++++++++++-------- drivers/acpi/scan.c | 84 +++++++++++++++++++++++++++++++++-------- 5 files changed, 115 insertions(+), 37 deletions(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4723690d0117..afcd1dc3062c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -112,16 +112,22 @@ struct acpi_scan_context_csi2 { * struct acpi_scan_context - Context for scanning ACPI devices * @device: The first encountered device, typically the root of the scanned tree * @postponed_head: The list head of the postponed ACPI handles + * @mipi_img_head: The list of ACPI devices with MIPI DisCo for Imaging related + * properties * @csi2: Context for scanning _CRS CSI2 resource descriptors */ struct acpi_scan_context { struct acpi_device *device; struct list_head postponed_head; + struct list_head mipi_img_head; struct acpi_scan_context_csi2 csi2; }; +void acpi_bus_device_postpone(struct acpi_device *device, + struct list_head *head); void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, - int type, void (*release)(struct device *)); + int type, void (*release)(struct device *), + struct list_head *mipi_img_head); int acpi_tie_acpi_dev(struct acpi_device *adev); int acpi_device_add(struct acpi_device *device); int acpi_device_setup_files(struct acpi_device *dev); @@ -275,7 +281,8 @@ static inline bool force_storage_d3(void) -------------------------------------------------------------------------- */ #define ACPI_DT_NAMESPACE_HID "PRP0001" -void acpi_init_properties(struct acpi_device *adev); +void acpi_init_properties(struct acpi_device *adev, + struct list_head *mipi_img_head); void acpi_free_properties(struct acpi_device *adev); #ifdef CONFIG_X86 @@ -304,6 +311,8 @@ static inline void acpi_init_lpit(void) { } ACPI _CRS CSI2 and MIPI DisCo for Imaging conversion -------------------------------------------------------------------------- */ +#define MIPI_IMG_PORT_PREFIX "mipi-img-port-" + void acpi_crs_csi2_swnodes_del_free(void); void acpi_bus_scan_check_crs_csi2(acpi_handle handle, struct acpi_scan_context *ctx); void acpi_bus_scan_crs_csi2(struct acpi_scan_context_csi2 *ctx); diff --git a/drivers/acpi/mipi.c b/drivers/acpi/mipi.c index 5d05d899bede..315f076b9208 100644 --- a/drivers/acpi/mipi.c +++ b/drivers/acpi/mipi.c @@ -491,11 +491,10 @@ void acpi_bus_scan_crs_csi2(struct acpi_scan_context_csi2 *ctx) static struct fwnode_handle *get_mipi_port_handle(struct acpi_device *device, unsigned int port) { - static const char mipi_port_prefix[] = "mipi-img-port-"; - char mipi_port_name[sizeof(mipi_port_prefix) + 2]; + char mipi_port_name[sizeof(MIPI_IMG_PORT_PREFIX) + 2]; if (snprintf(mipi_port_name, sizeof(mipi_port_name), "%s%u", - mipi_port_prefix, port) >= sizeof(mipi_port_name)) { + MIPI_IMG_PORT_PREFIX, port) >= sizeof(mipi_port_name)) { acpi_handle_info(acpi_device_handle(device), "mipi port name too long for port %u\n", port); return NULL; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 23507d29f000..1096cdbf3d28 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -945,7 +945,7 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) device = &resource->device; acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER, - acpi_release_power_resource); + acpi_release_power_resource, NULL); mutex_init(&resource->resource_lock); INIT_LIST_HEAD(&resource->list_node); INIT_LIST_HEAD(&resource->dependents); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 08831ffba26c..1892787e73a6 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -62,10 +62,12 @@ static const guid_t buffer_prop_guid = GUID_INIT(0xedb12dd0, 0x363d, 0x4085, 0xa3, 0xd2, 0x49, 0x52, 0x2c, 0xa1, 0x60, 0xc4); -static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, +static bool acpi_enumerate_nondev_subnodes(struct acpi_device *device, + acpi_handle scope, union acpi_object *desc, struct acpi_device_data *data, - struct fwnode_handle *parent); + struct fwnode_handle *parent, + struct list_head *mipi_img_head); static bool acpi_extract_properties(acpi_handle handle, union acpi_object *desc, struct acpi_device_data *data); @@ -103,11 +105,12 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, */ status = acpi_get_parent(handle, &scope); if (ACPI_SUCCESS(status) - && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, - &dn->fwnode)) + && acpi_enumerate_nondev_subnodes(NULL, scope, desc, + &dn->data, &dn->fwnode, + NULL)) result = true; - } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data, - &dn->fwnode)) { + } else if (acpi_enumerate_nondev_subnodes(NULL, NULL, desc, &dn->data, + &dn->fwnode, NULL)) { result = true; } @@ -163,11 +166,14 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope, return acpi_nondev_subnode_data_ok(handle, link, list, parent); } -static bool acpi_add_nondev_subnodes(acpi_handle scope, +static bool acpi_add_nondev_subnodes(struct acpi_device *device, + acpi_handle scope, union acpi_object *links, struct list_head *list, - struct fwnode_handle *parent) + struct fwnode_handle *parent, + struct list_head *mipi_img_head) { + bool has_mipi_img_nodes = false; bool ret = false; int i; @@ -188,6 +194,13 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope, /* The second one may be a string, a reference or a package. */ switch (link->package.elements[1].type) { case ACPI_TYPE_STRING: + if (!has_mipi_img_nodes && mipi_img_head && + !strncmp(MIPI_IMG_PORT_PREFIX, + link->package.elements[0].string.pointer, + strlen(MIPI_IMG_PORT_PREFIX))) { + acpi_bus_device_postpone(device, mipi_img_head); + has_mipi_img_nodes = true; + } result = acpi_nondev_subnode_ok(scope, link, list, parent); break; @@ -211,10 +224,12 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope, return ret; } -static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, +static bool acpi_enumerate_nondev_subnodes(struct acpi_device *device, + acpi_handle scope, union acpi_object *desc, struct acpi_device_data *data, - struct fwnode_handle *parent) + struct fwnode_handle *parent, + struct list_head *mipi_img_head) { int i; @@ -238,8 +253,9 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, if (!guid_equal((guid_t *)guid->buffer.pointer, &ads_guid)) continue; - return acpi_add_nondev_subnodes(scope, links, &data->subnodes, - parent); + return acpi_add_nondev_subnodes(device, scope, links, + &data->subnodes, parent, + mipi_img_head); } return false; @@ -533,7 +549,8 @@ static bool acpi_extract_properties(acpi_handle scope, union acpi_object *desc, return !list_empty(&data->properties); } -void acpi_init_properties(struct acpi_device *adev) +void acpi_init_properties(struct acpi_device *adev, + struct list_head *mipi_img_head) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; struct acpi_hardware_id *hwid; @@ -567,8 +584,9 @@ void acpi_init_properties(struct acpi_device *adev) if (acpi_of) acpi_init_of_compatible(adev); } - if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, - &adev->data, acpi_fwnode_handle(adev))) + if (acpi_enumerate_nondev_subnodes(adev, adev->handle, buf.pointer, + &adev->data, acpi_fwnode_handle(adev), + mipi_img_head)) adev->data.pointer = buf.pointer; if (!adev->data.pointer) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c21e5dedc5f1..c54063caaaa2 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1774,7 +1774,8 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) } void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, - int type, void (*release)(struct device *)) + int type, void (*release)(struct device *), + struct list_head *mipi_img_head) { struct acpi_device *parent = acpi_find_parent_acpi_dev(handle); @@ -1788,7 +1789,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, acpi_set_device_status(device, ACPI_STA_DEFAULT); acpi_device_get_busid(device); acpi_set_pnp_ids(handle, &device->pnp, type); - acpi_init_properties(device); + acpi_init_properties(device, mipi_img_head); acpi_bus_get_flags(device); device->flags.match_driver = false; device->flags.initialized = true; @@ -1827,7 +1828,8 @@ static void acpi_scan_init_status(struct acpi_device *adev) } static int acpi_add_single_object(struct acpi_device **child, - acpi_handle handle, int type, bool dep_init) + acpi_handle handle, int type, bool dep_init, + struct list_head *mipi_img_head) { struct acpi_device *device; bool release_dep_lock = false; @@ -1837,7 +1839,9 @@ static int acpi_add_single_object(struct acpi_device **child, if (!device) return -ENOMEM; - acpi_init_device_object(device, handle, type, acpi_device_release); + acpi_init_device_object(device, handle, type, acpi_device_release, + mipi_img_head); + /* * Getting the status is delayed till here so that we can call * acpi_bus_get_status() and use its quirk handling. Note that @@ -2048,15 +2052,19 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) } /** - * struct acpi_postponed_handle - A postponed ACPI handle + * struct acpi_postponed_handle - A postponed ACPI handle or device * @handle: The postponed handle + * @device: The postponed device * @list: Entry in a postponed list * - * One such entry represents an ACPI handle the scanning of which has been - * postponed. + * One such entry represents an ACPI handle or an ACPI device the scanning of + * which has been postponed. */ struct acpi_postponed_handle { - acpi_handle handle; + union { + acpi_handle handle; + struct acpi_device *device; + }; struct list_head list; }; @@ -2068,8 +2076,7 @@ struct acpi_postponed_handle { * Add a given ACPI handle to a list of ACPI objects for which the creation * of the device objects is to be postponed. */ -static void acpi_bus_handle_postpone(acpi_handle handle, - struct list_head *head) +static void acpi_bus_handle_postpone(acpi_handle handle, struct list_head *head) { struct acpi_postponed_handle *ph; @@ -2081,6 +2088,27 @@ static void acpi_bus_handle_postpone(acpi_handle handle, list_add(&ph->list, head); } +/** + * acpi_bus_device_postpone - Add an ACPI device to a given postponed list + * @device: The ACPI device + * @head: Postponed list head + * + * Add a given ACPI device to a list of ACPI objects for which the creation + * of the device objects is to be postponed. + */ +void acpi_bus_device_postpone(struct acpi_device *device, + struct list_head *head) +{ + struct acpi_postponed_handle *ph; + + ph = kzalloc(sizeof(*ph), GFP_KERNEL); + if (!ph) + return; + + ph->device = device; + list_add(&ph->list, head); +} + static acpi_status acpi_bus_check_add(acpi_handle handle, bool first_pass, struct acpi_scan_context *ctx) { @@ -2132,7 +2160,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool first_pass, * If first_pass is true at this point, the device has no dependencies, * or the creation of the device object would have been postponed above. */ - acpi_add_single_object(&device, handle, type, !first_pass); + acpi_add_single_object(&device, handle, type, !first_pass, + &ctx->mipi_img_head); if (!device) return AE_CTRL_DEPTH; @@ -2485,6 +2514,7 @@ int acpi_bus_scan(acpi_handle handle) { struct acpi_scan_context ctx = { .postponed_head = LIST_HEAD_INIT(ctx.postponed_head), + .mipi_img_head = LIST_HEAD_INIT(ctx.mipi_img_head), .csi2.crs_csi2_head = LIST_HEAD_INIT(ctx.csi2.crs_csi2_head), }; struct acpi_postponed_handle *ph, *tmp_ph; @@ -2514,13 +2544,25 @@ int acpi_bus_scan(acpi_handle handle) /* Construct software nodes out of _CRS CSI2 records */ acpi_bus_scan_crs_csi2(&ctx.csi2); + /* + * Initialise software nodes for devices that have MIPI DisCo for + * Imaging related properties. + */ + list_for_each_entry_safe(ph, tmp_ph, &ctx.mipi_img_head, list) { + list_del(&ph->list); + acpi_init_swnodes(ph->device); + kfree(ph); + } + acpi_bus_attach(ctx.device, (void *)true); /* - * Proceed to register ACPI devices that were postponed due to _DEP - * objects during the namespace walk. + * Proceed to register ACPI devices that were postponed due to _CRS CSI2 + * resources or _DEP objects during the namespace walk. */ list_for_each_entry_safe(ph, tmp_ph, &ctx.postponed_head, list) { + struct acpi_postponed_handle *pm, *tmp_pm; + list_del(&ph->list); /* Set device NULL here to obtain the root for this sub-tree. */ ctx.device = NULL; @@ -2534,6 +2576,16 @@ int acpi_bus_scan(acpi_handle handle) acpi_walk_namespace(ACPI_TYPE_ANY, ph->handle, ACPI_UINT32_MAX, acpi_bus_check_add_2, NULL, (void *)&ctx, NULL); + /* + * Initialise software nodes for devices that have MIPI DisCo + * for Imaging related properties but which were postponed + * because of _DEP. + */ + list_for_each_entry_safe(pm, tmp_pm, &ctx.mipi_img_head, list) { + list_del(&pm->list); + acpi_init_swnodes(pm->device); + kfree(pm); + } if (ctx.device) acpi_bus_attach(ctx.device, NULL); kfree(ph); @@ -2594,7 +2646,7 @@ int acpi_bus_register_early_device(int type) struct acpi_device *device = NULL; int result; - result = acpi_add_single_object(&device, NULL, type, false); + result = acpi_add_single_object(&device, NULL, type, false, NULL); if (result) return result; @@ -2609,7 +2661,7 @@ static void acpi_bus_scan_fixed(void) struct acpi_device *adev = NULL; acpi_add_single_object(&adev, NULL, ACPI_BUS_TYPE_POWER_BUTTON, - false); + false, NULL); if (adev) { adev->flags.match_driver = true; if (device_attach(&adev->dev) >= 0) @@ -2623,7 +2675,7 @@ static void acpi_bus_scan_fixed(void) struct acpi_device *adev = NULL; acpi_add_single_object(&adev, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON, - false); + false, NULL); if (adev) { adev->flags.match_driver = true; if (device_attach(&adev->dev) < 0) From patchwork Tue Mar 28 10:01:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 667930 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A6651C77B6F for ; Tue, 28 Mar 2023 10:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230386AbjC1KCi (ORCPT ); Tue, 28 Mar 2023 06:02:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232873AbjC1KCO (ORCPT ); Tue, 28 Mar 2023 06:02:14 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E729D619C; Tue, 28 Mar 2023 03:02:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997734; x=1711533734; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=k2wXv6cEvPP8j8J/b9F7VttPHh08sa/YyVhSeBf27tE=; b=P7uT350ZDdQBzlEA2R/j6UTR1vsgdEYKmoMjv/5V3yJv3mLzi/gnGOGH LHcOl/O55EwFCn2Rn04tyU0BrQ2T4rxhfqnaawFMznhEgKPzC39zhuF36 xBe60qoVV+M1WUW+36IbLWn3ZNtcqe5KQ2yRm1Z4KOpP8vwpt93kTI5nE APEk2D3FsBGPlhFiKn105P/wFDzrF32UgZVMXAE40kFELY4EA845ix9O1 yt3COZOaHP2+mZJrBguwKbBGFsVvm8zCqbIKSyUGF6eRvRPggAd8hk2i1 47iRA6PpOQDJGDG+TF80sWixxqNdmOfQAa4784SnNczuuAbydTAg0Puu4 A==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324420015" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324420015" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078552" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078552" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:10 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id D3D9A122499; Tue, 28 Mar 2023 13:02:07 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 07/10] ACPI: property: Dig "rotation" property for devices with CSI2 _CRS Date: Tue, 28 Mar 2023 13:01:56 +0300 Message-Id: <20230328100159.1457160-9-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Dig "rotation" property value for devices with _CRS CSI2 resource descriptor. The value comes from _PLD (physical location of device) object, if it exists for the device. This way camera sensor drivers that know the "rotation" property do not need to care about _PLD on ACPI. Signed-off-by: Sakari Ailus --- drivers/acpi/mipi.c | 17 +++++++++++++++++ include/acpi/acpi_bus.h | 1 + 2 files changed, 18 insertions(+) diff --git a/drivers/acpi/mipi.c b/drivers/acpi/mipi.c index 315f076b9208..9f29bf231eaf 100644 --- a/drivers/acpi/mipi.c +++ b/drivers/acpi/mipi.c @@ -654,10 +654,12 @@ static void init_port_csi2_remote(struct acpi_device *device, */ void acpi_init_swnodes(struct acpi_device *device) { + struct fwnode_handle *fwnode = acpi_fwnode_handle(device); struct acpi_device_software_nodes *ads; struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER }; acpi_handle handle = acpi_device_handle(device); struct fwnode_handle *primary; + unsigned int prop_index = 0; acpi_status status; unsigned int i; int ret; @@ -666,6 +668,21 @@ void acpi_init_swnodes(struct acpi_device *device) if (!ads) return; + /* + * Check if "rotation" property exists and if it doesn't but there's a + * _PLD object, then get the rotation value from there. + */ + if (!fwnode_property_present(fwnode, "rotation")) { + struct acpi_pld_info *pld; + + status = acpi_get_physical_device_location(handle, &pld); + if (ACPI_SUCCESS(status)) { + ads->dev_props[NEXT_PROPERTY(prop_index, DEV_ROTATION)] = + PROPERTY_ENTRY_U32("rotation", pld->rotation * 45U); + kfree(pld); + } + } + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); if (ACPI_FAILURE(status)) { acpi_handle_warn(handle, "cannot get path name\n"); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e05d1c1f6ac2..f73e65a21b89 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -361,6 +361,7 @@ struct acpi_device_data { struct acpi_gpio_mapping; enum acpi_device_swnode_dev_props { + ACPI_DEVICE_SWNODE_DEV_ROTATION, ACPI_DEVICE_SWNODE_DEV_NUM_OF, ACPI_DEVICE_SWNODE_DEV_NUM_ENTRIES }; From patchwork Tue Mar 28 10:01:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 667927 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D37DC77B75 for ; Tue, 28 Mar 2023 10:03:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232392AbjC1KCm (ORCPT ); Tue, 28 Mar 2023 06:02:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53100 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232372AbjC1KCP (ORCPT ); Tue, 28 Mar 2023 06:02:15 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5D98A5FCB; Tue, 28 Mar 2023 03:02:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997734; x=1711533734; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vLL1m2QQXU8PS63Q2Za2fPq8nNvJPseI0J5KMCDCQJg=; b=QGTfDn26NVxH+C/n1OSQJbxS+BBljLUOKoSNSS19S8sTsCFJIOVivH+S 2T7ylsSpCBjM5tmaaAnMwyKXxeiSemQcTEq6ymm5CYlcQ6lZi/zLW7v7s Q1Isp4ViSBCVUwYwkWEqfjqS3fmCQmmO1w6Q0FsXLMR+HrxPuuN2dZ/Ln x8an4K4JZDRlnXPm7yBtIE/8J304SlPW2SK/+p9SmdT+sXAlSMErXZNmz xt8NivMRj6xPaoIxJmNMHLBuEMEK7bKi9oBaQFpWWM90lOxTBcilQC2Ya ZXfi4x0i3qZfGeYzHe/vNz+z5J/Cu0C4TtZhzjKfA2XNw1EhrpCzDq/YT g==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324420022" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324420022" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078557" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078557" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:11 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id CA26F12233C; Tue, 28 Mar 2023 13:02:08 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 08/10] ACPI: property: Rename parsed MIPI DisCo for Imaging properties Date: Tue, 28 Mar 2023 13:01:57 +0300 Message-Id: <20230328100159.1457160-10-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org MIPI DisCo for Imaging defines properties for sensor-adjacent devices such as EEPROM, LED flash or lens VCM as either device or sub-node references. This is compliant with existing DT definitions apart from property names. Rename parsed MIPI-defined properties so drivers will have a unified view of them as defined in DT and already parsed by drivers. This can be done in-place as the MIPI-defined property strings are always longer than the DT one. This also results in loss of constness in parser function arguments. Individual bindings to devices could define the references differently between MIPI DisCo for Imaging and DT, in terms of device or sub-node references. This will still need to be handled in the drivers themselves. Signed-off-by: Sakari Ailus --- drivers/acpi/internal.h | 1 + drivers/acpi/mipi.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/acpi/property.c | 22 ++++++++++++---------- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index afcd1dc3062c..bcacad73c5a7 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -317,5 +317,6 @@ void acpi_crs_csi2_swnodes_del_free(void); void acpi_bus_scan_check_crs_csi2(acpi_handle handle, struct acpi_scan_context *ctx); void acpi_bus_scan_crs_csi2(struct acpi_scan_context_csi2 *ctx); void acpi_init_swnodes(struct acpi_device *device); +void acpi_properties_prepare_mipi(union acpi_object *elements); #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/mipi.c b/drivers/acpi/mipi.c index 9f29bf231eaf..fcbef3677558 100644 --- a/drivers/acpi/mipi.c +++ b/drivers/acpi/mipi.c @@ -716,3 +716,39 @@ void acpi_init_swnodes(struct acpi_device *device) primary = acpi_fwnode_handle(device); primary->secondary = software_node_fwnode(ads->nodes); } + +static const struct mipi_disco_prop { + const char *mipi_prop; + const char *dt_prop; +} mipi_disco_props[] = { + { "mipi-img-lens-focus", "lens-focus" }, + { "mipi-img-flash-leds", "flash-leds" }, + { "mipi-img-clock-frequency", "clock-frequency" }, + { "mipi-img-led-max-current", "led-max-microamp" }, + { "mipi-img-flash-max-current", "flash-max-microamp" }, + { "mipi-img-flash-max-timeout", "flash-max-timeout-us" }, +}; + +/** + * acpi_properties_prepare_mipi - Rename MIPI properties as commin DT ones + * + * @elements: ACPI object containing _DSD properties for a device node + * + * Renames MIPI-defined properties as common DT ones. The pre-requisite is that + * the names of all such MIPI properties are no longer than the corresponding DT + * ones. + */ +void acpi_properties_prepare_mipi(union acpi_object *elements) +{ + char *e0 = elements[0].string.pointer; + unsigned int i; + + /* Replace MIPI DisCo for Imaging property names with DT equivalents. */ + for (i = 0; i < ARRAY_SIZE(mipi_disco_props); i++) { + if (!strcmp(mipi_disco_props[i].mipi_prop, e0)) { + WARN_ON(strscpy(e0, mipi_disco_props[i].dt_prop, + elements[0].string.length) < 0); + break; + } + } +} diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 1892787e73a6..541bda2c118f 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -127,7 +127,7 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, } static bool acpi_nondev_subnode_data_ok(acpi_handle handle, - const union acpi_object *link, + union acpi_object *link, struct list_head *list, struct fwnode_handle *parent) { @@ -148,7 +148,7 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle, } static bool acpi_nondev_subnode_ok(acpi_handle scope, - const union acpi_object *link, + union acpi_object *link, struct list_head *list, struct fwnode_handle *parent) { @@ -292,22 +292,24 @@ static bool acpi_property_value_ok(const union acpi_object *value) return false; } -static bool acpi_properties_format_valid(const union acpi_object *properties) +static bool acpi_properties_prepare(union acpi_object *properties) { - int i; + unsigned int i; for (i = 0; i < properties->package.count; i++) { - const union acpi_object *property; + union acpi_object *property = &properties->package.elements[i]; + union acpi_object *elements = property->package.elements; - property = &properties->package.elements[i]; /* * Only two elements allowed, the first one must be a string and * the second one has to satisfy certain conditions. */ - if (property->package.count != 2 - || property->package.elements[0].type != ACPI_TYPE_STRING - || !acpi_property_value_ok(&property->package.elements[1])) + if (property->package.count != 2 || + elements[0].type != ACPI_TYPE_STRING || + !acpi_property_value_ok(&elements[1])) return false; + + acpi_properties_prepare_mipi(elements); } return true; } @@ -539,7 +541,7 @@ static bool acpi_extract_properties(acpi_handle scope, union acpi_object *desc, * We found the matching GUID. Now validate the format of the * package immediately following it. */ - if (!acpi_properties_format_valid(properties)) + if (!acpi_properties_prepare(properties)) continue; acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer, From patchwork Tue Mar 28 10:01:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 667928 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B8CF1C77B78 for ; Tue, 28 Mar 2023 10:03:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232440AbjC1KCm (ORCPT ); Tue, 28 Mar 2023 06:02:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53060 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232893AbjC1KCP (ORCPT ); Tue, 28 Mar 2023 06:02:15 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 86E0A6588; Tue, 28 Mar 2023 03:02:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997734; x=1711533734; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5hkNgIaP0g/C3BTjHNqyHJHmBw3OxqK9Z0QZNFnAGY0=; b=XfLYGRadDRRq/cwNUcto5tal5d0CEqTWIjZtkU5afj0qBCbXEc0USOW2 iEPJC37lRNkuEvJFr2r9lm5Bz08hYKaKn0NiUstHVEKYyfO4xtJhwKrlB nyOW5OiOSE2z2kfi/2hAyfgSE2WAMrO02I2LJbuYEbAcUyS/WcibguDru vzgFSJAGY3URh1Z+kd5oPAJAdFs88Efw8wWJSUEcgeFdiwBLCbe+mq5AJ hOsDcuVXo/8tpeNPZGhaAu9/QG3j3QwRZ0fIsHrAvfqCOxg+jeXlYW1O1 bmyS3dscsABB87hRwt6hLH6dHZbN5GXt3kVfjkid3B/ufo+YRNJzOE/Z2 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324420025" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324420025" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:14 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078565" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078565" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:12 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id AEEFC120243; Tue, 28 Mar 2023 13:02:09 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 09/10] ACPI: property: Skip MIPI property table without "mipi-img" prefix Date: Tue, 28 Mar 2023 13:01:58 +0300 Message-Id: <20230328100159.1457160-11-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org For all _DSD properties, skip going through the MIPI DisCo for Imaging property name substitution table if the property doesn't have "mipi-img-" prefix. Signed-off-by: Sakari Ailus --- drivers/acpi/mipi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/acpi/mipi.c b/drivers/acpi/mipi.c index fcbef3677558..ae6bdc487363 100644 --- a/drivers/acpi/mipi.c +++ b/drivers/acpi/mipi.c @@ -717,6 +717,8 @@ void acpi_init_swnodes(struct acpi_device *device) primary->secondary = software_node_fwnode(ads->nodes); } +#define MIPI_IMG_PREFIX "mipi-img-" + static const struct mipi_disco_prop { const char *mipi_prop; const char *dt_prop; @@ -743,6 +745,9 @@ void acpi_properties_prepare_mipi(union acpi_object *elements) char *e0 = elements[0].string.pointer; unsigned int i; + if (!str_has_prefix(elements[0].string.pointer, MIPI_IMG_PREFIX)) + return; + /* Replace MIPI DisCo for Imaging property names with DT equivalents. */ for (i = 0; i < ARRAY_SIZE(mipi_disco_props); i++) { if (!strcmp(mipi_disco_props[i].mipi_prop, e0)) { From patchwork Tue Mar 28 10:01:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 667926 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 919B0C77B76 for ; Tue, 28 Mar 2023 10:03:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232480AbjC1KCm (ORCPT ); Tue, 28 Mar 2023 06:02:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53198 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230103AbjC1KCQ (ORCPT ); Tue, 28 Mar 2023 06:02:16 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CF70959DC; Tue, 28 Mar 2023 03:02:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679997735; x=1711533735; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=d41bXUASvUdMimuMBcCpF2HXIPKRE8fC9XN80/His4Q=; b=Xjb0+S/5L4QSDP71orMlm+Dcmmh1RetDB0LJSiJwXagnq5e7GoXIT7S0 4pYM1KnNiAy5KP3VYlJs7wJuZQdhWDpUVSiCHUNJnZApT9Phv8RDxc+Jj zPqVeVCpChh/RMBbX9s2pDt/c9OhF0VQWmJKzSVAdC5eFbivX3pumz8YR JF0MFCYbO4nqJDDh95WExiDJICpMKQEdBYUAZ/I+U4L1cVPkMnQEOh7NN O7ubcdJFP+PNffeBDai7kIkAVvpC7LusBt6m8kFXTMzCgZ+v2nySQjuG6 HNY+WlHzqgiSMH4RcI6jzJ70uW3JF9Lwi1VOXc7/6AwBpbl/vK9qXCZT0 Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="324420027" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="324420027" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:15 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10662"; a="753078570" X-IronPort-AV: E=Sophos;i="5.98,297,1673942400"; d="scan'208";a="753078570" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Mar 2023 03:02:13 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id CD29611F937; Tue, 28 Mar 2023 13:02:10 +0300 (EEST) From: Sakari Ailus To: linux-acpi@vger.kernel.org Cc: linux-media@vger.kernel.org, rafael@kernel.org, andriy.shevchenko@linux.intel.com, heikki.krogerus@linux.intel.com Subject: [PATCH v6 10/10] ACPI: property: Document _CRS CSI-2 and DisCo for Imaging support Date: Tue, 28 Mar 2023 13:01:59 +0300 Message-Id: <20230328100159.1457160-12-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> References: <20230328100159.1457160-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Document how ACPI _CRS CSI-2 and DisCo for Imaging works. It's non-trivial so such documentation can be useful. Signed-off-by: Sakari Ailus --- drivers/acpi/mipi.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/acpi/mipi.c b/drivers/acpi/mipi.c index ae6bdc487363..3800e6c9bc10 100644 --- a/drivers/acpi/mipi.c +++ b/drivers/acpi/mipi.c @@ -9,6 +9,43 @@ * Also see . * * Copyright (C) 2023 Intel Corporation + * + * _CRS CSI-2 descriptors, as defined starting from ACPI 6.4 [1], contain + * information on cross-device CSI-2 bus configuration. The descriptors are + * located under transmitter devices, and the receiver devices have no direct + * way to access them even if the information in these descriptors is equally + * important for receivers. This information is amended with MIPI DisCo for + * Imaging [2] specification that defines _DSD data nodes and properties. + * + * The support for these is based on two-fold approach, firstly renaming + * properties where semantics matches and secondly gathering information to + * generate properties using information gathered from various sources. The + * former is trivial (see acpi_properties_prepare_mipi() at the end of the + * file) whereas the latter requires a more elaborate explanation. + * + * acpi_bus_scan_crs_csi2() scans an ACPI bus for devices with _CRS CSI-2 + * descriptors and stores them to a linked list. This is done as traversing just + * this list is much smaller task than the entire DSDT. This list is then used + * to figure out how much memory is needed for swnodes related to a given ACPI + * device (handle). Further on, the same function sets the property values for + * the properties the values of which are obtained from the _CRS CSI-2 + * descriptor. The information is stored into another list where the information + * can be looked up based on device's acpi_handle as the struct acpi_device + * isn't available yet at this point (and could not, as cross-device references + * need to be set up before the devices are available for drivers to probe). + * + * For each struct acpi_device, acpi_init_swnodes() further obtains information + * required to find out the values for the rest of the properties needed by + * drivers. This includes all port and endpoint properties as the node + * structures used by DT graphs and DisCo for Imaging are different. Finally the + * function registers software nodes for the device and sets the secondary + * pointer for the ACPI device's fwnode. + * + * Access to data the structures is serialised using acpi_scan_lock in scan.c. + * + * [1] https://uefi.org/sites/default/files/resources/ACPI_Spec_6_4_Jan22.pdf + * + * [2] https://www.mipi.org/specifications/mipi-disco-imaging */ #include