blob: ec89971cbd8e18998ce366ab94c742853bb7c057 [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>
Elyes Haouas5318d9c2022-10-31 14:06:21 +01008#include <cpu/cpu.h>
V Sowmya9f8023a2017-02-28 17:52:05 +05309#include <console/console.h>
Sugnan Prabhu Sdcf04592021-12-03 19:07:04 +053010#include <cpu/intel/cpu_ids.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +020011#include <device/i2c_simple.h>
V Sowmya9f8023a2017-02-28 17:52:05 +053012#include <device/device.h>
13#include <device/path.h>
Matt Delco7d002932020-06-16 11:39:52 +053014#include <device/pci_def.h>
V Sowmya9f8023a2017-02-28 17:52:05 +053015#include "chip.h"
16
Matt Delco1245b1e2020-06-17 07:26:55 +053017#define SENSOR_NAME_UUID "822ace8f-2814-4174-a56b-5f029fe079ee"
18#define SENSOR_TYPE_UUID "26257549-9271-4ca4-bb43-c4899d5a4881"
19#define DEFAULT_ENDPOINT 0
Matt Delco879b3c12020-06-17 13:10:22 +053020#define DEFAULT_REMOTE_NAME "\\_SB.PCI0.CIO2"
21#define CIO2_PCI_DEV 0x14
22#define CIO2_PCI_FN 0x3
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +053023#define POWER_RESOURCE_NAME "PRIC"
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +053024#define GUARD_VARIABLE_FORMAT "RES%1d"
25#define ENABLE_METHOD_FORMAT "ENB%1d"
26#define DISABLE_METHOD_FORMAT "DSB%1d"
27#define UNKNOWN_METHOD_FORMAT "UNK%1d"
28#define CLK_ENABLE_METHOD "MCON"
29#define CLK_DISABLE_METHOD "MCOF"
30
31static struct camera_resource_manager res_mgr;
32
33static void resource_set_action_type(struct resource_config *res_config,
34 enum action_type action)
35{
36 if (res_config)
37 res_config->action = action;
38}
39
40static enum action_type resource_get_action_type(const struct resource_config *res_config)
41{
42 return res_config ? res_config->action : UNKNOWN_ACTION;
43}
44
45static enum ctrl_type resource_get_ctrl_type(const struct resource_config *res_config)
46{
47 return res_config ? res_config->type : UNKNOWN_CTRL;
48}
49
50static void resource_set_clk_config(struct resource_config *res_config,
51 const struct clk_config *clk_conf)
52{
53 if (res_config) {
54 res_config->type = IMGCLK;
55 res_config->clk_conf = clk_conf;
56 }
57}
58
59static const struct clk_config *resource_clk_config(const struct resource_config *res_config)
60{
61 return res_config ? res_config->clk_conf : NULL;
62}
63
64static void resource_set_gpio_config(struct resource_config *res_config,
65 const struct gpio_config *gpio_conf)
66{
67 if (res_config) {
68 res_config->type = GPIO;
69 res_config->gpio_conf = gpio_conf;
70 }
71}
72
73static const struct gpio_config *resource_gpio_config(const struct resource_config *res_config)
74{
75 return res_config ? res_config->gpio_conf : NULL;
76}
Matt Delco879b3c12020-06-17 13:10:22 +053077
78/*
79 * This implementation assumes there is only 1 endpoint at each end of every data port. It also
80 * assumes there are no clock lanes. It also assumes that any VCM or NVM for a CAM is on the
81 * same I2C bus as the CAM.
82 */
83
84/*
85 * Adds settings for a CIO2 device (typically at "\_SB.PCI0.CIO2"). A _DSD is added that
86 * specifies a child table for each port (e.g., PRT0 for "port0" and PRT1 for "port1"). Each
87 * PRTx table specifies a table for each endpoint (though only 1 endpoint is supported by this
88 * implementation so the table only has an "endpoint0" that points to a EPx0 table). The EPx0
89 * table primarily describes the # of lanes in "data-lines" and specifies the name of the other
90 * side in "remote-endpoint" (the name is usually of the form "\_SB.PCI0.I2Cx.CAM0" for the
91 * first port/cam and "\_SB.PCI0.I2Cx.CAM1" if there's a second port/cam).
92 */
93static void camera_fill_cio2(const struct device *dev)
94{
95 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
96 struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
97 char *ep_table_name[MAX_PORT_ENTRIES] = {NULL};
98 char *port_table_name[MAX_PORT_ENTRIES] = {NULL};
99 char *port_name[MAX_PORT_ENTRIES] = {NULL};
100 unsigned int i, j;
101 char name[BUS_PATH_MAX];
102 struct acpi_dp *ep_table = NULL;
103 struct acpi_dp *port_table = NULL;
104 struct acpi_dp *remote = NULL;
105 struct acpi_dp *lanes = NULL;
106
107 for (i = 0; i < config->cio2_num_ports && i < MAX_PORT_ENTRIES; ++i) {
108 snprintf(name, sizeof(name), "EP%u0", i);
109 ep_table_name[i] = strdup(name);
110 ep_table = acpi_dp_new_table(ep_table_name[i]);
111 acpi_dp_add_integer(ep_table, "endpoint", 0);
112 acpi_dp_add_integer(ep_table, "clock-lanes", 0);
113
114 if (config->cio2_lanes_used[i] > 0) {
115 lanes = acpi_dp_new_table("data-lanes");
116
117 for (j = 1; j <= config->cio2_lanes_used[i] &&
118 j <= MAX_PORT_ENTRIES; ++j)
119 acpi_dp_add_integer(lanes, NULL, j);
120 acpi_dp_add_array(ep_table, lanes);
121 }
122
123 if (config->cio2_lane_endpoint[i]) {
124 remote = acpi_dp_new_table("remote-endpoint");
125 acpi_dp_add_reference(remote, NULL, config->cio2_lane_endpoint[i]);
126 acpi_dp_add_integer(remote, NULL, 0);
127 acpi_dp_add_integer(remote, NULL, 0);
128 acpi_dp_add_array(ep_table, remote);
129 }
130
131 snprintf(name, sizeof(name), "PRT%u", i);
132 port_table_name[i] = strdup(name);
133 port_table = acpi_dp_new_table(port_table_name[i]);
134 acpi_dp_add_integer(port_table, "port", config->cio2_prt[i]);
135 acpi_dp_add_child(port_table, "endpoint0", ep_table);
136
137 snprintf(name, sizeof(name), "port%u", i);
138 port_name[i] = strdup(name);
Sugnan Prabhu Sdcf04592021-12-03 19:07:04 +0530139 if (CONFIG(ACPI_ADL_IPU_ES_SUPPORT)) {
140 u32 cpu_id = cpu_get_cpuid();
jimlaibbc8d912022-11-23 16:47:40 +0800141 if (cpu_id == CPUID_ALDERLAKE_J0 || cpu_id == CPUID_ALDERLAKE_Q0)
Sugnan Prabhu Sdcf04592021-12-03 19:07:04 +0530142 acpi_dp_add_integer(dsd, "is_es", 1);
143 else
144 acpi_dp_add_integer(dsd, "is_es", 0);
145 }
146
Matt Delco879b3c12020-06-17 13:10:22 +0530147 acpi_dp_add_child(dsd, port_name[i], port_table);
148 }
149
150 acpi_dp_write(dsd);
151
152 for (i = 0; i < config->cio2_num_ports; ++i) {
153 free(ep_table_name[i]);
154 free(port_table_name[i]);
155 free(port_name[i]);
156 }
157}
Matt Delco1245b1e2020-06-17 07:26:55 +0530158
Matt Delco1ffee9d2020-06-17 12:55:35 +0530159static void apply_pld_defaults(struct drivers_intel_mipi_camera_config *config)
160{
161 if (!config->pld.ignore_color)
162 config->pld.ignore_color = 1;
163
164 if (!config->pld.visible)
165 config->pld.visible = 1;
166
167 if (!config->pld.vertical_offset)
168 config->pld.vertical_offset = 0xffff;
169
170 if (!config->pld.horizontal_offset)
171 config->pld.horizontal_offset = 0xffff;
172
173 /*
174 * PLD_PANEL_TOP has a value of zero, so the following will change any instance of
175 * PLD_PANEL_TOP to PLD_PANEL_FRONT unless disable_pld_defaults is set.
176 */
177 if (!config->pld.panel)
178 config->pld.panel = PLD_PANEL_FRONT;
179
180 /*
181 * PLD_HORIZONTAL_POSITION_LEFT has a value of zero, so the following will change any
182 * instance of that value to PLD_HORIZONTAL_POSITION_CENTER unless disable_pld_defaults
183 * is set.
184 */
185 if (!config->pld.horizontal_position)
186 config->pld.horizontal_position = PLD_HORIZONTAL_POSITION_CENTER;
187
188 /*
189 * The desired default for |vertical_position| is PLD_VERTICAL_POSITION_UPPER, which
190 * has a value of zero so no work is needed to set a default. The same applies for
191 * setting |shape| to PLD_SHAPE_ROUND.
192 */
193}
194
195static void camera_generate_pld(const struct device *dev)
196{
197 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
198
199 if (config->use_pld) {
200 if (!config->disable_pld_defaults)
201 apply_pld_defaults(config);
202
203 acpigen_write_pld(&config->pld);
204 }
205}
206
Matt Delco964033f2020-06-17 12:49:43 +0530207static uint32_t address_for_dev_type(const struct device *dev, uint8_t dev_type)
208{
209 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
210 uint16_t i2c_bus = dev->bus ? dev->bus->secondary : 0xFFFF;
211 uint16_t i2c_addr;
212
213 switch (dev_type) {
214 case DEV_TYPE_SENSOR:
215 i2c_addr = dev->path.i2c.device;
216 break;
217 case DEV_TYPE_VCM:
218 i2c_addr = config->vcm_address;
219 break;
220 case DEV_TYPE_ROM:
221 i2c_addr = config->rom_address;
222 break;
223 default:
224 return 0;
225 }
226
227 return (((uint32_t)i2c_bus) << 24 | ((uint32_t)i2c_addr) << 8 | dev_type);
228}
229
230static void camera_generate_dsm(const struct device *dev)
231{
232 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
233 int local1_ret = 1 + (config->ssdb.vcm_type ? 1 : 0) + (config->ssdb.rom_type ? 1 : 0);
234 int next_local1 = 1;
235 /* Method (_DSM, 4, NotSerialized) */
236 acpigen_write_method("_DSM", 4);
237
238 /* ToBuffer (Arg0, Local0) */
239 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
240
241 /* If (LEqual (Local0, ToUUID(uuid))) */
242 acpigen_write_if();
243 acpigen_emit_byte(LEQUAL_OP);
244 acpigen_emit_byte(LOCAL0_OP);
245 acpigen_write_uuid(SENSOR_NAME_UUID);
246 acpigen_write_return_string(config->sensor_name ? config->sensor_name : "UNKNOWN");
247 acpigen_pop_len(); /* If */
248
249 /* If (LEqual (Local0, ToUUID(uuid))) */
250 acpigen_write_if();
251 acpigen_emit_byte(LEQUAL_OP);
252 acpigen_emit_byte(LOCAL0_OP);
253 acpigen_write_uuid(SENSOR_TYPE_UUID);
254 /* ToInteger (Arg2, Local1) */
255 acpigen_write_to_integer(ARG2_OP, LOCAL1_OP);
256
257 /* If (LEqual (Local1, 1)) */
258 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
259 acpigen_write_return_integer(local1_ret);
260 acpigen_pop_len(); /* If Arg2=1 */
261
262 /* If (LEqual (Local1, 2)) */
263 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
264 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_SENSOR));
265 acpigen_pop_len(); /* If Arg2=2 */
266
267 if (config->ssdb.vcm_type) {
268 /* If (LEqual (Local1, 3)) */
269 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
270 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_VCM));
271 acpigen_pop_len(); /* If Arg2=3 */
272 }
273
274 if (config->ssdb.rom_type) {
275 /* If (LEqual (Local1, 3 or 4)) */
276 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1);
277 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_ROM));
278 acpigen_pop_len(); /* If Arg2=3 or 4 */
279 }
280
281 acpigen_pop_len(); /* If uuid */
282
283 /* Return (Buffer (One) { 0x0 }) */
284 acpigen_write_return_singleton_buffer(0x0);
285
286 acpigen_pop_len(); /* Method _DSM */
287}
288
Matt Delco879b3c12020-06-17 13:10:22 +0530289static void camera_fill_ssdb_defaults(struct drivers_intel_mipi_camera_config *config)
Matt Delco1245b1e2020-06-17 07:26:55 +0530290{
Matt Delco879b3c12020-06-17 13:10:22 +0530291 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
292 struct drivers_intel_mipi_camera_config *cio2_config;
293
Matt Delco1245b1e2020-06-17 07:26:55 +0530294 if (config->disable_ssdb_defaults)
295 return;
296
Matt Delco879b3c12020-06-17 13:10:22 +0530297 if (!config->ssdb.bdf_value)
298 config->ssdb.bdf_value = PCI_DEVFN(CIO2_PCI_DEV, CIO2_PCI_FN);
299
Matt Delco1245b1e2020-06-17 07:26:55 +0530300 if (!config->ssdb.platform)
301 config->ssdb.platform = PLATFORM_SKC;
302
303 if (!config->ssdb.flash_support)
304 config->ssdb.flash_support = FLASH_DISABLE;
305
306 if (!config->ssdb.privacy_led)
307 config->ssdb.privacy_led = PRIVACY_LED_A_16mA;
308
309 if (!config->ssdb.mipi_define)
310 config->ssdb.mipi_define = MIPI_INFO_ACPI_DEFINED;
311
312 if (!config->ssdb.mclk_speed)
313 config->ssdb.mclk_speed = CLK_FREQ_19_2MHZ;
Matt Delco879b3c12020-06-17 13:10:22 +0530314
315 if (!config->ssdb.lanes_used) {
316 cio2_config = cio2 ? cio2->chip_info : NULL;
317
318 if (!cio2_config) {
319 printk(BIOS_ERR, "Failed to get CIO2 config\n");
320 } else if (cio2_config->device_type != INTEL_ACPI_CAMERA_CIO2) {
321 printk(BIOS_ERR, "Device type isn't CIO2: %u\n",
322 (u32)cio2_config->device_type);
323 } else if (config->ssdb.link_used >= cio2_config->cio2_num_ports) {
324 printk(BIOS_ERR, "%u exceeds CIO2's %u links\n",
325 (u32)config->ssdb.link_used,
326 (u32)cio2_config->cio2_num_ports);
327 } else {
328 config->ssdb.lanes_used =
329 cio2_config->cio2_lanes_used[config->ssdb.link_used];
330 }
331 }
Matt Delco1245b1e2020-06-17 07:26:55 +0530332}
333
334/*
335 * Adds settings for a camera sensor device (typically at "\_SB.PCI0.I2Cx.CAMy"). The drivers
336 * for Linux tends to expect the camera sensor device and any related nvram / vcm devices to be
337 * separate ACPI devices, while the drivers for Windows want all of these to be grouped
338 * together in the camera sensor ACPI device. This implementation tries to satisfy both,
339 * though the unfortunate tradeoff is that the same I2C address for nvram and vcm is advertised
340 * by multiple devices in ACPI (via "_CRS"). The Windows driver can use the "_DSM" method to
341 * disambiguate the I2C resources in the camera sensor ACPI device. Drivers for Windows
342 * typically query "SSDB" for configuration information (represented as a binary blob dump of
343 * struct), while Linux drivers typically consult individual parameters in "_DSD".
344 *
345 * The tree of tables in "_DSD" is analogous to what's used for the "CIO2" device. The _DSD
346 * specifies a child table for the sensor's port (e.g., PRT0 for "port0"--this implementation
347 * assumes a camera only has 1 port). The PRT0 table specifies a table for each endpoint
348 * (though only 1 endpoint is supported by this implementation so the table only has an
349 * "endpoint0" that points to a EP00 table). The EP00 table primarily describes the # of lanes
350 * in "data-lines", a list of frequencies in "list-frequencies", and specifies the name of the
351 * other side in "remote-endpoint" (typically "\_SB.PCI0.CIO2").
352 */
353static void camera_fill_sensor(const struct device *dev)
354{
355 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
356 struct acpi_dp *ep00 = NULL;
357 struct acpi_dp *prt0 = NULL;
358 struct acpi_dp *dsd = NULL;
359 struct acpi_dp *remote = NULL;
360 const char *vcm_name = NULL;
361 struct acpi_dp *lens_focus = NULL;
Matt Delco879b3c12020-06-17 13:10:22 +0530362 const char *remote_name;
363 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
Matt Delco1245b1e2020-06-17 07:26:55 +0530364
Matt Delco1ffee9d2020-06-17 12:55:35 +0530365 camera_generate_pld(dev);
366
Matt Delco879b3c12020-06-17 13:10:22 +0530367 camera_fill_ssdb_defaults(config);
Matt Delco1245b1e2020-06-17 07:26:55 +0530368
Matt Delco964033f2020-06-17 12:49:43 +0530369 /* _DSM */
370 camera_generate_dsm(dev);
371
Matt Delco1245b1e2020-06-17 07:26:55 +0530372 ep00 = acpi_dp_new_table("EP00");
373 acpi_dp_add_integer(ep00, "endpoint", DEFAULT_ENDPOINT);
374 acpi_dp_add_integer(ep00, "clock-lanes", 0);
375
376 if (config->ssdb.lanes_used > 0) {
377 struct acpi_dp *lanes = acpi_dp_new_table("data-lanes");
378 uint32_t i;
379 for (i = 1; i <= config->ssdb.lanes_used; ++i)
380 acpi_dp_add_integer(lanes, NULL, i);
381 acpi_dp_add_array(ep00, lanes);
382 }
383
384 if (config->num_freq_entries) {
385 struct acpi_dp *freq = acpi_dp_new_table("link-frequencies");
386 uint32_t i;
387 for (i = 0; i < config->num_freq_entries && i < MAX_LINK_FREQ_ENTRIES; ++i)
388 acpi_dp_add_integer(freq, NULL, config->link_freq[i]);
389 acpi_dp_add_array(ep00, freq);
390 }
391
392 remote = acpi_dp_new_table("remote-endpoint");
393
Matt Delco879b3c12020-06-17 13:10:22 +0530394 if (config->remote_name) {
395 remote_name = config->remote_name;
396 } else {
397 if (cio2)
398 remote_name = acpi_device_path(cio2);
399 else
400 remote_name = DEFAULT_REMOTE_NAME;
401 }
402
403 acpi_dp_add_reference(remote, NULL, remote_name);
Matt Delco1245b1e2020-06-17 07:26:55 +0530404 acpi_dp_add_integer(remote, NULL, config->ssdb.link_used);
405 acpi_dp_add_integer(remote, NULL, DEFAULT_ENDPOINT);
406 acpi_dp_add_array(ep00, remote);
407
408 prt0 = acpi_dp_new_table("PRT0");
409
410 acpi_dp_add_integer(prt0, "port", 0);
411 acpi_dp_add_child(prt0, "endpoint0", ep00);
412 dsd = acpi_dp_new_table("_DSD");
413
414 acpi_dp_add_integer(dsd, "clock-frequency", config->ssdb.mclk_speed);
415
416 if (config->ssdb.degree)
417 acpi_dp_add_integer(dsd, "rotation", 180);
418
419 if (config->ssdb.vcm_type) {
420 if (config->vcm_name) {
421 vcm_name = config->vcm_name;
422 } else {
423 const struct device_path path = {
424 .type = DEVICE_PATH_I2C,
425 .i2c.device = config->vcm_address,
426 };
427 struct device *vcm_dev = find_dev_path(dev->bus, &path);
428 struct drivers_intel_mipi_camera_config *vcm_config;
429 vcm_config = vcm_dev ? vcm_dev->chip_info : NULL;
430
431 if (!vcm_config)
432 printk(BIOS_ERR, "Failed to get VCM\n");
433 else if (vcm_config->device_type != INTEL_ACPI_CAMERA_VCM)
434 printk(BIOS_ERR, "Device isn't VCM\n");
435 else
436 vcm_name = acpi_device_path(vcm_dev);
437 }
438 }
439
440 if (vcm_name) {
441 lens_focus = acpi_dp_new_table("lens-focus");
442 acpi_dp_add_reference(lens_focus, NULL, vcm_name);
443 acpi_dp_add_array(dsd, lens_focus);
444 }
445
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530446 if (config->low_power_probe)
447 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
448
Matt Delco1245b1e2020-06-17 07:26:55 +0530449 acpi_dp_add_child(dsd, "port0", prt0);
450 acpi_dp_write(dsd);
451
452 acpigen_write_method_serialized("SSDB", 0);
453 acpigen_write_return_byte_buffer((uint8_t *)&config->ssdb, sizeof(config->ssdb));
454 acpigen_pop_len(); /* Method */
455
456 /* Fill Power Sequencing Data */
457 if (config->num_pwdb_entries > 0) {
458 acpigen_write_method_serialized("PWDB", 0);
459 acpigen_write_return_byte_buffer((uint8_t *)&config->pwdb,
460 sizeof(struct intel_pwdb) *
461 config->num_pwdb_entries);
462 acpigen_pop_len(); /* Method */
463 }
464}
465
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530466static void camera_fill_nvm(const struct device *dev)
467{
468 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
John Zhao388e5512020-09-18 11:54:05 -0700469 struct acpi_dp *dsd;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530470
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530471 if (!config->nvm_compat)
472 return;
473
John Zhao388e5512020-09-18 11:54:05 -0700474 dsd = acpi_dp_new_table("_DSD");
475
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530476 /* It might be possible to default size or width based on type. */
477 if (!config->disable_nvm_defaults && !config->nvm_pagesize)
478 config->nvm_pagesize = 1;
479
480 if (!config->disable_nvm_defaults && !config->nvm_readonly)
481 config->nvm_readonly = 1;
482
483 if (config->nvm_size)
484 acpi_dp_add_integer(dsd, "size", config->nvm_size);
485
486 if (config->nvm_pagesize)
487 acpi_dp_add_integer(dsd, "pagesize", config->nvm_pagesize);
488
489 if (config->nvm_readonly)
490 acpi_dp_add_integer(dsd, "read-only", config->nvm_readonly);
491
492 if (config->nvm_width)
493 acpi_dp_add_integer(dsd, "address-width", config->nvm_width);
494
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530495 acpi_dp_add_string(dsd, "compatible", config->nvm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530496
497 if (config->low_power_probe)
498 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
499
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530500 acpi_dp_write(dsd);
501}
502
503static void camera_fill_vcm(const struct device *dev)
504{
505 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
506 struct acpi_dp *dsd;
507
508 if (!config->vcm_compat)
509 return;
510
511 dsd = acpi_dp_new_table("_DSD");
512 acpi_dp_add_string(dsd, "compatible", config->vcm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530513
514 if (config->low_power_probe)
515 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
516
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530517 acpi_dp_write(dsd);
518}
519
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530520static int get_resource_index(const struct resource_config *res_config)
521{
522 enum ctrl_type type = resource_get_ctrl_type(res_config);
523 const struct clk_config *clk_config;
524 const struct gpio_config *gpio_config;
525 unsigned int i;
526 uint8_t res_id;
527
528 switch (type) {
529 case IMGCLK:
530 clk_config = resource_clk_config(res_config);
531 res_id = clk_config->clknum;
532 break;
533 case GPIO:
534 gpio_config = resource_gpio_config(res_config);
535 res_id = gpio_config->gpio_num;
536 break;
537 default:
538 printk(BIOS_ERR, "Unsupported power operation: %x\n"
539 "OS camera driver will likely not work", type);
540 return -1;
541 }
542
543 for (i = 0; i < res_mgr.cnt; i++)
544 if (res_mgr.resource[i].type == type && res_mgr.resource[i].id == res_id)
545 return i;
546
547 return -1;
548}
549
550static void add_guarded_method_namestring(struct resource_config *res_config, int res_index)
551{
552 char method_name[ACPI_NAME_BUFFER_SIZE];
553 enum action_type action = resource_get_action_type(res_config);
554
555 switch (action) {
556 case ENABLE:
557 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
558 break;
559 case DISABLE:
560 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
561 break;
562 default:
563 snprintf(method_name, sizeof(method_name), UNKNOWN_METHOD_FORMAT, res_index);
564 printk(BIOS_ERR, "Unsupported resource action: %x\n", action);
565 }
566
567 acpigen_emit_namestring(method_name);
568}
569
570static void call_guarded_method(struct resource_config *res_config)
571{
572 int res_index;
573
574 if (res_config == NULL)
575 return;
576
577 res_index = get_resource_index(res_config);
578
579 if (res_index != -1)
580 add_guarded_method_namestring(res_config, res_index);
581}
582
583static void add_clk_op(const struct clk_config *clk_config, enum action_type action)
584{
585 if (clk_config == NULL)
586 return;
587
588 switch (action) {
589 case ENABLE:
590 acpigen_write_if();
591 acpigen_emit_ext_op(COND_REFOF_OP);
592 acpigen_emit_string(CLK_ENABLE_METHOD);
593 acpigen_emit_namestring(CLK_ENABLE_METHOD);
594 acpigen_write_integer(clk_config->clknum);
595 acpigen_write_integer(clk_config->freq);
596 acpigen_pop_len(); /* CondRefOf */
597 break;
598 case DISABLE:
599 acpigen_write_if();
600 acpigen_emit_ext_op(COND_REFOF_OP);
601 acpigen_emit_string(CLK_DISABLE_METHOD);
602 acpigen_emit_namestring(CLK_DISABLE_METHOD);
603 acpigen_write_integer(clk_config->clknum);
604 acpigen_pop_len(); /* CondRefOf */
605 break;
606 default:
607 acpigen_write_debug_string("Unsupported clock action");
608 printk(BIOS_ERR, "Unsupported clock action: %x\n"
609 "OS camera driver will likely not work", action);
610 }
611}
612
613static void add_gpio_op(const struct gpio_config *gpio_config, enum action_type action)
614{
615 if (gpio_config == NULL)
616 return;
617
618 switch (action) {
619 case ENABLE:
620 acpigen_soc_set_tx_gpio(gpio_config->gpio_num);
621 break;
622 case DISABLE:
623 acpigen_soc_clear_tx_gpio(gpio_config->gpio_num);
624 break;
625 default:
626 acpigen_write_debug_string("Unsupported GPIO action");
627 printk(BIOS_ERR, "Unsupported GPIO action: %x\n"
628 "OS camera driver will likely not work\n", action);
629 }
630}
631
632static void add_power_operation(const struct resource_config *res_config)
633{
634 const struct clk_config *clk_config;
635 const struct gpio_config *gpio_config;
636 enum ctrl_type type = resource_get_ctrl_type(res_config);
637 enum action_type action = resource_get_action_type(res_config);
638
639 if (res_config == NULL)
640 return;
641
642 switch (type) {
643 case IMGCLK:
644 clk_config = resource_clk_config(res_config);
645 add_clk_op(clk_config, action);
646 break;
647 case GPIO:
648 gpio_config = resource_gpio_config(res_config);
649 add_gpio_op(gpio_config, action);
650 break;
651 default:
652 printk(BIOS_ERR, "Unsupported power operation: %x\n"
653 "OS camera driver will likely not work\n", type);
654 break;
655 }
656}
657
658static void write_guard_variable(uint8_t res_index)
659{
660 char varname[ACPI_NAME_BUFFER_SIZE];
661
662 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
663 acpigen_write_name_integer(varname, 0);
664}
665
666static void write_enable_method(struct resource_config *res_config, uint8_t res_index)
667{
668 char method_name[ACPI_NAME_BUFFER_SIZE];
669 char varname[ACPI_NAME_BUFFER_SIZE];
670
671 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
672
673 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
674
675 acpigen_write_method_serialized(method_name, 0);
676 acpigen_write_if_lequal_namestr_int(varname, 0);
677 resource_set_action_type(res_config, ENABLE);
678 add_power_operation(res_config);
679 acpigen_pop_len(); /* if */
680
681 acpigen_emit_byte(INCREMENT_OP);
682 acpigen_emit_namestring(varname);
683 acpigen_pop_len(); /* method_name */
684}
685
686static void write_disable_method(struct resource_config *res_config, uint8_t res_index)
687{
688 char method_name[ACPI_NAME_BUFFER_SIZE];
689 char varname[ACPI_NAME_BUFFER_SIZE];
690
691 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
692
693 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
694
695 acpigen_write_method_serialized(method_name, 0);
696 acpigen_write_if();
697 acpigen_emit_byte(LGREATER_OP);
698 acpigen_emit_namestring(varname);
699 acpigen_write_integer(0x0);
700 acpigen_emit_byte(DECREMENT_OP);
701 acpigen_emit_namestring(varname);
702 acpigen_pop_len(); /* if */
703
704 acpigen_write_if_lequal_namestr_int(varname, 0);
705 resource_set_action_type(res_config, DISABLE);
706 add_power_operation(res_config);
707 acpigen_pop_len(); /* if */
708 acpigen_pop_len(); /* method_name */
709}
710
711static void add_guarded_operations(const struct drivers_intel_mipi_camera_config *config,
712 const struct operation_seq *seq)
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530713{
714 unsigned int i;
715 uint8_t index;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530716 uint8_t res_id;
717 struct resource_config res_config;
718 int res_index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530719
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530720 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
721 index = seq->ops[i].index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530722 switch (seq->ops[i].type) {
723 case IMGCLK:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530724 res_id = config->clk_panel.clks[index].clknum;
725 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530726 break;
727 case GPIO:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530728 res_id = config->gpio_panel.gpio[index].gpio_num;
729 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530730 break;
731 default:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530732 printk(BIOS_ERR, "Unsupported power operation: %x\n"
733 "OS camera driver will likely not work\n",
734 seq->ops[i].type);
735 return;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530736 }
737
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530738 res_index = get_resource_index(&res_config);
739
740 if (res_index == -1) {
741 if (res_mgr.cnt >= MAX_GUARDED_RESOURCES) {
742 printk(BIOS_ERR, "Unable to add guarded camera resource\n"
743 "OS camera driver will likely not work\n");
744 return;
745 }
746
747 res_mgr.resource[res_mgr.cnt].id = res_id;
748 res_mgr.resource[res_mgr.cnt].type = seq->ops[i].type;
749
750 write_guard_variable(res_mgr.cnt);
751 write_enable_method(&res_config, res_mgr.cnt);
752 write_disable_method(&res_config, res_mgr.cnt);
753
754 res_mgr.cnt++;
755 }
756 }
757}
758
759static void fill_power_res_sequence(struct drivers_intel_mipi_camera_config *config,
760 struct operation_seq *seq)
761{
762 struct resource_config res_config;
763 unsigned int i;
764 uint8_t index;
765
766 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
767 index = seq->ops[i].index;
768
769 switch (seq->ops[i].type) {
770 case IMGCLK:
771 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
772 break;
773 case GPIO:
774 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
775 break;
776 default:
777 printk(BIOS_ERR, "Unsupported power operation: %x\n"
778 "OS camera driver will likely not work\n",
779 seq->ops[i].type);
780 return;
781 }
782
783 resource_set_action_type(&res_config, seq->ops[i].action);
784 call_guarded_method(&res_config);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530785 if (seq->ops[i].delay_ms)
786 acpigen_write_sleep(seq->ops[i].delay_ms);
787 }
788}
789
Matt Delco7d002932020-06-16 11:39:52 +0530790static void write_pci_camera_device(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530791{
Matt Delco7d002932020-06-16 11:39:52 +0530792 if (dev->path.type != DEVICE_PATH_PCI) {
793 printk(BIOS_ERR, "CIO2/IMGU devices require PCI\n");
794 return;
795 }
796
797 acpigen_write_device(acpi_device_name(dev));
798 acpigen_write_ADR_pci_device(dev);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530799 acpigen_write_name_string("_DDN", "Camera and Imaging Subsystem");
Matt Delco7d002932020-06-16 11:39:52 +0530800}
801
802static void write_i2c_camera_device(const struct device *dev, const char *scope)
803{
804 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
V Sowmya9f8023a2017-02-28 17:52:05 +0530805 struct acpi_i2c i2c = {
806 .address = dev->path.i2c.device,
807 .mode_10bit = dev->path.i2c.mode_10bit,
808 .speed = I2C_SPEED_FAST,
809 .resource = scope,
810 };
811
V Sowmya9f8023a2017-02-28 17:52:05 +0530812 acpigen_write_device(acpi_device_name(dev));
Matt Delco7d002932020-06-16 11:39:52 +0530813
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530814 /* add power resource */
815 if (config->has_power_resource) {
816 acpigen_write_power_res(POWER_RESOURCE_NAME, 0, 0, NULL, 0);
817 acpigen_write_name_integer("STA", 0);
818 acpigen_write_STA_ext("STA");
819
820 acpigen_write_method_serialized("_ON", 0);
821 acpigen_write_if();
822 acpigen_emit_byte(LEQUAL_OP);
823 acpigen_emit_namestring("STA");
824 acpigen_write_integer(0);
825
826 fill_power_res_sequence(config, &config->on_seq);
827
828 acpigen_write_store_op_to_namestr(1, "STA");
829 acpigen_pop_len(); /* if */
830 acpigen_pop_len(); /* _ON */
831
832 /* _OFF operations */
833 acpigen_write_method_serialized("_OFF", 0);
834 acpigen_write_if();
835 acpigen_emit_byte(LEQUAL_OP);
836 acpigen_emit_namestring("STA");
837 acpigen_write_integer(1);
838
839 fill_power_res_sequence(config, &config->off_seq);
840
841 acpigen_write_store_op_to_namestr(0, "STA");
842 acpigen_pop_len(); /* if */
843 acpigen_pop_len(); /* _ON */
844
845 acpigen_pop_len(); /* Power Resource */
846 }
847
Matt Delco7d002932020-06-16 11:39:52 +0530848 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR)
849 acpigen_write_name_integer("_ADR", 0);
850
851 if (config->acpi_hid)
852 acpigen_write_name_string("_HID", config->acpi_hid);
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530853 else if (config->device_type == INTEL_ACPI_CAMERA_VCM ||
854 config->device_type == INTEL_ACPI_CAMERA_NVM)
Matt Delco7d002932020-06-16 11:39:52 +0530855 acpigen_write_name_string("_HID", ACPI_DT_NAMESPACE_HID);
Matt Delco7d002932020-06-16 11:39:52 +0530856
V Sowmya9f8023a2017-02-28 17:52:05 +0530857 acpigen_write_name_integer("_UID", config->acpi_uid);
858 acpigen_write_name_string("_DDN", config->chip_name);
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800859 acpigen_write_STA(acpi_device_status(dev));
Varshit B Pandya04e8c2b2021-10-27 10:41:32 +0530860 acpigen_write_method("_DSC", 0);
861 acpigen_write_return_integer(config->max_dstate_for_probe);
862 acpigen_pop_len(); /* Method _DSC */
V Sowmya9f8023a2017-02-28 17:52:05 +0530863
864 /* Resources */
865 acpigen_write_name("_CRS");
866 acpigen_write_resourcetemplate_header();
867 acpi_device_write_i2c(&i2c);
V Sowmya9f8023a2017-02-28 17:52:05 +0530868
Matt Delco7d002932020-06-16 11:39:52 +0530869 /*
870 * The optional vcm/nvram devices are presumed to be on the same I2C bus as the camera
871 * sensor.
872 */
873 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
874 config->ssdb.vcm_type && config->vcm_address) {
875 struct acpi_i2c i2c_vcm = i2c;
876 i2c_vcm.address = config->vcm_address;
877 acpi_device_write_i2c(&i2c_vcm);
V Sowmya9f8023a2017-02-28 17:52:05 +0530878 }
879
Matt Delco7d002932020-06-16 11:39:52 +0530880 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
881 config->ssdb.rom_type && config->rom_address) {
882 struct acpi_i2c i2c_rom = i2c;
883 i2c_rom.address = config->rom_address;
884 acpi_device_write_i2c(&i2c_rom);
885 }
886
887 acpigen_write_resourcetemplate_footer();
888}
889
890static void write_camera_device_common(const struct device *dev)
891{
892 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
893
894 /* Mark it as Camera related device */
895 if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
896 config->device_type == INTEL_ACPI_CAMERA_IMGU ||
897 config->device_type == INTEL_ACPI_CAMERA_SENSOR ||
898 config->device_type == INTEL_ACPI_CAMERA_VCM) {
899 acpigen_write_name_integer("CAMD", config->device_type);
900 }
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530901
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530902 if (config->pr0 || config->has_power_resource) {
903 acpigen_write_name("_PR0");
904 acpigen_write_package(1);
905 if (config->pr0)
906 acpigen_emit_namestring(config->pr0); /* External power resource */
907 else
908 acpigen_emit_namestring(POWER_RESOURCE_NAME);
909
910 acpigen_pop_len(); /* _PR0 */
911 }
912
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530913 switch (config->device_type) {
Matt Delco879b3c12020-06-17 13:10:22 +0530914 case INTEL_ACPI_CAMERA_CIO2:
915 camera_fill_cio2(dev);
916 break;
Matt Delco1245b1e2020-06-17 07:26:55 +0530917 case INTEL_ACPI_CAMERA_SENSOR:
918 camera_fill_sensor(dev);
919 break;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530920 case INTEL_ACPI_CAMERA_VCM:
921 camera_fill_vcm(dev);
922 break;
923 case INTEL_ACPI_CAMERA_NVM:
924 camera_fill_nvm(dev);
925 break;
926 default:
927 break;
928 }
Matt Delco7d002932020-06-16 11:39:52 +0530929}
930
931static void camera_fill_ssdt(const struct device *dev)
932{
933 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530934 const char *scope = NULL;
935 const struct device *pdev;
Matt Delco7d002932020-06-16 11:39:52 +0530936
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530937 if (config->has_power_resource) {
938 pdev = dev->bus->dev;
939 if (!pdev || !pdev->enabled)
940 return;
941
942 scope = acpi_device_scope(pdev);
943 if (!scope)
944 return;
945
946 acpigen_write_scope(scope);
947 add_guarded_operations(config, &config->on_seq);
948 add_guarded_operations(config, &config->off_seq);
949 acpigen_pop_len(); /* Guarded power resource operations scope */
950 }
951
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530952 switch (dev->path.type) {
953 case DEVICE_PATH_I2C:
954 scope = acpi_device_scope(dev);
955 if (!scope)
956 return;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530957
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530958 acpigen_write_scope(scope);
Matt Delco7d002932020-06-16 11:39:52 +0530959 write_i2c_camera_device(dev, scope);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530960 break;
961 case DEVICE_PATH_GENERIC:
962 pdev = dev->bus->dev;
963 scope = acpi_device_scope(pdev);
964 if (!scope)
965 return;
966
967 acpigen_write_scope(scope);
968 write_pci_camera_device(pdev);
969 break;
970 default:
971 printk(BIOS_ERR, "Unsupported device type: %x\n"
972 "OS camera driver will likely not work\n", dev->path.type);
973 return;
974 }
Matt Delco7d002932020-06-16 11:39:52 +0530975
976 write_camera_device_common(dev);
V Sowmya9f8023a2017-02-28 17:52:05 +0530977
978 acpigen_pop_len(); /* Device */
979 acpigen_pop_len(); /* Scope */
Matt Delco7d002932020-06-16 11:39:52 +0530980
981 if (dev->path.type == DEVICE_PATH_PCI) {
982 printk(BIOS_INFO, "%s: %s PCI address 0%x\n", acpi_device_path(dev),
983 dev->chip_ops->name, dev->path.pci.devfn);
984 } else {
985 printk(BIOS_INFO, "%s: %s I2C address 0%xh\n", acpi_device_path(dev),
986 dev->chip_ops->name, dev->path.i2c.device);
987 }
V Sowmya9f8023a2017-02-28 17:52:05 +0530988}
989
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600990static const char *camera_acpi_name(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530991{
Matt Delco7d002932020-06-16 11:39:52 +0530992 const char *prefix = NULL;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530993 static char name[ACPI_NAME_BUFFER_SIZE];
V Sowmya9f8023a2017-02-28 17:52:05 +0530994 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Matt Delco7d002932020-06-16 11:39:52 +0530995
996 if (config->acpi_name)
997 return config->acpi_name;
998
999 switch (config->device_type) {
1000 case INTEL_ACPI_CAMERA_CIO2:
1001 return "CIO2";
1002 case INTEL_ACPI_CAMERA_IMGU:
1003 return "IMGU";
1004 case INTEL_ACPI_CAMERA_PMIC:
1005 return "PMIC";
1006 case INTEL_ACPI_CAMERA_SENSOR:
1007 prefix = "CAM";
1008 break;
1009 case INTEL_ACPI_CAMERA_VCM:
1010 prefix = "VCM";
1011 break;
1012 case INTEL_ACPI_CAMERA_NVM:
1013 prefix = "NVM";
1014 break;
1015 default:
1016 printk(BIOS_ERR, "Invalid device type: %x\n", config->device_type);
1017 return NULL;
1018 }
1019
1020 /*
1021 * The camera # knows which link # they use, so that's used as the basis for the
1022 * instance #. The VCM and NVM don't have this information, so the best we can go on is
1023 * the _UID.
1024 */
1025 snprintf(name, sizeof(name), "%s%1u", prefix,
1026 config->device_type == INTEL_ACPI_CAMERA_SENSOR ?
1027 config->ssdb.link_used : config->acpi_uid);
1028 return name;
V Sowmya9f8023a2017-02-28 17:52:05 +05301029}
1030
1031static struct device_operations camera_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +02001032 .read_resources = noop_read_resources,
1033 .set_resources = noop_set_resources,
Nico Huber68680dd2020-03-31 17:34:52 +02001034 .acpi_name = camera_acpi_name,
1035 .acpi_fill_ssdt = camera_fill_ssdt,
V Sowmya9f8023a2017-02-28 17:52:05 +05301036};
1037
1038static void camera_enable(struct device *dev)
1039{
1040 dev->ops = &camera_ops;
1041}
1042
1043struct chip_operations drivers_intel_mipi_camera_ops = {
1044 CHIP_NAME("Intel MIPI Camera Device")
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +01001045 .enable_dev = camera_enable
V Sowmya9f8023a2017-02-28 17:52:05 +05301046};