blob: ec79e39a60b66ebe16ae3613fcf67bb2a73da01b [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
V Sowmya9f8023a2017-02-28 17:52:05 +05302
Matt Delco879b3c12020-06-17 13:10:22 +05303#include <stdlib.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07004#include <acpi/acpi.h>
5#include <acpi/acpi_device.h>
6#include <acpi/acpigen.h>
Tim Wawrzynczakd40a4c22021-02-25 13:14:49 -07007#include <acpi/acpigen_pci.h>
V Sowmya9f8023a2017-02-28 17:52:05 +05308#include <console/console.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02009#include <device/i2c_simple.h>
V Sowmya9f8023a2017-02-28 17:52:05 +053010#include <device/device.h>
11#include <device/path.h>
Matt Delco7d002932020-06-16 11:39:52 +053012#include <device/pci_def.h>
V Sowmya9f8023a2017-02-28 17:52:05 +053013#include "chip.h"
14
Matt Delco1245b1e2020-06-17 07:26:55 +053015#define SENSOR_NAME_UUID "822ace8f-2814-4174-a56b-5f029fe079ee"
16#define SENSOR_TYPE_UUID "26257549-9271-4ca4-bb43-c4899d5a4881"
17#define DEFAULT_ENDPOINT 0
Matt Delco879b3c12020-06-17 13:10:22 +053018#define DEFAULT_REMOTE_NAME "\\_SB.PCI0.CIO2"
19#define CIO2_PCI_DEV 0x14
20#define CIO2_PCI_FN 0x3
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +053021#define POWER_RESOURCE_NAME "PRIC"
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +053022#define GUARD_VARIABLE_FORMAT "RES%1d"
23#define ENABLE_METHOD_FORMAT "ENB%1d"
24#define DISABLE_METHOD_FORMAT "DSB%1d"
25#define UNKNOWN_METHOD_FORMAT "UNK%1d"
26#define CLK_ENABLE_METHOD "MCON"
27#define CLK_DISABLE_METHOD "MCOF"
28
29static struct camera_resource_manager res_mgr;
30
31static void resource_set_action_type(struct resource_config *res_config,
32 enum action_type action)
33{
34 if (res_config)
35 res_config->action = action;
36}
37
38static enum action_type resource_get_action_type(const struct resource_config *res_config)
39{
40 return res_config ? res_config->action : UNKNOWN_ACTION;
41}
42
43static enum ctrl_type resource_get_ctrl_type(const struct resource_config *res_config)
44{
45 return res_config ? res_config->type : UNKNOWN_CTRL;
46}
47
48static void resource_set_clk_config(struct resource_config *res_config,
49 const struct clk_config *clk_conf)
50{
51 if (res_config) {
52 res_config->type = IMGCLK;
53 res_config->clk_conf = clk_conf;
54 }
55}
56
57static const struct clk_config *resource_clk_config(const struct resource_config *res_config)
58{
59 return res_config ? res_config->clk_conf : NULL;
60}
61
62static void resource_set_gpio_config(struct resource_config *res_config,
63 const struct gpio_config *gpio_conf)
64{
65 if (res_config) {
66 res_config->type = GPIO;
67 res_config->gpio_conf = gpio_conf;
68 }
69}
70
71static const struct gpio_config *resource_gpio_config(const struct resource_config *res_config)
72{
73 return res_config ? res_config->gpio_conf : NULL;
74}
Matt Delco879b3c12020-06-17 13:10:22 +053075
76/*
77 * This implementation assumes there is only 1 endpoint at each end of every data port. It also
78 * assumes there are no clock lanes. It also assumes that any VCM or NVM for a CAM is on the
79 * same I2C bus as the CAM.
80 */
81
82/*
83 * Adds settings for a CIO2 device (typically at "\_SB.PCI0.CIO2"). A _DSD is added that
84 * specifies a child table for each port (e.g., PRT0 for "port0" and PRT1 for "port1"). Each
85 * PRTx table specifies a table for each endpoint (though only 1 endpoint is supported by this
86 * implementation so the table only has an "endpoint0" that points to a EPx0 table). The EPx0
87 * table primarily describes the # of lanes in "data-lines" and specifies the name of the other
88 * side in "remote-endpoint" (the name is usually of the form "\_SB.PCI0.I2Cx.CAM0" for the
89 * first port/cam and "\_SB.PCI0.I2Cx.CAM1" if there's a second port/cam).
90 */
91static void camera_fill_cio2(const struct device *dev)
92{
93 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
94 struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
95 char *ep_table_name[MAX_PORT_ENTRIES] = {NULL};
96 char *port_table_name[MAX_PORT_ENTRIES] = {NULL};
97 char *port_name[MAX_PORT_ENTRIES] = {NULL};
98 unsigned int i, j;
99 char name[BUS_PATH_MAX];
100 struct acpi_dp *ep_table = NULL;
101 struct acpi_dp *port_table = NULL;
102 struct acpi_dp *remote = NULL;
103 struct acpi_dp *lanes = NULL;
104
105 for (i = 0; i < config->cio2_num_ports && i < MAX_PORT_ENTRIES; ++i) {
106 snprintf(name, sizeof(name), "EP%u0", i);
107 ep_table_name[i] = strdup(name);
108 ep_table = acpi_dp_new_table(ep_table_name[i]);
109 acpi_dp_add_integer(ep_table, "endpoint", 0);
110 acpi_dp_add_integer(ep_table, "clock-lanes", 0);
111
112 if (config->cio2_lanes_used[i] > 0) {
113 lanes = acpi_dp_new_table("data-lanes");
114
115 for (j = 1; j <= config->cio2_lanes_used[i] &&
116 j <= MAX_PORT_ENTRIES; ++j)
117 acpi_dp_add_integer(lanes, NULL, j);
118 acpi_dp_add_array(ep_table, lanes);
119 }
120
121 if (config->cio2_lane_endpoint[i]) {
122 remote = acpi_dp_new_table("remote-endpoint");
123 acpi_dp_add_reference(remote, NULL, config->cio2_lane_endpoint[i]);
124 acpi_dp_add_integer(remote, NULL, 0);
125 acpi_dp_add_integer(remote, NULL, 0);
126 acpi_dp_add_array(ep_table, remote);
127 }
128
129 snprintf(name, sizeof(name), "PRT%u", i);
130 port_table_name[i] = strdup(name);
131 port_table = acpi_dp_new_table(port_table_name[i]);
132 acpi_dp_add_integer(port_table, "port", config->cio2_prt[i]);
133 acpi_dp_add_child(port_table, "endpoint0", ep_table);
134
135 snprintf(name, sizeof(name), "port%u", i);
136 port_name[i] = strdup(name);
137 acpi_dp_add_child(dsd, port_name[i], port_table);
138 }
139
140 acpi_dp_write(dsd);
141
142 for (i = 0; i < config->cio2_num_ports; ++i) {
143 free(ep_table_name[i]);
144 free(port_table_name[i]);
145 free(port_name[i]);
146 }
147}
Matt Delco1245b1e2020-06-17 07:26:55 +0530148
Matt Delco1ffee9d2020-06-17 12:55:35 +0530149static void apply_pld_defaults(struct drivers_intel_mipi_camera_config *config)
150{
151 if (!config->pld.ignore_color)
152 config->pld.ignore_color = 1;
153
154 if (!config->pld.visible)
155 config->pld.visible = 1;
156
157 if (!config->pld.vertical_offset)
158 config->pld.vertical_offset = 0xffff;
159
160 if (!config->pld.horizontal_offset)
161 config->pld.horizontal_offset = 0xffff;
162
163 /*
164 * PLD_PANEL_TOP has a value of zero, so the following will change any instance of
165 * PLD_PANEL_TOP to PLD_PANEL_FRONT unless disable_pld_defaults is set.
166 */
167 if (!config->pld.panel)
168 config->pld.panel = PLD_PANEL_FRONT;
169
170 /*
171 * PLD_HORIZONTAL_POSITION_LEFT has a value of zero, so the following will change any
172 * instance of that value to PLD_HORIZONTAL_POSITION_CENTER unless disable_pld_defaults
173 * is set.
174 */
175 if (!config->pld.horizontal_position)
176 config->pld.horizontal_position = PLD_HORIZONTAL_POSITION_CENTER;
177
178 /*
179 * The desired default for |vertical_position| is PLD_VERTICAL_POSITION_UPPER, which
180 * has a value of zero so no work is needed to set a default. The same applies for
181 * setting |shape| to PLD_SHAPE_ROUND.
182 */
183}
184
185static void camera_generate_pld(const struct device *dev)
186{
187 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
188
189 if (config->use_pld) {
190 if (!config->disable_pld_defaults)
191 apply_pld_defaults(config);
192
193 acpigen_write_pld(&config->pld);
194 }
195}
196
Matt Delco964033f2020-06-17 12:49:43 +0530197static uint32_t address_for_dev_type(const struct device *dev, uint8_t dev_type)
198{
199 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
200 uint16_t i2c_bus = dev->bus ? dev->bus->secondary : 0xFFFF;
201 uint16_t i2c_addr;
202
203 switch (dev_type) {
204 case DEV_TYPE_SENSOR:
205 i2c_addr = dev->path.i2c.device;
206 break;
207 case DEV_TYPE_VCM:
208 i2c_addr = config->vcm_address;
209 break;
210 case DEV_TYPE_ROM:
211 i2c_addr = config->rom_address;
212 break;
213 default:
214 return 0;
215 }
216
217 return (((uint32_t)i2c_bus) << 24 | ((uint32_t)i2c_addr) << 8 | dev_type);
218}
219
220static void camera_generate_dsm(const struct device *dev)
221{
222 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
223 int local1_ret = 1 + (config->ssdb.vcm_type ? 1 : 0) + (config->ssdb.rom_type ? 1 : 0);
224 int next_local1 = 1;
225 /* Method (_DSM, 4, NotSerialized) */
226 acpigen_write_method("_DSM", 4);
227
228 /* ToBuffer (Arg0, Local0) */
229 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
230
231 /* If (LEqual (Local0, ToUUID(uuid))) */
232 acpigen_write_if();
233 acpigen_emit_byte(LEQUAL_OP);
234 acpigen_emit_byte(LOCAL0_OP);
235 acpigen_write_uuid(SENSOR_NAME_UUID);
236 acpigen_write_return_string(config->sensor_name ? config->sensor_name : "UNKNOWN");
237 acpigen_pop_len(); /* If */
238
239 /* If (LEqual (Local0, ToUUID(uuid))) */
240 acpigen_write_if();
241 acpigen_emit_byte(LEQUAL_OP);
242 acpigen_emit_byte(LOCAL0_OP);
243 acpigen_write_uuid(SENSOR_TYPE_UUID);
244 /* ToInteger (Arg2, Local1) */
245 acpigen_write_to_integer(ARG2_OP, LOCAL1_OP);
246
247 /* If (LEqual (Local1, 1)) */
248 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
249 acpigen_write_return_integer(local1_ret);
250 acpigen_pop_len(); /* If Arg2=1 */
251
252 /* If (LEqual (Local1, 2)) */
253 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
254 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_SENSOR));
255 acpigen_pop_len(); /* If Arg2=2 */
256
257 if (config->ssdb.vcm_type) {
258 /* If (LEqual (Local1, 3)) */
259 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
260 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_VCM));
261 acpigen_pop_len(); /* If Arg2=3 */
262 }
263
264 if (config->ssdb.rom_type) {
265 /* If (LEqual (Local1, 3 or 4)) */
266 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1);
267 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_ROM));
268 acpigen_pop_len(); /* If Arg2=3 or 4 */
269 }
270
271 acpigen_pop_len(); /* If uuid */
272
273 /* Return (Buffer (One) { 0x0 }) */
274 acpigen_write_return_singleton_buffer(0x0);
275
276 acpigen_pop_len(); /* Method _DSM */
277}
278
Matt Delco879b3c12020-06-17 13:10:22 +0530279static void camera_fill_ssdb_defaults(struct drivers_intel_mipi_camera_config *config)
Matt Delco1245b1e2020-06-17 07:26:55 +0530280{
Matt Delco879b3c12020-06-17 13:10:22 +0530281 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
282 struct drivers_intel_mipi_camera_config *cio2_config;
283
Matt Delco1245b1e2020-06-17 07:26:55 +0530284 if (config->disable_ssdb_defaults)
285 return;
286
Matt Delco879b3c12020-06-17 13:10:22 +0530287 if (!config->ssdb.bdf_value)
288 config->ssdb.bdf_value = PCI_DEVFN(CIO2_PCI_DEV, CIO2_PCI_FN);
289
Matt Delco1245b1e2020-06-17 07:26:55 +0530290 if (!config->ssdb.platform)
291 config->ssdb.platform = PLATFORM_SKC;
292
293 if (!config->ssdb.flash_support)
294 config->ssdb.flash_support = FLASH_DISABLE;
295
296 if (!config->ssdb.privacy_led)
297 config->ssdb.privacy_led = PRIVACY_LED_A_16mA;
298
299 if (!config->ssdb.mipi_define)
300 config->ssdb.mipi_define = MIPI_INFO_ACPI_DEFINED;
301
302 if (!config->ssdb.mclk_speed)
303 config->ssdb.mclk_speed = CLK_FREQ_19_2MHZ;
Matt Delco879b3c12020-06-17 13:10:22 +0530304
305 if (!config->ssdb.lanes_used) {
306 cio2_config = cio2 ? cio2->chip_info : NULL;
307
308 if (!cio2_config) {
309 printk(BIOS_ERR, "Failed to get CIO2 config\n");
310 } else if (cio2_config->device_type != INTEL_ACPI_CAMERA_CIO2) {
311 printk(BIOS_ERR, "Device type isn't CIO2: %u\n",
312 (u32)cio2_config->device_type);
313 } else if (config->ssdb.link_used >= cio2_config->cio2_num_ports) {
314 printk(BIOS_ERR, "%u exceeds CIO2's %u links\n",
315 (u32)config->ssdb.link_used,
316 (u32)cio2_config->cio2_num_ports);
317 } else {
318 config->ssdb.lanes_used =
319 cio2_config->cio2_lanes_used[config->ssdb.link_used];
320 }
321 }
Matt Delco1245b1e2020-06-17 07:26:55 +0530322}
323
324/*
325 * Adds settings for a camera sensor device (typically at "\_SB.PCI0.I2Cx.CAMy"). The drivers
326 * for Linux tends to expect the camera sensor device and any related nvram / vcm devices to be
327 * separate ACPI devices, while the drivers for Windows want all of these to be grouped
328 * together in the camera sensor ACPI device. This implementation tries to satisfy both,
329 * though the unfortunate tradeoff is that the same I2C address for nvram and vcm is advertised
330 * by multiple devices in ACPI (via "_CRS"). The Windows driver can use the "_DSM" method to
331 * disambiguate the I2C resources in the camera sensor ACPI device. Drivers for Windows
332 * typically query "SSDB" for configuration information (represented as a binary blob dump of
333 * struct), while Linux drivers typically consult individual parameters in "_DSD".
334 *
335 * The tree of tables in "_DSD" is analogous to what's used for the "CIO2" device. The _DSD
336 * specifies a child table for the sensor's port (e.g., PRT0 for "port0"--this implementation
337 * assumes a camera only has 1 port). The PRT0 table specifies a table for each endpoint
338 * (though only 1 endpoint is supported by this implementation so the table only has an
339 * "endpoint0" that points to a EP00 table). The EP00 table primarily describes the # of lanes
340 * in "data-lines", a list of frequencies in "list-frequencies", and specifies the name of the
341 * other side in "remote-endpoint" (typically "\_SB.PCI0.CIO2").
342 */
343static void camera_fill_sensor(const struct device *dev)
344{
345 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
346 struct acpi_dp *ep00 = NULL;
347 struct acpi_dp *prt0 = NULL;
348 struct acpi_dp *dsd = NULL;
349 struct acpi_dp *remote = NULL;
350 const char *vcm_name = NULL;
351 struct acpi_dp *lens_focus = NULL;
Matt Delco879b3c12020-06-17 13:10:22 +0530352 const char *remote_name;
353 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
Matt Delco1245b1e2020-06-17 07:26:55 +0530354
Matt Delco1ffee9d2020-06-17 12:55:35 +0530355 camera_generate_pld(dev);
356
Matt Delco879b3c12020-06-17 13:10:22 +0530357 camera_fill_ssdb_defaults(config);
Matt Delco1245b1e2020-06-17 07:26:55 +0530358
Matt Delco964033f2020-06-17 12:49:43 +0530359 /* _DSM */
360 camera_generate_dsm(dev);
361
Matt Delco1245b1e2020-06-17 07:26:55 +0530362 ep00 = acpi_dp_new_table("EP00");
363 acpi_dp_add_integer(ep00, "endpoint", DEFAULT_ENDPOINT);
364 acpi_dp_add_integer(ep00, "clock-lanes", 0);
365
366 if (config->ssdb.lanes_used > 0) {
367 struct acpi_dp *lanes = acpi_dp_new_table("data-lanes");
368 uint32_t i;
369 for (i = 1; i <= config->ssdb.lanes_used; ++i)
370 acpi_dp_add_integer(lanes, NULL, i);
371 acpi_dp_add_array(ep00, lanes);
372 }
373
374 if (config->num_freq_entries) {
375 struct acpi_dp *freq = acpi_dp_new_table("link-frequencies");
376 uint32_t i;
377 for (i = 0; i < config->num_freq_entries && i < MAX_LINK_FREQ_ENTRIES; ++i)
378 acpi_dp_add_integer(freq, NULL, config->link_freq[i]);
379 acpi_dp_add_array(ep00, freq);
380 }
381
382 remote = acpi_dp_new_table("remote-endpoint");
383
Matt Delco879b3c12020-06-17 13:10:22 +0530384 if (config->remote_name) {
385 remote_name = config->remote_name;
386 } else {
387 if (cio2)
388 remote_name = acpi_device_path(cio2);
389 else
390 remote_name = DEFAULT_REMOTE_NAME;
391 }
392
393 acpi_dp_add_reference(remote, NULL, remote_name);
Matt Delco1245b1e2020-06-17 07:26:55 +0530394 acpi_dp_add_integer(remote, NULL, config->ssdb.link_used);
395 acpi_dp_add_integer(remote, NULL, DEFAULT_ENDPOINT);
396 acpi_dp_add_array(ep00, remote);
397
398 prt0 = acpi_dp_new_table("PRT0");
399
400 acpi_dp_add_integer(prt0, "port", 0);
401 acpi_dp_add_child(prt0, "endpoint0", ep00);
402 dsd = acpi_dp_new_table("_DSD");
403
404 acpi_dp_add_integer(dsd, "clock-frequency", config->ssdb.mclk_speed);
405
406 if (config->ssdb.degree)
407 acpi_dp_add_integer(dsd, "rotation", 180);
408
409 if (config->ssdb.vcm_type) {
410 if (config->vcm_name) {
411 vcm_name = config->vcm_name;
412 } else {
413 const struct device_path path = {
414 .type = DEVICE_PATH_I2C,
415 .i2c.device = config->vcm_address,
416 };
417 struct device *vcm_dev = find_dev_path(dev->bus, &path);
418 struct drivers_intel_mipi_camera_config *vcm_config;
419 vcm_config = vcm_dev ? vcm_dev->chip_info : NULL;
420
421 if (!vcm_config)
422 printk(BIOS_ERR, "Failed to get VCM\n");
423 else if (vcm_config->device_type != INTEL_ACPI_CAMERA_VCM)
424 printk(BIOS_ERR, "Device isn't VCM\n");
425 else
426 vcm_name = acpi_device_path(vcm_dev);
427 }
428 }
429
430 if (vcm_name) {
431 lens_focus = acpi_dp_new_table("lens-focus");
432 acpi_dp_add_reference(lens_focus, NULL, vcm_name);
433 acpi_dp_add_array(dsd, lens_focus);
434 }
435
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530436 if (config->low_power_probe)
437 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
438
Matt Delco1245b1e2020-06-17 07:26:55 +0530439 acpi_dp_add_child(dsd, "port0", prt0);
440 acpi_dp_write(dsd);
441
442 acpigen_write_method_serialized("SSDB", 0);
443 acpigen_write_return_byte_buffer((uint8_t *)&config->ssdb, sizeof(config->ssdb));
444 acpigen_pop_len(); /* Method */
445
446 /* Fill Power Sequencing Data */
447 if (config->num_pwdb_entries > 0) {
448 acpigen_write_method_serialized("PWDB", 0);
449 acpigen_write_return_byte_buffer((uint8_t *)&config->pwdb,
450 sizeof(struct intel_pwdb) *
451 config->num_pwdb_entries);
452 acpigen_pop_len(); /* Method */
453 }
454}
455
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530456static void camera_fill_nvm(const struct device *dev)
457{
458 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
John Zhao388e5512020-09-18 11:54:05 -0700459 struct acpi_dp *dsd;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530460
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530461 if (!config->nvm_compat)
462 return;
463
John Zhao388e5512020-09-18 11:54:05 -0700464 dsd = acpi_dp_new_table("_DSD");
465
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530466 /* It might be possible to default size or width based on type. */
467 if (!config->disable_nvm_defaults && !config->nvm_pagesize)
468 config->nvm_pagesize = 1;
469
470 if (!config->disable_nvm_defaults && !config->nvm_readonly)
471 config->nvm_readonly = 1;
472
473 if (config->nvm_size)
474 acpi_dp_add_integer(dsd, "size", config->nvm_size);
475
476 if (config->nvm_pagesize)
477 acpi_dp_add_integer(dsd, "pagesize", config->nvm_pagesize);
478
479 if (config->nvm_readonly)
480 acpi_dp_add_integer(dsd, "read-only", config->nvm_readonly);
481
482 if (config->nvm_width)
483 acpi_dp_add_integer(dsd, "address-width", config->nvm_width);
484
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530485 acpi_dp_add_string(dsd, "compatible", config->nvm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530486
487 if (config->low_power_probe)
488 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
489
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530490 acpi_dp_write(dsd);
491}
492
493static void camera_fill_vcm(const struct device *dev)
494{
495 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
496 struct acpi_dp *dsd;
497
498 if (!config->vcm_compat)
499 return;
500
501 dsd = acpi_dp_new_table("_DSD");
502 acpi_dp_add_string(dsd, "compatible", config->vcm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530503
504 if (config->low_power_probe)
505 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
506
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530507 acpi_dp_write(dsd);
508}
509
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530510static int get_resource_index(const struct resource_config *res_config)
511{
512 enum ctrl_type type = resource_get_ctrl_type(res_config);
513 const struct clk_config *clk_config;
514 const struct gpio_config *gpio_config;
515 unsigned int i;
516 uint8_t res_id;
517
518 switch (type) {
519 case IMGCLK:
520 clk_config = resource_clk_config(res_config);
521 res_id = clk_config->clknum;
522 break;
523 case GPIO:
524 gpio_config = resource_gpio_config(res_config);
525 res_id = gpio_config->gpio_num;
526 break;
527 default:
528 printk(BIOS_ERR, "Unsupported power operation: %x\n"
529 "OS camera driver will likely not work", type);
530 return -1;
531 }
532
533 for (i = 0; i < res_mgr.cnt; i++)
534 if (res_mgr.resource[i].type == type && res_mgr.resource[i].id == res_id)
535 return i;
536
537 return -1;
538}
539
540static void add_guarded_method_namestring(struct resource_config *res_config, int res_index)
541{
542 char method_name[ACPI_NAME_BUFFER_SIZE];
543 enum action_type action = resource_get_action_type(res_config);
544
545 switch (action) {
546 case ENABLE:
547 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
548 break;
549 case DISABLE:
550 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
551 break;
552 default:
553 snprintf(method_name, sizeof(method_name), UNKNOWN_METHOD_FORMAT, res_index);
554 printk(BIOS_ERR, "Unsupported resource action: %x\n", action);
555 }
556
557 acpigen_emit_namestring(method_name);
558}
559
560static void call_guarded_method(struct resource_config *res_config)
561{
562 int res_index;
563
564 if (res_config == NULL)
565 return;
566
567 res_index = get_resource_index(res_config);
568
569 if (res_index != -1)
570 add_guarded_method_namestring(res_config, res_index);
571}
572
573static void add_clk_op(const struct clk_config *clk_config, enum action_type action)
574{
575 if (clk_config == NULL)
576 return;
577
578 switch (action) {
579 case ENABLE:
580 acpigen_write_if();
581 acpigen_emit_ext_op(COND_REFOF_OP);
582 acpigen_emit_string(CLK_ENABLE_METHOD);
583 acpigen_emit_namestring(CLK_ENABLE_METHOD);
584 acpigen_write_integer(clk_config->clknum);
585 acpigen_write_integer(clk_config->freq);
586 acpigen_pop_len(); /* CondRefOf */
587 break;
588 case DISABLE:
589 acpigen_write_if();
590 acpigen_emit_ext_op(COND_REFOF_OP);
591 acpigen_emit_string(CLK_DISABLE_METHOD);
592 acpigen_emit_namestring(CLK_DISABLE_METHOD);
593 acpigen_write_integer(clk_config->clknum);
594 acpigen_pop_len(); /* CondRefOf */
595 break;
596 default:
597 acpigen_write_debug_string("Unsupported clock action");
598 printk(BIOS_ERR, "Unsupported clock action: %x\n"
599 "OS camera driver will likely not work", action);
600 }
601}
602
603static void add_gpio_op(const struct gpio_config *gpio_config, enum action_type action)
604{
605 if (gpio_config == NULL)
606 return;
607
608 switch (action) {
609 case ENABLE:
610 acpigen_soc_set_tx_gpio(gpio_config->gpio_num);
611 break;
612 case DISABLE:
613 acpigen_soc_clear_tx_gpio(gpio_config->gpio_num);
614 break;
615 default:
616 acpigen_write_debug_string("Unsupported GPIO action");
617 printk(BIOS_ERR, "Unsupported GPIO action: %x\n"
618 "OS camera driver will likely not work\n", action);
619 }
620}
621
622static void add_power_operation(const struct resource_config *res_config)
623{
624 const struct clk_config *clk_config;
625 const struct gpio_config *gpio_config;
626 enum ctrl_type type = resource_get_ctrl_type(res_config);
627 enum action_type action = resource_get_action_type(res_config);
628
629 if (res_config == NULL)
630 return;
631
632 switch (type) {
633 case IMGCLK:
634 clk_config = resource_clk_config(res_config);
635 add_clk_op(clk_config, action);
636 break;
637 case GPIO:
638 gpio_config = resource_gpio_config(res_config);
639 add_gpio_op(gpio_config, action);
640 break;
641 default:
642 printk(BIOS_ERR, "Unsupported power operation: %x\n"
643 "OS camera driver will likely not work\n", type);
644 break;
645 }
646}
647
648static void write_guard_variable(uint8_t res_index)
649{
650 char varname[ACPI_NAME_BUFFER_SIZE];
651
652 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
653 acpigen_write_name_integer(varname, 0);
654}
655
656static void write_enable_method(struct resource_config *res_config, uint8_t res_index)
657{
658 char method_name[ACPI_NAME_BUFFER_SIZE];
659 char varname[ACPI_NAME_BUFFER_SIZE];
660
661 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
662
663 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
664
665 acpigen_write_method_serialized(method_name, 0);
666 acpigen_write_if_lequal_namestr_int(varname, 0);
667 resource_set_action_type(res_config, ENABLE);
668 add_power_operation(res_config);
669 acpigen_pop_len(); /* if */
670
671 acpigen_emit_byte(INCREMENT_OP);
672 acpigen_emit_namestring(varname);
673 acpigen_pop_len(); /* method_name */
674}
675
676static void write_disable_method(struct resource_config *res_config, uint8_t res_index)
677{
678 char method_name[ACPI_NAME_BUFFER_SIZE];
679 char varname[ACPI_NAME_BUFFER_SIZE];
680
681 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
682
683 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
684
685 acpigen_write_method_serialized(method_name, 0);
686 acpigen_write_if();
687 acpigen_emit_byte(LGREATER_OP);
688 acpigen_emit_namestring(varname);
689 acpigen_write_integer(0x0);
690 acpigen_emit_byte(DECREMENT_OP);
691 acpigen_emit_namestring(varname);
692 acpigen_pop_len(); /* if */
693
694 acpigen_write_if_lequal_namestr_int(varname, 0);
695 resource_set_action_type(res_config, DISABLE);
696 add_power_operation(res_config);
697 acpigen_pop_len(); /* if */
698 acpigen_pop_len(); /* method_name */
699}
700
701static void add_guarded_operations(const struct drivers_intel_mipi_camera_config *config,
702 const struct operation_seq *seq)
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530703{
704 unsigned int i;
705 uint8_t index;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530706 uint8_t res_id;
707 struct resource_config res_config;
708 int res_index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530709
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530710 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
711 index = seq->ops[i].index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530712 switch (seq->ops[i].type) {
713 case IMGCLK:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530714 res_id = config->clk_panel.clks[index].clknum;
715 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530716 break;
717 case GPIO:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530718 res_id = config->gpio_panel.gpio[index].gpio_num;
719 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530720 break;
721 default:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530722 printk(BIOS_ERR, "Unsupported power operation: %x\n"
723 "OS camera driver will likely not work\n",
724 seq->ops[i].type);
725 return;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530726 }
727
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530728 res_index = get_resource_index(&res_config);
729
730 if (res_index == -1) {
731 if (res_mgr.cnt >= MAX_GUARDED_RESOURCES) {
732 printk(BIOS_ERR, "Unable to add guarded camera resource\n"
733 "OS camera driver will likely not work\n");
734 return;
735 }
736
737 res_mgr.resource[res_mgr.cnt].id = res_id;
738 res_mgr.resource[res_mgr.cnt].type = seq->ops[i].type;
739
740 write_guard_variable(res_mgr.cnt);
741 write_enable_method(&res_config, res_mgr.cnt);
742 write_disable_method(&res_config, res_mgr.cnt);
743
744 res_mgr.cnt++;
745 }
746 }
747}
748
749static void fill_power_res_sequence(struct drivers_intel_mipi_camera_config *config,
750 struct operation_seq *seq)
751{
752 struct resource_config res_config;
753 unsigned int i;
754 uint8_t index;
755
756 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
757 index = seq->ops[i].index;
758
759 switch (seq->ops[i].type) {
760 case IMGCLK:
761 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
762 break;
763 case GPIO:
764 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
765 break;
766 default:
767 printk(BIOS_ERR, "Unsupported power operation: %x\n"
768 "OS camera driver will likely not work\n",
769 seq->ops[i].type);
770 return;
771 }
772
773 resource_set_action_type(&res_config, seq->ops[i].action);
774 call_guarded_method(&res_config);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530775 if (seq->ops[i].delay_ms)
776 acpigen_write_sleep(seq->ops[i].delay_ms);
777 }
778}
779
Matt Delco7d002932020-06-16 11:39:52 +0530780static void write_pci_camera_device(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530781{
Matt Delco7d002932020-06-16 11:39:52 +0530782 if (dev->path.type != DEVICE_PATH_PCI) {
783 printk(BIOS_ERR, "CIO2/IMGU devices require PCI\n");
784 return;
785 }
786
787 acpigen_write_device(acpi_device_name(dev));
788 acpigen_write_ADR_pci_device(dev);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530789 acpigen_write_name_string("_DDN", "Camera and Imaging Subsystem");
Matt Delco7d002932020-06-16 11:39:52 +0530790}
791
792static void write_i2c_camera_device(const struct device *dev, const char *scope)
793{
794 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
V Sowmya9f8023a2017-02-28 17:52:05 +0530795 struct acpi_i2c i2c = {
796 .address = dev->path.i2c.device,
797 .mode_10bit = dev->path.i2c.mode_10bit,
798 .speed = I2C_SPEED_FAST,
799 .resource = scope,
800 };
801
V Sowmya9f8023a2017-02-28 17:52:05 +0530802 acpigen_write_device(acpi_device_name(dev));
Matt Delco7d002932020-06-16 11:39:52 +0530803
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530804 /* add power resource */
805 if (config->has_power_resource) {
806 acpigen_write_power_res(POWER_RESOURCE_NAME, 0, 0, NULL, 0);
807 acpigen_write_name_integer("STA", 0);
808 acpigen_write_STA_ext("STA");
809
810 acpigen_write_method_serialized("_ON", 0);
811 acpigen_write_if();
812 acpigen_emit_byte(LEQUAL_OP);
813 acpigen_emit_namestring("STA");
814 acpigen_write_integer(0);
815
816 fill_power_res_sequence(config, &config->on_seq);
817
818 acpigen_write_store_op_to_namestr(1, "STA");
819 acpigen_pop_len(); /* if */
820 acpigen_pop_len(); /* _ON */
821
822 /* _OFF operations */
823 acpigen_write_method_serialized("_OFF", 0);
824 acpigen_write_if();
825 acpigen_emit_byte(LEQUAL_OP);
826 acpigen_emit_namestring("STA");
827 acpigen_write_integer(1);
828
829 fill_power_res_sequence(config, &config->off_seq);
830
831 acpigen_write_store_op_to_namestr(0, "STA");
832 acpigen_pop_len(); /* if */
833 acpigen_pop_len(); /* _ON */
834
835 acpigen_pop_len(); /* Power Resource */
836 }
837
Matt Delco7d002932020-06-16 11:39:52 +0530838 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR)
839 acpigen_write_name_integer("_ADR", 0);
840
841 if (config->acpi_hid)
842 acpigen_write_name_string("_HID", config->acpi_hid);
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530843 else if (config->device_type == INTEL_ACPI_CAMERA_VCM ||
844 config->device_type == INTEL_ACPI_CAMERA_NVM)
Matt Delco7d002932020-06-16 11:39:52 +0530845 acpigen_write_name_string("_HID", ACPI_DT_NAMESPACE_HID);
Matt Delco7d002932020-06-16 11:39:52 +0530846
V Sowmya9f8023a2017-02-28 17:52:05 +0530847 acpigen_write_name_integer("_UID", config->acpi_uid);
848 acpigen_write_name_string("_DDN", config->chip_name);
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800849 acpigen_write_STA(acpi_device_status(dev));
V Sowmya9f8023a2017-02-28 17:52:05 +0530850
851 /* Resources */
852 acpigen_write_name("_CRS");
853 acpigen_write_resourcetemplate_header();
854 acpi_device_write_i2c(&i2c);
V Sowmya9f8023a2017-02-28 17:52:05 +0530855
Matt Delco7d002932020-06-16 11:39:52 +0530856 /*
857 * The optional vcm/nvram devices are presumed to be on the same I2C bus as the camera
858 * sensor.
859 */
860 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
861 config->ssdb.vcm_type && config->vcm_address) {
862 struct acpi_i2c i2c_vcm = i2c;
863 i2c_vcm.address = config->vcm_address;
864 acpi_device_write_i2c(&i2c_vcm);
V Sowmya9f8023a2017-02-28 17:52:05 +0530865 }
866
Matt Delco7d002932020-06-16 11:39:52 +0530867 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
868 config->ssdb.rom_type && config->rom_address) {
869 struct acpi_i2c i2c_rom = i2c;
870 i2c_rom.address = config->rom_address;
871 acpi_device_write_i2c(&i2c_rom);
872 }
873
874 acpigen_write_resourcetemplate_footer();
875}
876
877static void write_camera_device_common(const struct device *dev)
878{
879 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
880
881 /* Mark it as Camera related device */
882 if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
883 config->device_type == INTEL_ACPI_CAMERA_IMGU ||
884 config->device_type == INTEL_ACPI_CAMERA_SENSOR ||
885 config->device_type == INTEL_ACPI_CAMERA_VCM) {
886 acpigen_write_name_integer("CAMD", config->device_type);
887 }
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530888
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530889 if (config->pr0 || config->has_power_resource) {
890 acpigen_write_name("_PR0");
891 acpigen_write_package(1);
892 if (config->pr0)
893 acpigen_emit_namestring(config->pr0); /* External power resource */
894 else
895 acpigen_emit_namestring(POWER_RESOURCE_NAME);
896
897 acpigen_pop_len(); /* _PR0 */
898 }
899
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530900 switch (config->device_type) {
Matt Delco879b3c12020-06-17 13:10:22 +0530901 case INTEL_ACPI_CAMERA_CIO2:
902 camera_fill_cio2(dev);
903 break;
Matt Delco1245b1e2020-06-17 07:26:55 +0530904 case INTEL_ACPI_CAMERA_SENSOR:
905 camera_fill_sensor(dev);
906 break;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530907 case INTEL_ACPI_CAMERA_VCM:
908 camera_fill_vcm(dev);
909 break;
910 case INTEL_ACPI_CAMERA_NVM:
911 camera_fill_nvm(dev);
912 break;
913 default:
914 break;
915 }
Matt Delco7d002932020-06-16 11:39:52 +0530916}
917
918static void camera_fill_ssdt(const struct device *dev)
919{
920 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530921 const char *scope = NULL;
922 const struct device *pdev;
Matt Delco7d002932020-06-16 11:39:52 +0530923
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530924 if (config->has_power_resource) {
925 pdev = dev->bus->dev;
926 if (!pdev || !pdev->enabled)
927 return;
928
929 scope = acpi_device_scope(pdev);
930 if (!scope)
931 return;
932
933 acpigen_write_scope(scope);
934 add_guarded_operations(config, &config->on_seq);
935 add_guarded_operations(config, &config->off_seq);
936 acpigen_pop_len(); /* Guarded power resource operations scope */
937 }
938
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530939 switch (dev->path.type) {
940 case DEVICE_PATH_I2C:
941 scope = acpi_device_scope(dev);
942 if (!scope)
943 return;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530944
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530945 acpigen_write_scope(scope);
Matt Delco7d002932020-06-16 11:39:52 +0530946 write_i2c_camera_device(dev, scope);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530947 break;
948 case DEVICE_PATH_GENERIC:
949 pdev = dev->bus->dev;
950 scope = acpi_device_scope(pdev);
951 if (!scope)
952 return;
953
954 acpigen_write_scope(scope);
955 write_pci_camera_device(pdev);
956 break;
957 default:
958 printk(BIOS_ERR, "Unsupported device type: %x\n"
959 "OS camera driver will likely not work\n", dev->path.type);
960 return;
961 }
Matt Delco7d002932020-06-16 11:39:52 +0530962
963 write_camera_device_common(dev);
V Sowmya9f8023a2017-02-28 17:52:05 +0530964
965 acpigen_pop_len(); /* Device */
966 acpigen_pop_len(); /* Scope */
Matt Delco7d002932020-06-16 11:39:52 +0530967
968 if (dev->path.type == DEVICE_PATH_PCI) {
969 printk(BIOS_INFO, "%s: %s PCI address 0%x\n", acpi_device_path(dev),
970 dev->chip_ops->name, dev->path.pci.devfn);
971 } else {
972 printk(BIOS_INFO, "%s: %s I2C address 0%xh\n", acpi_device_path(dev),
973 dev->chip_ops->name, dev->path.i2c.device);
974 }
V Sowmya9f8023a2017-02-28 17:52:05 +0530975}
976
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600977static const char *camera_acpi_name(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530978{
Matt Delco7d002932020-06-16 11:39:52 +0530979 const char *prefix = NULL;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530980 static char name[ACPI_NAME_BUFFER_SIZE];
V Sowmya9f8023a2017-02-28 17:52:05 +0530981 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Matt Delco7d002932020-06-16 11:39:52 +0530982
983 if (config->acpi_name)
984 return config->acpi_name;
985
986 switch (config->device_type) {
987 case INTEL_ACPI_CAMERA_CIO2:
988 return "CIO2";
989 case INTEL_ACPI_CAMERA_IMGU:
990 return "IMGU";
991 case INTEL_ACPI_CAMERA_PMIC:
992 return "PMIC";
993 case INTEL_ACPI_CAMERA_SENSOR:
994 prefix = "CAM";
995 break;
996 case INTEL_ACPI_CAMERA_VCM:
997 prefix = "VCM";
998 break;
999 case INTEL_ACPI_CAMERA_NVM:
1000 prefix = "NVM";
1001 break;
1002 default:
1003 printk(BIOS_ERR, "Invalid device type: %x\n", config->device_type);
1004 return NULL;
1005 }
1006
1007 /*
1008 * The camera # knows which link # they use, so that's used as the basis for the
1009 * instance #. The VCM and NVM don't have this information, so the best we can go on is
1010 * the _UID.
1011 */
1012 snprintf(name, sizeof(name), "%s%1u", prefix,
1013 config->device_type == INTEL_ACPI_CAMERA_SENSOR ?
1014 config->ssdb.link_used : config->acpi_uid);
1015 return name;
V Sowmya9f8023a2017-02-28 17:52:05 +05301016}
1017
1018static struct device_operations camera_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +02001019 .read_resources = noop_read_resources,
1020 .set_resources = noop_set_resources,
Nico Huber68680dd2020-03-31 17:34:52 +02001021 .acpi_name = camera_acpi_name,
1022 .acpi_fill_ssdt = camera_fill_ssdt,
V Sowmya9f8023a2017-02-28 17:52:05 +05301023};
1024
1025static void camera_enable(struct device *dev)
1026{
1027 dev->ops = &camera_ops;
1028}
1029
1030struct chip_operations drivers_intel_mipi_camera_ops = {
1031 CHIP_NAME("Intel MIPI Camera Device")
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +01001032 .enable_dev = camera_enable
V Sowmya9f8023a2017-02-28 17:52:05 +05301033};