From b087a940a27f00d2ae7434b2ccf9a876d5f3b046 Mon Sep 17 00:00:00 2001 From: Sugnan Prabhu S Date: Thu, 21 May 2020 20:41:03 +0530 Subject: drivers/intel/mipi_camera: Add camera power resource to SSDT This change adds support function to parse entries in the devicetree to generate PowerResource entries for the MIPI camera. Change-Id: I31e198b50acf2c64035aff9cb054fbe3602dd83e Signed-off-by: Sugnan Prabhu S Reviewed-on: https://review.coreboot.org/c/coreboot/+/41624 Reviewed-by: Rizwan Qureshi Reviewed-by: Tim Wawrzynczak Tested-by: build bot (Jenkins) --- src/drivers/intel/mipi_camera/camera.c | 98 ++++++++++++++++++++++++++++++++++ src/drivers/intel/mipi_camera/chip.h | 61 +++++++++++++++++++++ 2 files changed, 159 insertions(+) diff --git a/src/drivers/intel/mipi_camera/camera.c b/src/drivers/intel/mipi_camera/camera.c index 03e5ab65db..f32f744f8f 100644 --- a/src/drivers/intel/mipi_camera/camera.c +++ b/src/drivers/intel/mipi_camera/camera.c @@ -17,6 +17,7 @@ #define DEFAULT_REMOTE_NAME "\\_SB.PCI0.CIO2" #define CIO2_PCI_DEV 0x14 #define CIO2_PCI_FN 0x3 +#define POWER_RESOURCE_NAME "PRIC" /* * This implementation assumes there is only 1 endpoint at each end of every data port. It also @@ -435,6 +436,58 @@ static void camera_fill_vcm(const struct device *dev) acpi_dp_write(dsd); } +static void fill_power_res_sequence(struct drivers_intel_mipi_camera_config *config, + struct operation_seq *seq) +{ + unsigned int i; + uint8_t index; + uint8_t gpio_num; + + for (i = 0; i < seq->ops_cnt; i++) { + switch (seq->ops[i].type) { + case IMGCLK: + index = seq->ops[i].index; + if (seq->ops[i].action == ENABLE) { + acpigen_emit_namestring("MCON"); + acpigen_write_byte(config->clk_panel.clks[index].clknum); + acpigen_write_byte(config->clk_panel.clks[index].freq); + } else if (seq->ops[i].action == DISABLE) { + acpigen_emit_namestring("MCOF"); + acpigen_write_byte(config->clk_panel.clks[index].clknum); + } else { + acpigen_write_debug_string("Unsupported clock action"); + printk(BIOS_ERR, "Unsupported clock action: %x\n", + seq->ops[i].action); + printk(BIOS_ERR, "OS camera driver will likely not work"); + } + + break; + case GPIO: + index = seq->ops[i].index; + gpio_num = config->gpio_panel.gpio[index].gpio_num; + if (seq->ops[i].action == ENABLE) { + acpigen_soc_set_tx_gpio(gpio_num); + } else if (seq->ops[i].action == DISABLE) { + acpigen_soc_clear_tx_gpio(gpio_num); + } else { + acpigen_write_debug_string("Unsupported GPIO action"); + printk(BIOS_ERR, "Unsupported GPIO action: %x\n", + seq->ops[i].action); + printk(BIOS_ERR, "OS camera driver will likely not work"); + } + + break; + default: + printk(BIOS_ERR, "Unsupported power operation: %x\n", seq->ops[i].type); + printk(BIOS_ERR, "OS camera driver will likely not work"); + break; + } + + if (seq->ops[i].delay_ms) + acpigen_write_sleep(seq->ops[i].delay_ms); + } +} + static void write_pci_camera_device(const struct device *dev) { struct drivers_intel_mipi_camera_config *config = dev->chip_info; @@ -467,6 +520,40 @@ static void write_i2c_camera_device(const struct device *dev, const char *scope) acpigen_write_device(acpi_device_name(dev)); + /* add power resource */ + if (config->has_power_resource) { + acpigen_write_power_res(POWER_RESOURCE_NAME, 0, 0, NULL, 0); + acpigen_write_name_integer("STA", 0); + acpigen_write_STA_ext("STA"); + + acpigen_write_method_serialized("_ON", 0); + acpigen_write_if(); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_namestring("STA"); + acpigen_write_integer(0); + + fill_power_res_sequence(config, &config->on_seq); + + acpigen_write_store_op_to_namestr(1, "STA"); + acpigen_pop_len(); /* if */ + acpigen_pop_len(); /* _ON */ + + /* _OFF operations */ + acpigen_write_method_serialized("_OFF", 0); + acpigen_write_if(); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_namestring("STA"); + acpigen_write_integer(1); + + fill_power_res_sequence(config, &config->off_seq); + + acpigen_write_store_op_to_namestr(0, "STA"); + acpigen_pop_len(); /* if */ + acpigen_pop_len(); /* _ON */ + + acpigen_pop_len(); /* Power Resource */ + } + if (config->device_type == INTEL_ACPI_CAMERA_SENSOR) acpigen_write_name_integer("_ADR", 0); @@ -519,6 +606,17 @@ static void write_camera_device_common(const struct device *dev) acpigen_write_name_integer("CAMD", config->device_type); } + if (config->pr0 || config->has_power_resource) { + acpigen_write_name("_PR0"); + acpigen_write_package(1); + if (config->pr0) + acpigen_emit_namestring(config->pr0); /* External power resource */ + else + acpigen_emit_namestring(POWER_RESOURCE_NAME); + + acpigen_pop_len(); /* _PR0 */ + } + switch (config->device_type) { case INTEL_ACPI_CAMERA_CIO2: camera_fill_cio2(dev); diff --git a/src/drivers/intel/mipi_camera/chip.h b/src/drivers/intel/mipi_camera/chip.h index 92d3eac6cf..d133f7df86 100644 --- a/src/drivers/intel/mipi_camera/chip.h +++ b/src/drivers/intel/mipi_camera/chip.h @@ -10,6 +10,18 @@ #define MAX_PWDB_ENTRIES 12 #define MAX_PORT_ENTRIES 4 #define MAX_LINK_FREQ_ENTRIES 4 +#define MAX_CLK_CONFIGS 2 +#define MAX_GPIO_CONFIGS 4 +#define MAX_PWR_OPS 5 + +#define SEQ_OPS_CLK_ENABLE(ind, delay) \ + { .type = IMGCLK, .index = (ind), .action = ENABLE, .delay_ms = (delay) } +#define SEQ_OPS_CLK_DISABLE(ind, delay) \ + { .type = IMGCLK, .index = (ind), .action = DISABLE, .delay_ms = (delay) } +#define SEQ_OPS_GPIO_ENABLE(ind, delay) \ + { .type = GPIO, .index = (ind), .action = ENABLE, .delay_ms = (delay) } +#define SEQ_OPS_GPIO_DISABLE(ind, delay) \ + { .type = GPIO, .index = (ind), .action = DISABLE, .delay_ms = (delay) } enum camera_device_type { DEV_TYPE_SENSOR = 0, @@ -57,6 +69,47 @@ enum intel_power_action_type { INTEL_ACPI_CAMERA_GPIO, }; +enum ctrl_type { + IMGCLK = 1, + GPIO +}; + +enum action_type { + ENABLE = 1, + DISABLE +}; + +struct clk_config { + /* IMGCLKOUT_x being used for a port */ + uint8_t clknum; + /* frequency setting: 0:24Mhz, 1:19.2 Mhz */ + uint8_t freq; +} __packed; + +struct gpio_config { + uint8_t gpio_num; +} __packed; + +struct clock_ctrl_panel { + struct clk_config clks[MAX_CLK_CONFIGS]; +} __packed; + +struct gpio_ctrl_panel { + struct gpio_config gpio[MAX_GPIO_CONFIGS]; +} __packed; + +struct operation_type { + enum ctrl_type type; + uint8_t index; + enum action_type action; + uint32_t delay_ms; +} __packed; + +struct operation_seq { + struct operation_type ops[MAX_PWR_OPS]; + uint8_t ops_cnt; +} __packed; + struct intel_ssdb { uint8_t version; /* Current version */ uint8_t sensor_card_sku; /* CRD Board type */ @@ -122,6 +175,11 @@ struct intel_pwdb { } __packed; struct drivers_intel_mipi_camera_config { + struct clock_ctrl_panel clk_panel; + struct gpio_ctrl_panel gpio_panel; + struct operation_seq on_seq; + struct operation_seq off_seq; + struct intel_ssdb ssdb; struct intel_pwdb pwdb[MAX_PWDB_ENTRIES]; enum intel_camera_device_type device_type; @@ -130,6 +188,7 @@ struct drivers_intel_mipi_camera_config { const char *acpi_name; const char *chip_name; unsigned int acpi_uid; + const char *pr0; /* Settings specific to CIO2 device */ uint32_t cio2_num_ports; @@ -163,6 +222,8 @@ struct drivers_intel_mipi_camera_config { /* Settings specific to vcm */ const char *vcm_compat; + /* Does the device have a power resource entries */ + bool has_power_resource; }; #endif -- cgit v1.2.3