drivers/intel/mipi_camera: Add ACPI device type selection

Refactor the MIPI camera driver to support two ACPI device generation
modes via a Kconfig choice:

1. Windows/Linux mode (MIPI_ACPI_TYPE_WINDOWS_LINUX): Generates a
   single ACPI device for the camera sensor and any associated VCM or
   NVM devices on the same I2C bus. The IPU ACPI device is attached to
   the iGPU, not standalone. This is the preferred method for Windows
   and mainline Linux.

2. ChromeOS mode (MIPI_ACPI_TYPE_CHROMEOS): Generates separate ACPI
   devices for each camera component (sensor, CIO2, VCM, NVM). The IPU
   ACPI device is generated separately from the iGPU. This maintains
   compatibility with the existing ChromeOS-style setup.

The implementation uses runtime conditionals to select between the two
modes. Common helper functions are shared between modes, while device-
specific logic is conditional based on the selected ACPI type.

The default selection is MIPI_ACPI_TYPE_CHROMEOS for ChromeOS builds and
MIPI_ACPI_TYPE_WINDOWS_LINUX otherwise.

Change-Id: I0bc4894aff04d6b296011e85d790d624890da055
Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/90522
Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Alicja Michalska <ahplka19@gmail.com>
This commit is contained in:
Matt DeVillier 2025-12-15 17:41:27 -06:00
commit ae0d232402
2 changed files with 101 additions and 23 deletions

View file

@ -8,8 +8,36 @@ config DRIVERS_INTEL_MIPI_CAMERA
MIPI CSI I2C camera SSDT generator. Generates SSDB and PWDB
structures which are used by the Intel kernel drivers.
if DRIVERS_INTEL_MIPI_CAMERA
config DRIVERS_INTEL_MIPI_SUPPORTS_PRE_PRODUCTION_SOC
def_bool n
help
Use this config to provide information to IPU kernel driver
if pre-production or production signed IPU FW needs to be loaded.
choice
prompt "MIPI camera ACPI type"
default MIPI_ACPI_TYPE_CHROMEOS if CHROMEOS
default MIPI_ACPI_TYPE_WINDOWS_LINUX
help
Select the ACPI device type to generate for the MIPI camera.
config MIPI_ACPI_TYPE_WINDOWS_LINUX
bool "Windows / Linux"
help
Generates a single ACPI device for the camera sensor and any
associated VCM or NVM devices on the same I2C bus, instead of
separate ACPI devices for each camera related device. The IPU
ACPI device is attached to the iGPU, not standalone. This is
the preferred method for Windows and mainline Linux.
config MIPI_ACPI_TYPE_CHROMEOS
bool "Chrome OS"
help
Generates separate ACPI devices for each camera related device.
The IPU ACPI device is generated separately from the iGPU.
This is the preferred method for ChromeOS.
endchoice
endif

View file

