summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/intel/mipi_camera/camera.c363
-rw-r--r--src/drivers/intel/mipi_camera/chip.h26
2 files changed, 351 insertions, 38 deletions
diff --git a/src/drivers/intel/mipi_camera/camera.c b/src/drivers/intel/mipi_camera/camera.c
index f32f744f8f..51686d018e 100644
--- a/src/drivers/intel/mipi_camera/camera.c
+++ b/src/drivers/intel/mipi_camera/camera.c
@@ -18,6 +18,59 @@
#define CIO2_PCI_DEV 0x14
#define CIO2_PCI_FN 0x3
#define POWER_RESOURCE_NAME "PRIC"
+#define GUARD_VARIABLE_FORMAT "RES%1d"
+#define ENABLE_METHOD_FORMAT "ENB%1d"
+#define DISABLE_METHOD_FORMAT "DSB%1d"
+#define UNKNOWN_METHOD_FORMAT "UNK%1d"
+#define CLK_ENABLE_METHOD "MCON"
+#define CLK_DISABLE_METHOD "MCOF"
+
+static struct camera_resource_manager res_mgr;
+
+static void resource_set_action_type(struct resource_config *res_config,
+ enum action_type action)
+{
+ if (res_config)
+ res_config->action = action;
+}
+
+static enum action_type resource_get_action_type(const struct resource_config *res_config)
+{
+ return res_config ? res_config->action : UNKNOWN_ACTION;
+}
+
+static enum ctrl_type resource_get_ctrl_type(const struct resource_config *res_config)
+{
+ return res_config ? res_config->type : UNKNOWN_CTRL;
+}
+
+static void resource_set_clk_config(struct resource_config *res_config,
+ const struct clk_config *clk_conf)
+{
+ if (res_config) {
+ res_config->type = IMGCLK;
+ res_config->clk_conf = clk_conf;
+ }
+}
+
+static const struct clk_config *resource_clk_config(const struct resource_config *res_config)
+{
+ return res_config ? res_config->clk_conf : NULL;
+}
+
+static void resource_set_gpio_config(struct resource_config *res_config,
+ const struct gpio_config *gpio_conf)
+{
+ if (res_config) {
+ res_config->type = GPIO;
+ res_config->gpio_conf = gpio_conf;
+ }
+}
+
+static const struct gpio_config *resource_gpio_config(const struct resource_config *res_config)
+{
+ return res_config ? res_config->gpio_conf : NULL;
+}
/*
* This implementation assumes there is only 1 endpoint at each end of every data port. It also
@@ -436,53 +489,271 @@ 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)
+static int get_resource_index(const struct resource_config *res_config)
+{
+ enum ctrl_type type = resource_get_ctrl_type(res_config);
+ const struct clk_config *clk_config;
+ const struct gpio_config *gpio_config;
+ unsigned int i;
+ uint8_t res_id;
+
+ switch (type) {
+ case IMGCLK:
+ clk_config = resource_clk_config(res_config);
+ res_id = clk_config->clknum;
+ break;
+ case GPIO:
+ gpio_config = resource_gpio_config(res_config);
+ res_id = gpio_config->gpio_num;
+ break;
+ default:
+ printk(BIOS_ERR, "Unsupported power operation: %x\n"
+ "OS camera driver will likely not work", type);
+ return -1;
+ }
+
+ for (i = 0; i < res_mgr.cnt; i++)
+ if (res_mgr.resource[i].type == type && res_mgr.resource[i].id == res_id)
+ return i;
+
+ return -1;
+}
+
+static void add_guarded_method_namestring(struct resource_config *res_config, int res_index)
+{
+ char method_name[ACPI_NAME_BUFFER_SIZE];
+ enum action_type action = resource_get_action_type(res_config);
+
+ switch (action) {
+ case ENABLE:
+ snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
+ break;
+ case DISABLE:
+ snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
+ break;
+ default:
+ snprintf(method_name, sizeof(method_name), UNKNOWN_METHOD_FORMAT, res_index);
+ printk(BIOS_ERR, "Unsupported resource action: %x\n", action);
+ }
+
+ acpigen_emit_namestring(method_name);
+}
+
+static void call_guarded_method(struct resource_config *res_config)
+{
+ int res_index;
+
+ if (res_config == NULL)
+ return;
+
+ res_index = get_resource_index(res_config);
+
+ if (res_index != -1)
+ add_guarded_method_namestring(res_config, res_index);
+}
+
+static void add_clk_op(const struct clk_config *clk_config, enum action_type action)
+{
+ if (clk_config == NULL)
+ return;
+
+ switch (action) {
+ case ENABLE:
+ acpigen_write_if();
+ acpigen_emit_ext_op(COND_REFOF_OP);
+ acpigen_emit_string(CLK_ENABLE_METHOD);
+ acpigen_emit_namestring(CLK_ENABLE_METHOD);
+ acpigen_write_integer(clk_config->clknum);
+ acpigen_write_integer(clk_config->freq);
+ acpigen_pop_len(); /* CondRefOf */
+ break;
+ case DISABLE:
+ acpigen_write_if();
+ acpigen_emit_ext_op(COND_REFOF_OP);
+ acpigen_emit_string(CLK_DISABLE_METHOD);
+ acpigen_emit_namestring(CLK_DISABLE_METHOD);
+ acpigen_write_integer(clk_config->clknum);
+ acpigen_pop_len(); /* CondRefOf */
+ break;
+ default:
+ acpigen_write_debug_string("Unsupported clock action");
+ printk(BIOS_ERR, "Unsupported clock action: %x\n"
+ "OS camera driver will likely not work", action);
+ }
+}
+
+static void add_gpio_op(const struct gpio_config *gpio_config, enum action_type action)
+{
+ if (gpio_config == NULL)
+ return;
+
+ switch (action) {
+ case ENABLE:
+ acpigen_soc_set_tx_gpio(gpio_config->gpio_num);
+ break;
+ case DISABLE:
+ acpigen_soc_clear_tx_gpio(gpio_config->gpio_num);
+ break;
+ default:
+ acpigen_write_debug_string("Unsupported GPIO action");
+ printk(BIOS_ERR, "Unsupported GPIO action: %x\n"
+ "OS camera driver will likely not work\n", action);
+ }
+}
+
+static void add_power_operation(const struct resource_config *res_config)
+{
+ const struct clk_config *clk_config;
+ const struct gpio_config *gpio_config;
+ enum ctrl_type type = resource_get_ctrl_type(res_config);
+ enum action_type action = resource_get_action_type(res_config);
+
+ if (res_config == NULL)
+ return;
+
+ switch (type) {
+ case IMGCLK:
+ clk_config = resource_clk_config(res_config);
+ add_clk_op(clk_config, action);
+ break;
+ case GPIO:
+ gpio_config = resource_gpio_config(res_config);
+ add_gpio_op(gpio_config, action);
+ break;
+ default:
+ printk(BIOS_ERR, "Unsupported power operation: %x\n"
+ "OS camera driver will likely not work\n", type);
+ break;
+ }
+}
+
+static void write_guard_variable(uint8_t res_index)
+{
+ char varname[ACPI_NAME_BUFFER_SIZE];
+
+ snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
+ acpigen_write_name_integer(varname, 0);
+}
+
+static void write_enable_method(struct resource_config *res_config, uint8_t res_index)
+{
+ char method_name[ACPI_NAME_BUFFER_SIZE];
+ char varname[ACPI_NAME_BUFFER_SIZE];
+
+ snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
+
+ snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
+
+ acpigen_write_method_serialized(method_name, 0);
+ acpigen_write_if_lequal_namestr_int(varname, 0);
+ resource_set_action_type(res_config, ENABLE);
+ add_power_operation(res_config);
+ acpigen_pop_len(); /* if */
+
+ acpigen_emit_byte(INCREMENT_OP);
+ acpigen_emit_namestring(varname);
+ acpigen_pop_len(); /* method_name */
+}
+
+static void write_disable_method(struct resource_config *res_config, uint8_t res_index)
+{
+ char method_name[ACPI_NAME_BUFFER_SIZE];
+ char varname[ACPI_NAME_BUFFER_SIZE];
+
+ snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
+
+ snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
+
+ acpigen_write_method_serialized(method_name, 0);
+ acpigen_write_if();
+ acpigen_emit_byte(LGREATER_OP);
+ acpigen_emit_namestring(varname);
+ acpigen_write_integer(0x0);
+ acpigen_emit_byte(DECREMENT_OP);
+ acpigen_emit_namestring(varname);
+ acpigen_pop_len(); /* if */
+
+ acpigen_write_if_lequal_namestr_int(varname, 0);
+ resource_set_action_type(res_config, DISABLE);
+ add_power_operation(res_config);
+ acpigen_pop_len(); /* if */
+ acpigen_pop_len(); /* method_name */
+}
+
+static void add_guarded_operations(const struct drivers_intel_mipi_camera_config *config,
+ const struct operation_seq *seq)
{
unsigned int i;
uint8_t index;
- uint8_t gpio_num;
+ uint8_t res_id;
+ struct resource_config res_config;
+ int res_index;
- for (i = 0; i < seq->ops_cnt; i++) {
+ for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
+ index = seq->ops[i].index;
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");
- }
-
+ res_id = config->clk_panel.clks[index].clknum;
+ resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
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");
+ res_id = config->gpio_panel.gpio[index].gpio_num;
+ resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
+ break;
+ default:
+ printk(BIOS_ERR, "Unsupported power operation: %x\n"
+ "OS camera driver will likely not work\n",
+ seq->ops[i].type);
+ return;
+ }
+
+ res_index = get_resource_index(&res_config);
+
+ if (res_index == -1) {
+ if (res_mgr.cnt >= MAX_GUARDED_RESOURCES) {
+ printk(BIOS_ERR, "Unable to add guarded camera resource\n"
+ "OS camera driver will likely not work\n");
+ return;
}
+ res_mgr.resource[res_mgr.cnt].id = res_id;
+ res_mgr.resource[res_mgr.cnt].type = seq->ops[i].type;
+
+ write_guard_variable(res_mgr.cnt);
+ write_enable_method(&res_config, res_mgr.cnt);
+ write_disable_method(&res_config, res_mgr.cnt);
+
+ res_mgr.cnt++;
+ }
+ }
+}
+
+static void fill_power_res_sequence(struct drivers_intel_mipi_camera_config *config,
+ struct operation_seq *seq)
+{
+ struct resource_config res_config;
+ unsigned int i;
+ uint8_t index;
+
+ for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
+ index = seq->ops[i].index;
+
+ switch (seq->ops[i].type) {
+ case IMGCLK:
+ resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
break;
- default:
- printk(BIOS_ERR, "Unsupported power operation: %x\n", seq->ops[i].type);
- printk(BIOS_ERR, "OS camera driver will likely not work");
+ case GPIO:
+ resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
break;
+ default:
+ printk(BIOS_ERR, "Unsupported power operation: %x\n"
+ "OS camera driver will likely not work\n",
+ seq->ops[i].type);
+ return;
}
+ resource_set_action_type(&res_config, seq->ops[i].action);
+ call_guarded_method(&res_config);
if (seq->ops[i].delay_ms)
acpigen_write_sleep(seq->ops[i].delay_ms);
}
@@ -638,12 +909,32 @@ static void write_camera_device_common(const struct device *dev)
static void camera_fill_ssdt(const struct device *dev)
{
struct drivers_intel_mipi_camera_config *config = dev->chip_info;
- const char *scope = acpi_device_scope(dev);
+ const char *scope = NULL;
+ const struct device *pdev;
- if (!dev->enabled || !scope)
+ if (!dev->enabled)
return;
+ if (config->has_power_resource) {
+ pdev = dev->bus->dev;
+ if (!pdev || !pdev->enabled)
+ return;
+
+ scope = acpi_device_scope(pdev);
+ if (!scope)
+ return;
+
+ acpigen_write_scope(scope);
+ add_guarded_operations(config, &config->on_seq);
+ add_guarded_operations(config, &config->off_seq);
+ acpigen_pop_len(); /* Guarded power resource operations scope */
+ }
+
/* Device */
+ scope = acpi_device_scope(dev);
+ if (!scope)
+ return;
+
acpigen_write_scope(scope);
if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
@@ -669,7 +960,7 @@ static void camera_fill_ssdt(const struct device *dev)
static const char *camera_acpi_name(const struct device *dev)
{
const char *prefix = NULL;
- static char name[5];
+ static char name[ACPI_NAME_BUFFER_SIZE];
struct drivers_intel_mipi_camera_config *config = dev->chip_info;
if (config->acpi_name)
diff --git a/src/drivers/intel/mipi_camera/chip.h b/src/drivers/intel/mipi_camera/chip.h
index d133f7df86..d91e1e749d 100644
--- a/src/drivers/intel/mipi_camera/chip.h
+++ b/src/drivers/intel/mipi_camera/chip.h
@@ -13,6 +13,7 @@
#define MAX_CLK_CONFIGS 2
#define MAX_GPIO_CONFIGS 4
#define MAX_PWR_OPS 5
+#define MAX_GUARDED_RESOURCES 10
#define SEQ_OPS_CLK_ENABLE(ind, delay) \
{ .type = IMGCLK, .index = (ind), .action = ENABLE, .delay_ms = (delay) }
@@ -70,15 +71,36 @@ enum intel_power_action_type {
};
enum ctrl_type {
- IMGCLK = 1,
+ UNKNOWN_CTRL,
+ IMGCLK,
GPIO
};
enum action_type {
- ENABLE = 1,
+ UNKNOWN_ACTION,
+ ENABLE,
DISABLE
};
+struct camera_resource {
+ uint8_t type;
+ uint8_t id;
+};
+
+struct camera_resource_manager {
+ uint8_t cnt;
+ struct camera_resource resource[MAX_GUARDED_RESOURCES];
+};
+
+struct resource_config {
+ enum action_type action;
+ enum ctrl_type type;
+ union {
+ const struct clk_config *clk_conf;
+ const struct gpio_config *gpio_conf;
+ };
+};
+
struct clk_config {
/* IMGCLKOUT_x being used for a port */
uint8_t clknum;