// SPDX-License-Identifier: GPL-2.0-only /* * MIPI DisCo for Imaging support. * * Copyright (C) 2023 Intel Corporation * * Support MIPI DisCo for Imaging by parsing ACPI _CRS CSI-2 records defined in * Section 6.4.3.8.2.4 "Camera Serial Interface (CSI-2) Connection Resource * Descriptor" of ACPI 6.5 and using device properties defined by the MIPI DisCo * for Imaging specification. * * The implementation looks for the information in the ACPI namespace (CSI-2 * resource descriptors in _CRS) and constructs software nodes compatible with * Documentation/firmware-guide/acpi/dsd/graph.rst to represent the CSI-2 * connection graph. The software nodes are then populated with the data * extracted from the _CRS CSI-2 resource descriptors and the MIPI DisCo * for Imaging device properties present in _DSD for the ACPI device objects * with CSI-2 connections. */ #include <linux/acpi.h> #include <linux/dmi.h> #include <linux/limits.h> #include <linux/list.h> #include <linux/module.h> #include <linux/overflow.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/string.h> #include <media/v4l2-fwnode.h> #include "internal.h" static LIST_HEAD(acpi_mipi_crs_csi2_list); static void acpi_mipi_data_tag(acpi_handle handle, void *context) { … } /* Connection data extracted from one _CRS CSI-2 resource descriptor. */ struct crs_csi2_connection { … }; /* Data extracted from _CRS CSI-2 resource descriptors for one device. */ struct crs_csi2 { … }; struct csi2_resources_walk_data { … }; static acpi_status parse_csi2_resource(struct acpi_resource *res, void *context) { … } static struct crs_csi2 *acpi_mipi_add_crs_csi2(acpi_handle handle, struct list_head *list) { … } static struct crs_csi2 *acpi_mipi_get_crs_csi2(acpi_handle handle) { … } static void csi_csr2_release_connections(struct list_head *list) { … } static void acpi_mipi_del_crs_csi2(struct crs_csi2 *csi2) { … } /** * acpi_mipi_check_crs_csi2 - Look for CSI-2 resources in _CRS * @handle: Device object handle to evaluate _CRS for. * * Find all CSI-2 resource descriptors in the given device's _CRS * and collect them into a list. */ void acpi_mipi_check_crs_csi2(acpi_handle handle) { … } #define NO_CSI2_PORT … static void alloc_crs_csi2_swnodes(struct crs_csi2 *csi2) { … } #define ACPI_CRS_CSI2_PHY_TYPE_C … #define ACPI_CRS_CSI2_PHY_TYPE_D … static unsigned int next_csi2_port_index(struct acpi_device_software_nodes *swnodes, unsigned int port_nr) { … } /* Print graph port name into a buffer, return non-zero on failure. */ #define GRAPH_PORT_NAME(var, num) … static void extract_crs_csi2_conn_info(acpi_handle local_handle, struct acpi_device_software_nodes *local_swnodes, struct crs_csi2_connection *conn) { … } static void prepare_crs_csi2_swnodes(struct crs_csi2 *csi2) { … } /** * acpi_mipi_scan_crs_csi2 - Create ACPI _CRS CSI-2 software nodes * * Note that this function must be called before any struct acpi_device objects * are bound to any ACPI drivers or scan handlers, so it cannot assume the * existence of struct acpi_device objects for every device present in the ACPI * namespace. * * acpi_scan_lock in scan.c must be held when calling this function. */ void acpi_mipi_scan_crs_csi2(void) { … } /* * Get the index of the next property in the property array, with a given * maximum value. */ #define NEXT_PROPERTY(index, max) … static void init_csi2_port_local(struct acpi_device *adev, struct acpi_device_software_node_port *port, struct fwnode_handle *port_fwnode, unsigned int index) { … } static void init_csi2_port(struct acpi_device *adev, struct acpi_device_software_nodes *swnodes, struct acpi_device_software_node_port *port, struct fwnode_handle *port_fwnode, unsigned int port_index) { … } #define MIPI_IMG_PORT_PREFIX … static struct fwnode_handle *get_mipi_port_handle(struct fwnode_handle *adev_fwnode, unsigned int port_nr) { … } static void init_crs_csi2_swnodes(struct crs_csi2 *csi2) { … } /** * acpi_mipi_init_crs_csi2_swnodes - Initialize _CRS CSI-2 software nodes * * Use MIPI DisCo for Imaging device properties to finalize the initialization * of CSI-2 software nodes for all ACPI device objects that have been already * enumerated. */ void acpi_mipi_init_crs_csi2_swnodes(void) { … } /** * acpi_mipi_crs_csi2_cleanup - Free _CRS CSI-2 temporary data */ void acpi_mipi_crs_csi2_cleanup(void) { … } #ifdef CONFIG_X86 #include <asm/cpu_device_id.h> #include <asm/intel-family.h> /* CPU matches for Dell generations with broken ACPI MIPI DISCO info */ static const struct x86_cpu_id dell_broken_mipi_disco_cpu_gens[] = …; static const char *strnext(const char *s1, const char *s2) { … } /** * acpi_graph_ignore_port - Tell whether a port node should be ignored * @handle: The ACPI handle of the node (which may be a port node) * * Return: true if a port node should be ignored and the data to that should * come from other sources instead (Windows ACPI definitions and * ipu-bridge). This is currently used to ignore bad port nodes related to IPU6 * ("IPU?") and camera sensor devices ("LNK?") in certain Dell systems with * Intel VSC. */ bool acpi_graph_ignore_port(acpi_handle handle) { … } #endif