From b883954d842f57f6f349bbbdf3d4347db3a416dc Mon Sep 17 00:00:00 2001 From: Fernando Rimoli Date: Wed, 2 Sep 2026 16:23:20 +0200 Subject: [PATCH] media: ipu-bridge: Match sensor configs per IPU and add config flags Some sensors need different treatment depending on which IPU they are connected to, so the ACPI HID alone is not enough. Match on an optional list of IPU PCI product IDs. Entries for one HID must be adjacent, IPU-specific ones first, so the generic entry is skipped once a specific one has matched. Signed-off-by: Fernando Rimoli Tested-by: Jakob Berg Jespersen # Surface Pro 7+, IPU6 Tiger Lake Tested-by: Fil Dunsky # Surface Pro 8, IPU6 Tiger Lake (8086:9a19) Tested-by: Lucas Lis # Surface Pro 7+, IPU6 Tiger Lake (0x9a19) Tested-by: Kengo Oki # Surface Go 4, IPU6 Alder Lake-N 8086:462e Signed-off-by: Sakari Ailus --- drivers/media/pci/intel/ipu-bridge.c | 35 ++++++++++++++++++++++++++++ include/media/ipu-bridge.h | 26 +++++++++++++++++---- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c index 9cd864bcce34..3d4de959c890 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -893,8 +894,28 @@ static int ipu_bridge_connect_sensor(const struct ipu_sensor_config *cfg, return ret; } +/* + * Whether a sensor config applies to the IPU this bridge sits on. A config + * listing PCI product IDs only applies to those IPUs. + */ +static bool ipu_bridge_config_matches(const struct ipu_sensor_config *cfg, + struct ipu_bridge *bridge) +{ + const u16 *id; + + if (!cfg->pci_ids) + return true; + + for (id = cfg->pci_ids; *id; id++) + if (*id == bridge->pci_id) + return true; + + return false; +} + static int ipu_bridge_connect_sensors(struct ipu_bridge *bridge) { + const char *done_hid = NULL; unsigned int i; int ret; @@ -902,9 +923,22 @@ static int ipu_bridge_connect_sensors(struct ipu_bridge *bridge) const struct ipu_sensor_config *cfg = &ipu_supported_sensors[i]; + /* + * Entries for one HID are adjacent, IPU-specific ones first, + * so the generic entry is skipped once a specific one has + * matched and the sensor is not connected twice. + */ + if (done_hid && !strcmp(cfg->hid, done_hid)) + continue; + + if (!ipu_bridge_config_matches(cfg, bridge)) + continue; + ret = ipu_bridge_connect_sensor(cfg, bridge); if (ret) goto err_unregister_sensors; + + done_hid = cfg->hid; } return 0; @@ -1000,6 +1034,7 @@ int ipu_bridge_init(struct device *dev, sizeof(bridge->ipu_node_name)); bridge->ipu_hid_node.name = bridge->ipu_node_name; bridge->dev = dev; + bridge->pci_id = dev_is_pci(dev) ? to_pci_dev(dev)->device : 0; bridge->parse_sensor_fwnode = parse_sensor_fwnode; ret = software_node_register(&bridge->ipu_hid_node); diff --git a/include/media/ipu-bridge.h b/include/media/ipu-bridge.h index e8aeb23dc5a2..c562db794ca8 100644 --- a/include/media/ipu-bridge.h +++ b/include/media/ipu-bridge.h @@ -17,13 +17,24 @@ #define IPU_SENSOR_ROTATION_NORMAL 0 #define IPU_SENSOR_ROTATION_INVERTED 1 -#define IPU_SENSOR_CONFIG(_HID, _NR, ...) \ - (const struct ipu_sensor_config) { \ - .hid = _HID, \ - .nr_link_freqs = _NR, \ - .link_freqs = { __VA_ARGS__ } \ +/* + * Sensor config specific to one or more IPUs, identified by their PCI product + * IDs, with flags describing what the sensor needs there. Entries for one HID + * must be adjacent in ipu_supported_sensors[], with the IPU-specific ones + * before the generic one. + */ +#define IPU_SENSOR_CONFIG_MATCH_FL(_HID, _IDS, _FLAGS, _NR, ...) \ + (const struct ipu_sensor_config) { \ + .hid = _HID, \ + .pci_ids = _IDS, \ + .flags = _FLAGS, \ + .nr_link_freqs = _NR, \ + .link_freqs = { __VA_ARGS__ } \ } +#define IPU_SENSOR_CONFIG(_HID, _NR, ...) \ + IPU_SENSOR_CONFIG_MATCH_FL(_HID, NULL, 0, _NR, __VA_ARGS__) + #define NODE_SENSOR(_HID, _PROPS) \ (const struct software_node) { \ .name = _HID, \ @@ -132,6 +143,9 @@ struct ipu_node_names { struct ipu_sensor_config { const char *hid; + /* Zero-terminated list of IPU PCI product IDs, NULL for any IPU */ + const u16 *pci_ids; + const u32 flags; const u8 nr_link_freqs; const u64 link_freqs[MAX_NUM_LINK_FREQS]; }; @@ -177,6 +191,8 @@ typedef int (*ipu_parse_sensor_fwnode_t)(struct acpi_device *adev, struct ipu_bridge { struct device *dev; + /* PCI product ID of the IPU, 0 if it is not a PCI device */ + u16 pci_id; ipu_parse_sensor_fwnode_t parse_sensor_fwnode; char ipu_node_name[ACPI_ID_LEN]; struct software_node ipu_hid_node;