@ -513,27 +513,44 @@ static void camera_fill_ssdb_defaults(struct drivers_intel_mipi_camera_config *c
}
/*
* Adds settings for a camera sensor device (typically at "\_SB.PCI0.I2Cx.CAMy"). The drivers
* for Linux tends to expect the camera sensor device and any related nvram / vcm devices to be
* separate ACPI devices, while the drivers for Windows want all of these to be grouped
* together in the camera sensor ACPI device. This implementation tries to satisfy both,
* though the unfortunate tradeoff is that the same I2C address for nvram and vcm is advertised
* by multiple devices in ACPI (via "_CRS"). The Windows driver can use the "_DSM" method to
* disambiguate the I2C resources in the camera sensor ACPI device. Drivers for Windows
* typically query "SSDB" for configuration information (represented as a binary blob dump of
* struct), while Linux drivers typically consult individual parameters in "_DSD".
* Adds settings for a camera sensor device (typically at "\_SB.PCI0.I2Cx.CAMy").
*
* Single ACPI device mode: The drivers for Windows and Linux want the sensor and any associated
* VCM or NVM devices to be grouped together in the camera sensor ACPI device. The OS driver
* uses the "_DSM" method to disambiguate the I2C resources in the camera sensor ACPI device.
* Drivers typically query "SSDB" for configuration information (represented as a binary blob
* dump of struct).
*
* Multi ACPI device mode: The drivers for ChromeOS expect the camera sensor device and any
* related nvram / vcm devices to be separate ACPI devices.
*
* The tree of tables in "_DSD" is analogous to what's used for the "CIO2" device. The _DSD
* specifies a child table for the sensor's port (e.g., PRT0 for "port0"--this implementation
* assumes a camera only has 1 port). The PRT0 table specifies a table for each endpoint
* (though only 1 endpoint is supported by this implementation so the table only has an
* "endpoint0" that points to a EP00 table). The EP00 table primarily describes the # of lanes
* in "data-lines", a list of frequencies in "list-frequencies", and specifies the name of the
* in "data-lanes", a list of frequencies in "list-frequencies", and specifies the name of the
* other side in "remote-endpoint" (typically "\_SB.PCI0.CIO2").
*/
static void camera_fill_sensor(const struct device *dev)
{
struct drivers_intel_mipi_camera_config *config = dev->chip_info;
camera_generate_pld(dev);
camera_fill_ssdb_defaults(config);
/* _DSM */
camera_generate_dsm(dev);
if (CONFIG(MIPI_ACPI_TYPE_WINDOWS_LINUX)) {
acpigen_write_method_serialized("SSDB", 0);
acpigen_write_return_byte_buffer((uint8_t *)&config->ssdb, sizeof(config->ssdb));
acpigen_pop_len(); /* Method */
return;
}
/* Multi-device mode: add _DSD with endpoint information */
struct acpi_dp *ep00 = NULL;
struct acpi_dp *prt0 = NULL;
struct acpi_dp *dsd = NULL;
@ -543,13 +560,6 @@ static void camera_fill_sensor(const struct device *dev)
const char *remote_name;
struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
camera_generate_pld(dev);
camera_fill_ssdb_defaults(config);
/* _DSM */
camera_generate_dsm(dev);
ep00 = acpi_dp_new_table("EP00");
acpi_dp_add_integer(ep00, "endpoint", DEFAULT_ENDPOINT);
acpi_dp_add_integer(ep00, "clock-lanes", 0);
@ -1035,7 +1045,10 @@ static void write_i2c_camera_device(const struct device *dev, const char *scope)
acpigen_write_name_integer("_ADR", 0);
acpigen_write_name_integer("_UID", config->acpi_uid);
acpigen_write_name_string("_DDN", config->chip_name);
if (CONFIG(MIPI_ACPI_TYPE_WINDOWS_LINUX))
acpigen_write_name_string("_DDN", config->sensor_name);
else
acpigen_write_name_string("_DDN", config->chip_name);
acpigen_write_STA(acpi_device_status(dev));
acpigen_write_method("_DSC", 0);
acpigen_write_return_integer(config->max_dstate_for_probe);
@ -1071,11 +1084,12 @@ static void write_camera_device_common(const struct device *dev)
{
struct drivers_intel_mipi_camera_config *config = dev->chip_info;
/* Mark it as Camera related device */
if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
config->device_type == INTEL_ACPI_CAMERA_IMGU ||
config->device_type == INTEL_ACPI_CAMERA_SENSOR ||
config->device_type == INTEL_ACPI_CAMERA_VCM) {
/* Mark it as Camera related device (multi-device mode only) */
if (CONFIG(MIPI_ACPI_TYPE_CHROMEOS) &&
(config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
config->device_type == INTEL_ACPI_CAMERA_IMGU ||
config->device_type == INTEL_ACPI_CAMERA_SENSOR ||
config->device_type == INTEL_ACPI_CAMERA_VCM)) {
acpigen_write_name_integer("CAMD", config->device_type);
}
@ -1114,6 +1128,36 @@ static void camera_fill_ssdt(const struct device *dev)
const char *scope = NULL;
const struct device *pdev = dev->upstream->dev;
if (CONFIG(MIPI_ACPI_TYPE_WINDOWS_LINUX)) {
/* Only generate SSDT for an i2c-attached sensor device */
if (dev->path.type != DEVICE_PATH_I2C || config->device_type != INTEL_ACPI_CAMERA_SENSOR)
return;
scope = acpi_device_scope(dev);
if (!scope) {
printk(BIOS_ERR, "Failed to get scope for device %s\n", dev_path(dev));
return;
}
acpigen_write_scope(scope);
if (config->has_power_resource && pdev && pdev->enabled) {
add_guarded_operations(config, &config->on_seq);
add_guarded_operations(config, &config->off_seq);
}
write_i2c_camera_device(dev, scope);
write_camera_device_common(dev);
acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
printk(BIOS_INFO, "%s: %s at I2C 0x%02x\n", acpi_device_path(dev),
dev->chip_ops->name, dev->path.i2c.device);
return;
}
/* Multi-device mode */
if (config->has_power_resource) {
if (!pdev || !pdev->enabled)
return;
@ -1175,6 +1219,12 @@ static const char *camera_acpi_name(const struct device *dev)
if (config->acpi_name)
return config->acpi_name;
if (CONFIG(MIPI_ACPI_TYPE_WINDOWS_LINUX)) {
snprintf(name, sizeof(name), "CAM%1u", config->acpi_uid);
return name;
}
/* Multi-device mode */
switch (config->device_type) {
case INTEL_ACPI_CAMERA_CIO2:
return "CIO2";