1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * MIPI DisCo for Imaging support. 4 * 5 * Copyright (C) 2023 Intel Corporation 6 * 7 * Support MIPI DisCo for Imaging by parsing ACPI _CRS CSI-2 records defined in 8 * Section 6.4.3.8.2.4 "Camera Serial Interface (CSI-2) Connection Resource 9 * Descriptor" of ACPI 6.5. 10 * 11 * The implementation looks for the information in the ACPI namespace (CSI-2 12 * resource descriptors in _CRS) and constructs software nodes compatible with 13 * Documentation/firmware-guide/acpi/dsd/graph.rst to represent the CSI-2 14 * connection graph. 15 */ 16 17 #include <linux/acpi.h> 18 #include <linux/limits.h> 19 #include <linux/list.h> 20 #include <linux/module.h> 21 #include <linux/overflow.h> 22 #include <linux/types.h> 23 #include <linux/slab.h> 24 #include <linux/string.h> 25 26 #include "internal.h" 27 28 static LIST_HEAD(acpi_mipi_crs_csi2_list); 29 30 static void acpi_mipi_data_tag(acpi_handle handle, void *context) 31 { 32 } 33 34 /* Connection data extracted from one _CRS CSI-2 resource descriptor. */ 35 struct crs_csi2_connection { 36 struct list_head entry; 37 struct acpi_resource_csi2_serialbus csi2_data; 38 acpi_handle remote_handle; 39 char remote_name[]; 40 }; 41 42 /* Data extracted from _CRS CSI-2 resource descriptors for one device. */ 43 struct crs_csi2 { 44 struct list_head entry; 45 acpi_handle handle; 46 struct acpi_device_software_nodes *swnodes; 47 struct list_head connections; 48 u32 port_count; 49 }; 50 51 struct csi2_resources_walk_data { 52 acpi_handle handle; 53 struct list_head connections; 54 }; 55 56 static acpi_status parse_csi2_resource(struct acpi_resource *res, void *context) 57 { 58 struct csi2_resources_walk_data *crwd = context; 59 struct acpi_resource_csi2_serialbus *csi2_res; 60 struct acpi_resource_source *csi2_res_src; 61 u16 csi2_res_src_length; 62 struct crs_csi2_connection *conn; 63 acpi_handle remote_handle; 64 65 if (res->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) 66 return AE_OK; 67 68 csi2_res = &res->data.csi2_serial_bus; 69 70 if (csi2_res->type != ACPI_RESOURCE_SERIAL_TYPE_CSI2) 71 return AE_OK; 72 73 csi2_res_src = &csi2_res->resource_source; 74 if (ACPI_FAILURE(acpi_get_handle(NULL, csi2_res_src->string_ptr, 75 &remote_handle))) { 76 acpi_handle_debug(crwd->handle, 77 "unable to find resource source\n"); 78 return AE_OK; 79 } 80 csi2_res_src_length = csi2_res_src->string_length; 81 if (!csi2_res_src_length) { 82 acpi_handle_debug(crwd->handle, 83 "invalid resource source string length\n"); 84 return AE_OK; 85 } 86 87 conn = kmalloc(struct_size(conn, remote_name, csi2_res_src_length + 1), 88 GFP_KERNEL); 89 if (!conn) 90 return AE_OK; 91 92 conn->csi2_data = *csi2_res; 93 strscpy(conn->remote_name, csi2_res_src->string_ptr, csi2_res_src_length); 94 conn->csi2_data.resource_source.string_ptr = conn->remote_name; 95 conn->remote_handle = remote_handle; 96 97 list_add(&conn->entry, &crwd->connections); 98 99 return AE_OK; 100 } 101 102 static struct crs_csi2 *acpi_mipi_add_crs_csi2(acpi_handle handle, 103 struct list_head *list) 104 { 105 struct crs_csi2 *csi2; 106 107 csi2 = kzalloc(sizeof(*csi2), GFP_KERNEL); 108 if (!csi2) 109 return NULL; 110 111 csi2->handle = handle; 112 INIT_LIST_HEAD(&csi2->connections); 113 csi2->port_count = 1; 114 115 if (ACPI_FAILURE(acpi_attach_data(handle, acpi_mipi_data_tag, csi2))) { 116 kfree(csi2); 117 return NULL; 118 } 119 120 list_add(&csi2->entry, list); 121 122 return csi2; 123 } 124 125 static struct crs_csi2 *acpi_mipi_get_crs_csi2(acpi_handle handle) 126 { 127 struct crs_csi2 *csi2; 128 129 if (ACPI_FAILURE(acpi_get_data_full(handle, acpi_mipi_data_tag, 130 (void **)&csi2, NULL))) 131 return NULL; 132 133 return csi2; 134 } 135 136 static void csi_csr2_release_connections(struct list_head *list) 137 { 138 struct crs_csi2_connection *conn, *conn_tmp; 139 140 list_for_each_entry_safe(conn, conn_tmp, list, entry) { 141 list_del(&conn->entry); 142 kfree(conn); 143 } 144 } 145 146 static void acpi_mipi_del_crs_csi2(struct crs_csi2 *csi2) 147 { 148 list_del(&csi2->entry); 149 acpi_detach_data(csi2->handle, acpi_mipi_data_tag); 150 kfree(csi2->swnodes); 151 csi_csr2_release_connections(&csi2->connections); 152 kfree(csi2); 153 } 154 155 /** 156 * acpi_mipi_check_crs_csi2 - Look for CSI-2 resources in _CRS 157 * @handle: Device object handle to evaluate _CRS for. 158 * 159 * Find all CSI-2 resource descriptors in the given device's _CRS 160 * and collect them into a list. 161 */ 162 void acpi_mipi_check_crs_csi2(acpi_handle handle) 163 { 164 struct csi2_resources_walk_data crwd = { 165 .handle = handle, 166 .connections = LIST_HEAD_INIT(crwd.connections), 167 }; 168 struct crs_csi2 *csi2; 169 170 /* 171 * Avoid allocating _CRS CSI-2 objects for devices without any CSI-2 172 * resource descriptions in _CRS to reduce overhead. 173 */ 174 acpi_walk_resources(handle, METHOD_NAME__CRS, parse_csi2_resource, &crwd); 175 if (list_empty(&crwd.connections)) 176 return; 177 178 /* 179 * Create a _CRS CSI-2 entry to store the extracted connection 180 * information and add it to the global list. 181 */ 182 csi2 = acpi_mipi_add_crs_csi2(handle, &acpi_mipi_crs_csi2_list); 183 if (!csi2) { 184 csi_csr2_release_connections(&crwd.connections); 185 return; /* Nothing really can be done about this. */ 186 } 187 188 list_replace(&crwd.connections, &csi2->connections); 189 } 190 191 #define NO_CSI2_PORT (UINT_MAX - 1) 192 193 static void alloc_crs_csi2_swnodes(struct crs_csi2 *csi2) 194 { 195 size_t port_count = csi2->port_count; 196 struct acpi_device_software_nodes *swnodes; 197 size_t alloc_size; 198 unsigned int i; 199 200 /* 201 * Allocate memory for ports, node pointers (number of nodes + 202 * 1 (guardian), nodes (root + number of ports * 2 (because for 203 * every port there is an endpoint)). 204 */ 205 if (check_mul_overflow(sizeof(*swnodes->ports) + 206 sizeof(*swnodes->nodes) * 2 + 207 sizeof(*swnodes->nodeptrs) * 2, 208 port_count, &alloc_size) || 209 check_add_overflow(sizeof(*swnodes) + 210 sizeof(*swnodes->nodes) + 211 sizeof(*swnodes->nodeptrs) * 2, 212 alloc_size, &alloc_size)) { 213 acpi_handle_info(csi2->handle, 214 "too many _CRS CSI-2 resource handles (%zu)", 215 port_count); 216 return; 217 } 218 219 swnodes = kmalloc(alloc_size, GFP_KERNEL); 220 if (!swnodes) 221 return; 222 223 swnodes->ports = (struct acpi_device_software_node_port *)(swnodes + 1); 224 swnodes->nodes = (struct software_node *)(swnodes->ports + port_count); 225 swnodes->nodeptrs = (const struct software_node **)(swnodes->nodes + 1 + 226 2 * port_count); 227 swnodes->num_ports = port_count; 228 229 for (i = 0; i < 2 * port_count + 1; i++) 230 swnodes->nodeptrs[i] = &swnodes->nodes[i]; 231 232 swnodes->nodeptrs[i] = NULL; 233 234 for (i = 0; i < port_count; i++) 235 swnodes->ports[i].port_nr = NO_CSI2_PORT; 236 237 csi2->swnodes = swnodes; 238 } 239 240 /** 241 * acpi_mipi_scan_crs_csi2 - Create ACPI _CRS CSI-2 software nodes 242 * 243 * Note that this function must be called before any struct acpi_device objects 244 * are bound to any ACPI drivers or scan handlers, so it cannot assume the 245 * existence of struct acpi_device objects for every device present in the ACPI 246 * namespace. 247 * 248 * acpi_scan_lock in scan.c must be held when calling this function. 249 */ 250 void acpi_mipi_scan_crs_csi2(void) 251 { 252 struct crs_csi2 *csi2; 253 LIST_HEAD(aux_list); 254 255 /* Count references to each ACPI handle in the CSI-2 connection graph. */ 256 list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry) { 257 struct crs_csi2_connection *conn; 258 259 list_for_each_entry(conn, &csi2->connections, entry) { 260 struct crs_csi2 *remote_csi2; 261 262 csi2->port_count++; 263 264 remote_csi2 = acpi_mipi_get_crs_csi2(conn->remote_handle); 265 if (remote_csi2) { 266 remote_csi2->port_count++; 267 continue; 268 } 269 /* 270 * The remote endpoint has no _CRS CSI-2 list entry yet, 271 * so create one for it and add it to the list. 272 */ 273 acpi_mipi_add_crs_csi2(conn->remote_handle, &aux_list); 274 } 275 } 276 list_splice(&aux_list, &acpi_mipi_crs_csi2_list); 277 278 /* Allocate software nodes for representing the CSI-2 information. */ 279 list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry) 280 alloc_crs_csi2_swnodes(csi2); 281 } 282 283 /** 284 * acpi_mipi_crs_csi2_cleanup - Free _CRS CSI-2 temporary data 285 */ 286 void acpi_mipi_crs_csi2_cleanup(void) 287 { 288 struct crs_csi2 *csi2, *csi2_tmp; 289 290 list_for_each_entry_safe(csi2, csi2_tmp, &acpi_mipi_crs_csi2_list, entry) 291 acpi_mipi_del_crs_csi2(csi2); 292 } 293