diff --git a/src/drivers/intel/mipi_camera/Kconfig b/src/drivers/intel/mipi_camera/Kconfig index 88c97bd0de..6bf307a581 100644 --- a/src/drivers/intel/mipi_camera/Kconfig +++ b/src/drivers/intel/mipi_camera/Kconfig @@ -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 diff --git a/src/drivers/intel/mipi_camera/camera.c b/src/drivers/intel/mipi_camera/camera.c index 472537c8e6..e4365d1b36 100644 --- a/src/drivers/intel/mipi_camera/camera.c +++ b/src/drivers/intel/mipi_camera/camera.c @@ -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";