Skip to content

Commit 693c667

Browse files
committed
ACPI: scan: Extract _CRS CSI-2 connection information into swnodes
Use the connection information extracted from the _CRS CSI-2 resource descriptors for all devices that have them to populate port names and the "reg", "bus-type" and "remote-endpoint" properties in the software nodes representing the CSI-2 connection graph. Link: https://uefi.org/specs/ACPI/6.5/06_Device_Configuration.html#camera-serial-interface-csi-2-connection-resource-descriptor Co-developed-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
1 parent bd721b9 commit 693c667

File tree

2 files changed

+205
-1
lines changed

2 files changed

+205
-1
lines changed

drivers/acpi/mipi-disco-img.c

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <linux/slab.h>
2424
#include <linux/string.h>
2525

26+
#include <media/v4l2-fwnode.h>
27+
2628
#include "internal.h"
2729

2830
static LIST_HEAD(acpi_mipi_crs_csi2_list);
@@ -237,6 +239,142 @@ static void alloc_crs_csi2_swnodes(struct crs_csi2 *csi2)
237239
csi2->swnodes = swnodes;
238240
}
239241

242+
#define ACPI_CRS_CSI2_PHY_TYPE_C 0
243+
#define ACPI_CRS_CSI2_PHY_TYPE_D 1
244+
245+
static unsigned int next_csi2_port_index(struct acpi_device_software_nodes *swnodes,
246+
unsigned int port_nr)
247+
{
248+
unsigned int i;
249+
250+
for (i = 0; i < swnodes->num_ports; i++) {
251+
struct acpi_device_software_node_port *port = &swnodes->ports[i];
252+
253+
if (port->port_nr == port_nr)
254+
return i;
255+
256+
if (port->port_nr == NO_CSI2_PORT) {
257+
port->port_nr = port_nr;
258+
return i;
259+
}
260+
}
261+
262+
return NO_CSI2_PORT;
263+
}
264+
265+
/* Print graph port name into a buffer, return non-zero on failure. */
266+
#define GRAPH_PORT_NAME(var, num) \
267+
(snprintf((var), sizeof(var), SWNODE_GRAPH_PORT_NAME_FMT, (num)) >= \
268+
sizeof(var))
269+
270+
static void extract_crs_csi2_conn_info(acpi_handle local_handle,
271+
struct acpi_device_software_nodes *local_swnodes,
272+
struct crs_csi2_connection *conn)
273+
{
274+
struct crs_csi2 *remote_csi2 = acpi_mipi_get_crs_csi2(conn->remote_handle);
275+
struct acpi_device_software_nodes *remote_swnodes;
276+
struct acpi_device_software_node_port *local_port, *remote_port;
277+
struct software_node *local_node, *remote_node;
278+
unsigned int local_index, remote_index;
279+
unsigned int bus_type;
280+
281+
/*
282+
* If the previous steps have failed to make room for a _CRS CSI-2
283+
* representation for the remote end of the given connection, skip it.
284+
*/
285+
if (!remote_csi2)
286+
return;
287+
288+
remote_swnodes = remote_csi2->swnodes;
289+
if (!remote_swnodes)
290+
return;
291+
292+
switch (conn->csi2_data.phy_type) {
293+
case ACPI_CRS_CSI2_PHY_TYPE_C:
294+
bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_CPHY;
295+
break;
296+
297+
case ACPI_CRS_CSI2_PHY_TYPE_D:
298+
bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_DPHY;
299+
break;
300+
301+
default:
302+
acpi_handle_info(local_handle, "unknown CSI-2 PHY type %u\n",
303+
conn->csi2_data.phy_type);
304+
return;
305+
}
306+
307+
local_index = next_csi2_port_index(local_swnodes,
308+
conn->csi2_data.local_port_instance);
309+
if (WARN_ON_ONCE(local_index >= local_swnodes->num_ports))
310+
return;
311+
312+
remote_index = next_csi2_port_index(remote_swnodes,
313+
conn->csi2_data.resource_source.index);
314+
if (WARN_ON_ONCE(remote_index >= remote_swnodes->num_ports))
315+
return;
316+
317+
local_port = &local_swnodes->ports[local_index];
318+
local_node = &local_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(local_index)];
319+
local_port->crs_csi2_local = true;
320+
321+
remote_port = &remote_swnodes->ports[remote_index];
322+
remote_node = &remote_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(remote_index)];
323+
324+
local_port->remote_ep[0] = SOFTWARE_NODE_REFERENCE(remote_node);
325+
remote_port->remote_ep[0] = SOFTWARE_NODE_REFERENCE(local_node);
326+
327+
local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] =
328+
PROPERTY_ENTRY_REF_ARRAY("remote-endpoint",
329+
local_port->remote_ep);
330+
331+
local_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] =
332+
PROPERTY_ENTRY_U32("bus-type", bus_type);
333+
334+
local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] =
335+
PROPERTY_ENTRY_U32("reg", 0);
336+
337+
local_port->port_props[ACPI_DEVICE_SWNODE_PORT_REG] =
338+
PROPERTY_ENTRY_U32("reg", conn->csi2_data.local_port_instance);
339+
340+
if (GRAPH_PORT_NAME(local_port->port_name,
341+
conn->csi2_data.local_port_instance))
342+
acpi_handle_info(local_handle, "local port %u name too long",
343+
conn->csi2_data.local_port_instance);
344+
345+
remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] =
346+
PROPERTY_ENTRY_REF_ARRAY("remote-endpoint",
347+
remote_port->remote_ep);
348+
349+
remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] =
350+
PROPERTY_ENTRY_U32("bus-type", bus_type);
351+
352+
remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] =
353+
PROPERTY_ENTRY_U32("reg", 0);
354+
355+
remote_port->port_props[ACPI_DEVICE_SWNODE_PORT_REG] =
356+
PROPERTY_ENTRY_U32("reg", conn->csi2_data.resource_source.index);
357+
358+
if (GRAPH_PORT_NAME(remote_port->port_name,
359+
conn->csi2_data.resource_source.index))
360+
acpi_handle_info(local_handle, "remote port %u name too long",
361+
conn->csi2_data.resource_source.index);
362+
}
363+
364+
static void prepare_crs_csi2_swnodes(struct crs_csi2 *csi2)
365+
{
366+
struct acpi_device_software_nodes *local_swnodes = csi2->swnodes;
367+
acpi_handle local_handle = csi2->handle;
368+
struct crs_csi2_connection *conn;
369+
370+
/* Bail out if the allocation of swnodes has failed. */
371+
if (!local_swnodes)
372+
return;
373+
374+
list_for_each_entry(conn, &csi2->connections, entry)
375+
extract_crs_csi2_conn_info(local_handle, local_swnodes, conn);
376+
}
377+
240378
/**
241379
* acpi_mipi_scan_crs_csi2 - Create ACPI _CRS CSI-2 software nodes
242380
*
@@ -275,9 +413,22 @@ void acpi_mipi_scan_crs_csi2(void)
275413
}
276414
list_splice(&aux_list, &acpi_mipi_crs_csi2_list);
277415

278-
/* Allocate software nodes for representing the CSI-2 information. */
416+
/*
417+
* Allocate software nodes for representing the CSI-2 information.
418+
*
419+
* This needs to be done for all of the list entries in one go, because
420+
* they may point to each other without restrictions and the next step
421+
* relies on the availability of swnodes memory for each list entry.
422+
*/
279423
list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry)
280424
alloc_crs_csi2_swnodes(csi2);
425+
426+
/*
427+
* Set up software node properties using data from _CRS CSI-2 resource
428+
* descriptors.
429+
*/
430+
list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry)
431+
prepare_crs_csi2_swnodes(csi2);
281432
}
282433

283434
/**

include/acpi/acpi_bus.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,61 @@ struct acpi_device_data {
366366

367367
struct acpi_gpio_mapping;
368368

369+
#define ACPI_DEVICE_CSI2_DATA_LANES 8
370+
371+
#define ACPI_DEVICE_SWNODE_PORT_NAME_LENGTH 8
372+
373+
enum acpi_device_swnode_port_props {
374+
ACPI_DEVICE_SWNODE_PORT_REG,
375+
ACPI_DEVICE_SWNODE_PORT_NUM_OF,
376+
ACPI_DEVICE_SWNODE_PORT_NUM_ENTRIES
377+
};
378+
379+
enum acpi_device_swnode_ep_props {
380+
ACPI_DEVICE_SWNODE_EP_REMOTE_EP,
381+
ACPI_DEVICE_SWNODE_EP_BUS_TYPE,
382+
ACPI_DEVICE_SWNODE_EP_REG,
383+
ACPI_DEVICE_SWNODE_EP_CLOCK_LANES,
384+
ACPI_DEVICE_SWNODE_EP_DATA_LANES,
385+
ACPI_DEVICE_SWNODE_EP_LANE_POLARITIES,
386+
/* TX only */
387+
ACPI_DEVICE_SWNODE_EP_LINK_FREQUENCIES,
388+
ACPI_DEVICE_SWNODE_EP_NUM_OF,
389+
ACPI_DEVICE_SWNODE_EP_NUM_ENTRIES
390+
};
391+
392+
/*
393+
* Each device has a root software node plus two times as many nodes as the
394+
* number of CSI-2 ports.
395+
*/
396+
#define ACPI_DEVICE_SWNODE_PORT(port) (2 * (port) + 1)
397+
#define ACPI_DEVICE_SWNODE_EP(endpoint) \
398+
(ACPI_DEVICE_SWNODE_PORT(endpoint) + 1)
399+
400+
/**
401+
* struct acpi_device_software_node_port - MIPI DisCo for Imaging CSI-2 port
402+
* @port_name: Port name.
403+
* @data_lanes: "data-lanes" property values.
404+
* @lane_polarities: "lane-polarities" property values.
405+
* @link_frequencies: "link_frequencies" property values.
406+
* @port_nr: Port number.
407+
* @crs_crs2_local: _CRS CSI2 record present (i.e. this is a transmitter one).
408+
* @port_props: Port properties.
409+
* @ep_props: Endpoint properties.
410+
* @remote_ep: Reference to the remote endpoint.
411+
*/
369412
struct acpi_device_software_node_port {
413+
char port_name[ACPI_DEVICE_SWNODE_PORT_NAME_LENGTH + 1];
414+
u32 data_lanes[ACPI_DEVICE_CSI2_DATA_LANES];
415+
u32 lane_polarities[ACPI_DEVICE_CSI2_DATA_LANES + 1 /* clock lane */];
416+
u64 link_frequencies[ACPI_DEVICE_CSI2_DATA_LANES];
370417
unsigned int port_nr;
418+
bool crs_csi2_local;
419+
420+
struct property_entry port_props[ACPI_DEVICE_SWNODE_PORT_NUM_ENTRIES];
421+
struct property_entry ep_props[ACPI_DEVICE_SWNODE_EP_NUM_ENTRIES];
422+
423+
struct software_node_ref_args remote_ep[1];
371424
};
372425

373426
/**

0 commit comments

Comments
 (0)