blob: 4044a268965ca8242f439ad1c1493c9dc2ae2664 [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);
Jamie Ryud6f30922023-09-11 15:38:46 -0700137 acpi_dp_add_integer(dsd, "is_es",
138 CONFIG(DRIVERS_INTEL_MIPI_SUPPORTS_PRE_PRODUCTION_SOC));
Matt Delco879b3c12020-06-17 13:10:22 +0530139 acpi_dp_add_child(dsd, port_name[i], port_table);
140 }
141
142 acpi_dp_write(dsd);
143
144 for (i = 0; i < config->cio2_num_ports; ++i) {
145 free(ep_table_name[i]);
146 free(port_table_name[i]);
147 free(port_name[i]);
148 }
149}
Matt Delco1245b1e2020-06-17 07:26:55 +0530150
Matt Delco1ffee9d2020-06-17 12:55:35 +0530151static void apply_pld_defaults(struct drivers_intel_mipi_camera_config *config)
152{
153 if (!config->pld.ignore_color)
154 config->pld.ignore_color = 1;
155
156 if (!config->pld.visible)
157 config->pld.visible = 1;
158
159 if (!config->pld.vertical_offset)
160 config->pld.vertical_offset = 0xffff;
161
162 if (!config->pld.horizontal_offset)
163 config->pld.horizontal_offset = 0xffff;
164
165 /*
166 * PLD_PANEL_TOP has a value of zero, so the following will change any instance of
167 * PLD_PANEL_TOP to PLD_PANEL_FRONT unless disable_pld_defaults is set.
168 */
169 if (!config->pld.panel)
170 config->pld.panel = PLD_PANEL_FRONT;
171
172 /*
173 * PLD_HORIZONTAL_POSITION_LEFT has a value of zero, so the following will change any
174 * instance of that value to PLD_HORIZONTAL_POSITION_CENTER unless disable_pld_defaults
175 * is set.
176 */
177 if (!config->pld.horizontal_position)
178 config->pld.horizontal_position = PLD_HORIZONTAL_POSITION_CENTER;
179
180 /*
181 * The desired default for |vertical_position| is PLD_VERTICAL_POSITION_UPPER, which
182 * has a value of zero so no work is needed to set a default. The same applies for
183 * setting |shape| to PLD_SHAPE_ROUND.
184 */
185}
186
187static void camera_generate_pld(const struct device *dev)
188{
189 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
190
191 if (config->use_pld) {
192 if (!config->disable_pld_defaults)
193 apply_pld_defaults(config);
194
195 acpigen_write_pld(&config->pld);
196 }
197}
198
Matt Delco964033f2020-06-17 12:49:43 +0530199static uint32_t address_for_dev_type(const struct device *dev, uint8_t dev_type)
200{
201 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200202 uint16_t i2c_bus = dev->upstream ? dev->upstream->secondary : 0xFFFF;
Matt Delco964033f2020-06-17 12:49:43 +0530203 uint16_t i2c_addr;
204
205 switch (dev_type) {
206 case DEV_TYPE_SENSOR:
207 i2c_addr = dev->path.i2c.device;
208 break;
209 case DEV_TYPE_VCM:
210 i2c_addr = config->vcm_address;
211 break;
212 case DEV_TYPE_ROM:
213 i2c_addr = config->rom_address;
214 break;
215 default:
216 return 0;
217 }
218
219 return (((uint32_t)i2c_bus) << 24 | ((uint32_t)i2c_addr) << 8 | dev_type);
220}
221
222static void camera_generate_dsm(const struct device *dev)
223{
224 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
225 int local1_ret = 1 + (config->ssdb.vcm_type ? 1 : 0) + (config->ssdb.rom_type ? 1 : 0);
226 int next_local1 = 1;
227 /* Method (_DSM, 4, NotSerialized) */
228 acpigen_write_method("_DSM", 4);
229
230 /* ToBuffer (Arg0, Local0) */
231 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
232
233 /* If (LEqual (Local0, ToUUID(uuid))) */
234 acpigen_write_if();
235 acpigen_emit_byte(LEQUAL_OP);
236 acpigen_emit_byte(LOCAL0_OP);
237 acpigen_write_uuid(SENSOR_NAME_UUID);
238 acpigen_write_return_string(config->sensor_name ? config->sensor_name : "UNKNOWN");
239 acpigen_pop_len(); /* If */
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_TYPE_UUID);
246 /* ToInteger (Arg2, Local1) */
247 acpigen_write_to_integer(ARG2_OP, LOCAL1_OP);
248
249 /* If (LEqual (Local1, 1)) */
250 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
251 acpigen_write_return_integer(local1_ret);
252 acpigen_pop_len(); /* If Arg2=1 */
253
254 /* If (LEqual (Local1, 2)) */
255 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
256 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_SENSOR));
257 acpigen_pop_len(); /* If Arg2=2 */
258
259 if (config->ssdb.vcm_type) {
260 /* If (LEqual (Local1, 3)) */
261 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
262 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_VCM));
263 acpigen_pop_len(); /* If Arg2=3 */
264 }
265
266 if (config->ssdb.rom_type) {
267 /* If (LEqual (Local1, 3 or 4)) */
268 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1);
269 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_ROM));
270 acpigen_pop_len(); /* If Arg2=3 or 4 */
271 }
272
273 acpigen_pop_len(); /* If uuid */
274
275 /* Return (Buffer (One) { 0x0 }) */
276 acpigen_write_return_singleton_buffer(0x0);
277
278 acpigen_pop_len(); /* Method _DSM */
279}
280
Matt Delco879b3c12020-06-17 13:10:22 +0530281static void camera_fill_ssdb_defaults(struct drivers_intel_mipi_camera_config *config)
Matt Delco1245b1e2020-06-17 07:26:55 +0530282{
Matt Delco879b3c12020-06-17 13:10:22 +0530283 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
284 struct drivers_intel_mipi_camera_config *cio2_config;
285
Matt Delco1245b1e2020-06-17 07:26:55 +0530286 if (config->disable_ssdb_defaults)
287 return;
288
Matt Delco879b3c12020-06-17 13:10:22 +0530289 if (!config->ssdb.bdf_value)
290 config->ssdb.bdf_value = PCI_DEVFN(CIO2_PCI_DEV, CIO2_PCI_FN);
291
Matt Delco1245b1e2020-06-17 07:26:55 +0530292 if (!config->ssdb.platform)
293 config->ssdb.platform = PLATFORM_SKC;
294
295 if (!config->ssdb.flash_support)
296 config->ssdb.flash_support = FLASH_DISABLE;
297
298 if (!config->ssdb.privacy_led)
299 config->ssdb.privacy_led = PRIVACY_LED_A_16mA;
300
301 if (!config->ssdb.mipi_define)
302 config->ssdb.mipi_define = MIPI_INFO_ACPI_DEFINED;
303
304 if (!config->ssdb.mclk_speed)
305 config->ssdb.mclk_speed = CLK_FREQ_19_2MHZ;
Matt Delco879b3c12020-06-17 13:10:22 +0530306
307 if (!config->ssdb.lanes_used) {
308 cio2_config = cio2 ? cio2->chip_info : NULL;
309
310 if (!cio2_config) {
311 printk(BIOS_ERR, "Failed to get CIO2 config\n");
312 } else if (cio2_config->device_type != INTEL_ACPI_CAMERA_CIO2) {
313 printk(BIOS_ERR, "Device type isn't CIO2: %u\n",
314 (u32)cio2_config->device_type);
315 } else if (config->ssdb.link_used >= cio2_config->cio2_num_ports) {
316 printk(BIOS_ERR, "%u exceeds CIO2's %u links\n",
317 (u32)config->ssdb.link_used,
318 (u32)cio2_config->cio2_num_ports);
319 } else {
320 config->ssdb.lanes_used =
321 cio2_config->cio2_lanes_used[config->ssdb.link_used];
322 }
323 }
Matt Delco1245b1e2020-06-17 07:26:55 +0530324}
325
326/*
327 * Adds settings for a camera sensor device (typically at "\_SB.PCI0.I2Cx.CAMy"). The drivers
328 * for Linux tends to expect the camera sensor device and any related nvram / vcm devices to be
329 * separate ACPI devices, while the drivers for Windows want all of these to be grouped
330 * together in the camera sensor ACPI device. This implementation tries to satisfy both,
331 * though the unfortunate tradeoff is that the same I2C address for nvram and vcm is advertised
332 * by multiple devices in ACPI (via "_CRS"). The Windows driver can use the "_DSM" method to
333 * disambiguate the I2C resources in the camera sensor ACPI device. Drivers for Windows
334 * typically query "SSDB" for configuration information (represented as a binary blob dump of
335 * struct), while Linux drivers typically consult individual parameters in "_DSD".
336 *
337 * The tree of tables in "_DSD" is analogous to what's used for the "CIO2" device. The _DSD
338 * specifies a child table for the sensor's port (e.g., PRT0 for "port0"--this implementation
339 * assumes a camera only has 1 port). The PRT0 table specifies a table for each endpoint
340 * (though only 1 endpoint is supported by this implementation so the table only has an
341 * "endpoint0" that points to a EP00 table). The EP00 table primarily describes the # of lanes
342 * in "data-lines", a list of frequencies in "list-frequencies", and specifies the name of the
343 * other side in "remote-endpoint" (typically "\_SB.PCI0.CIO2").
344 */
345static void camera_fill_sensor(const struct device *dev)
346{
347 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
348 struct acpi_dp *ep00 = NULL;
349 struct acpi_dp *prt0 = NULL;
350 struct acpi_dp *dsd = NULL;
351 struct acpi_dp *remote = NULL;
352 const char *vcm_name = NULL;
353 struct acpi_dp *lens_focus = NULL;
Matt Delco879b3c12020-06-17 13:10:22 +0530354 const char *remote_name;
355 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
Matt Delco1245b1e2020-06-17 07:26:55 +0530356
Matt Delco1ffee9d2020-06-17 12:55:35 +0530357 camera_generate_pld(dev);
358
Matt Delco879b3c12020-06-17 13:10:22 +0530359 camera_fill_ssdb_defaults(config);
Matt Delco1245b1e2020-06-17 07:26:55 +0530360
Matt Delco964033f2020-06-17 12:49:43 +0530361 /* _DSM */
362 camera_generate_dsm(dev);
363
Matt Delco1245b1e2020-06-17 07:26:55 +0530364 ep00 = acpi_dp_new_table("EP00");
365 acpi_dp_add_integer(ep00, "endpoint", DEFAULT_ENDPOINT);
366 acpi_dp_add_integer(ep00, "clock-lanes", 0);
367
368 if (config->ssdb.lanes_used > 0) {
369 struct acpi_dp *lanes = acpi_dp_new_table("data-lanes");
370 uint32_t i;
371 for (i = 1; i <= config->ssdb.lanes_used; ++i)
372 acpi_dp_add_integer(lanes, NULL, i);
373 acpi_dp_add_array(ep00, lanes);
374 }
375
376 if (config->num_freq_entries) {
377 struct acpi_dp *freq = acpi_dp_new_table("link-frequencies");
378 uint32_t i;
379 for (i = 0; i < config->num_freq_entries && i < MAX_LINK_FREQ_ENTRIES; ++i)
380 acpi_dp_add_integer(freq, NULL, config->link_freq[i]);
381 acpi_dp_add_array(ep00, freq);
382 }
383
384 remote = acpi_dp_new_table("remote-endpoint");
385
Matt Delco879b3c12020-06-17 13:10:22 +0530386 if (config->remote_name) {
387 remote_name = config->remote_name;
388 } else {
389 if (cio2)
390 remote_name = acpi_device_path(cio2);
391 else
392 remote_name = DEFAULT_REMOTE_NAME;
393 }
394
395 acpi_dp_add_reference(remote, NULL, remote_name);
Matt Delco1245b1e2020-06-17 07:26:55 +0530396 acpi_dp_add_integer(remote, NULL, config->ssdb.link_used);
397 acpi_dp_add_integer(remote, NULL, DEFAULT_ENDPOINT);
398 acpi_dp_add_array(ep00, remote);
399
400 prt0 = acpi_dp_new_table("PRT0");
401
402 acpi_dp_add_integer(prt0, "port", 0);
403 acpi_dp_add_child(prt0, "endpoint0", ep00);
404 dsd = acpi_dp_new_table("_DSD");
405
406 acpi_dp_add_integer(dsd, "clock-frequency", config->ssdb.mclk_speed);
407
408 if (config->ssdb.degree)
409 acpi_dp_add_integer(dsd, "rotation", 180);
410
411 if (config->ssdb.vcm_type) {
412 if (config->vcm_name) {
413 vcm_name = config->vcm_name;
414 } else {
415 const struct device_path path = {
416 .type = DEVICE_PATH_I2C,
417 .i2c.device = config->vcm_address,
418 };
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200419 struct device *vcm_dev = find_dev_path(dev->upstream, &path);
Matt Delco1245b1e2020-06-17 07:26:55 +0530420 struct drivers_intel_mipi_camera_config *vcm_config;
421 vcm_config = vcm_dev ? vcm_dev->chip_info : NULL;
422
423 if (!vcm_config)
424 printk(BIOS_ERR, "Failed to get VCM\n");
425 else if (vcm_config->device_type != INTEL_ACPI_CAMERA_VCM)
426 printk(BIOS_ERR, "Device isn't VCM\n");
427 else
428 vcm_name = acpi_device_path(vcm_dev);
429 }
430 }
431
432 if (vcm_name) {
433 lens_focus = acpi_dp_new_table("lens-focus");
434 acpi_dp_add_reference(lens_focus, NULL, vcm_name);
435 acpi_dp_add_array(dsd, lens_focus);
436 }
437
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530438 if (config->low_power_probe)
439 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
440
Matt Delco1245b1e2020-06-17 07:26:55 +0530441 acpi_dp_add_child(dsd, "port0", prt0);
442 acpi_dp_write(dsd);
443
444 acpigen_write_method_serialized("SSDB", 0);
445 acpigen_write_return_byte_buffer((uint8_t *)&config->ssdb, sizeof(config->ssdb));
446 acpigen_pop_len(); /* Method */
447
448 /* Fill Power Sequencing Data */
449 if (config->num_pwdb_entries > 0) {
450 acpigen_write_method_serialized("PWDB", 0);
451 acpigen_write_return_byte_buffer((uint8_t *)&config->pwdb,
452 sizeof(struct intel_pwdb) *
453 config->num_pwdb_entries);
454 acpigen_pop_len(); /* Method */
455 }
456}
457
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530458static void camera_fill_nvm(const struct device *dev)
459{
460 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
John Zhao388e5512020-09-18 11:54:05 -0700461 struct acpi_dp *dsd;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530462
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530463 if (!config->nvm_compat)
464 return;
465
John Zhao388e5512020-09-18 11:54:05 -0700466 dsd = acpi_dp_new_table("_DSD");
467
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530468 /* It might be possible to default size or width based on type. */
469 if (!config->disable_nvm_defaults && !config->nvm_pagesize)
470 config->nvm_pagesize = 1;
471
472 if (!config->disable_nvm_defaults && !config->nvm_readonly)
473 config->nvm_readonly = 1;
474
475 if (config->nvm_size)
476 acpi_dp_add_integer(dsd, "size", config->nvm_size);
477
478 if (config->nvm_pagesize)
479 acpi_dp_add_integer(dsd, "pagesize", config->nvm_pagesize);
480
481 if (config->nvm_readonly)
482 acpi_dp_add_integer(dsd, "read-only", config->nvm_readonly);
483
484 if (config->nvm_width)
485 acpi_dp_add_integer(dsd, "address-width", config->nvm_width);
486
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530487 acpi_dp_add_string(dsd, "compatible", config->nvm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530488
489 if (config->low_power_probe)
490 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
491
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530492 acpi_dp_write(dsd);
493}
494
495static void camera_fill_vcm(const struct device *dev)
496{
497 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
498 struct acpi_dp *dsd;
499
500 if (!config->vcm_compat)
501 return;
502
503 dsd = acpi_dp_new_table("_DSD");
504 acpi_dp_add_string(dsd, "compatible", config->vcm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530505
506 if (config->low_power_probe)
507 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
508
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530509 acpi_dp_write(dsd);
510}
511
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530512static int get_resource_index(const struct resource_config *res_config)
513{
514 enum ctrl_type type = resource_get_ctrl_type(res_config);
515 const struct clk_config *clk_config;
516 const struct gpio_config *gpio_config;
517 unsigned int i;
518 uint8_t res_id;
519
520 switch (type) {
521 case IMGCLK:
522 clk_config = resource_clk_config(res_config);
523 res_id = clk_config->clknum;
524 break;
525 case GPIO:
526 gpio_config = resource_gpio_config(res_config);
527 res_id = gpio_config->gpio_num;
528 break;
529 default:
530 printk(BIOS_ERR, "Unsupported power operation: %x\n"
531 "OS camera driver will likely not work", type);
532 return -1;
533 }
534
535 for (i = 0; i < res_mgr.cnt; i++)
536 if (res_mgr.resource[i].type == type && res_mgr.resource[i].id == res_id)
537 return i;
538
539 return -1;
540}
541
542static void add_guarded_method_namestring(struct resource_config *res_config, int res_index)
543{
544 char method_name[ACPI_NAME_BUFFER_SIZE];
545 enum action_type action = resource_get_action_type(res_config);
546
547 switch (action) {
548 case ENABLE:
549 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
550 break;
551 case DISABLE:
552 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
553 break;
554 default:
555 snprintf(method_name, sizeof(method_name), UNKNOWN_METHOD_FORMAT, res_index);
556 printk(BIOS_ERR, "Unsupported resource action: %x\n", action);
557 }
558
559 acpigen_emit_namestring(method_name);
560}
561
562static void call_guarded_method(struct resource_config *res_config)
563{
564 int res_index;
565
566 if (res_config == NULL)
567 return;
568
569 res_index = get_resource_index(res_config);
570
571 if (res_index != -1)
572 add_guarded_method_namestring(res_config, res_index);
573}
574
575static void add_clk_op(const struct clk_config *clk_config, enum action_type action)
576{
577 if (clk_config == NULL)
578 return;
579
580 switch (action) {
581 case ENABLE:
582 acpigen_write_if();
583 acpigen_emit_ext_op(COND_REFOF_OP);
584 acpigen_emit_string(CLK_ENABLE_METHOD);
585 acpigen_emit_namestring(CLK_ENABLE_METHOD);
586 acpigen_write_integer(clk_config->clknum);
587 acpigen_write_integer(clk_config->freq);
588 acpigen_pop_len(); /* CondRefOf */
589 break;
590 case DISABLE:
591 acpigen_write_if();
592 acpigen_emit_ext_op(COND_REFOF_OP);
593 acpigen_emit_string(CLK_DISABLE_METHOD);
594 acpigen_emit_namestring(CLK_DISABLE_METHOD);
595 acpigen_write_integer(clk_config->clknum);
596 acpigen_pop_len(); /* CondRefOf */
597 break;
598 default:
599 acpigen_write_debug_string("Unsupported clock action");
600 printk(BIOS_ERR, "Unsupported clock action: %x\n"
601 "OS camera driver will likely not work", action);
602 }
603}
604
605static void add_gpio_op(const struct gpio_config *gpio_config, enum action_type action)
606{
607 if (gpio_config == NULL)
608 return;
609
610 switch (action) {
611 case ENABLE:
612 acpigen_soc_set_tx_gpio(gpio_config->gpio_num);
613 break;
614 case DISABLE:
615 acpigen_soc_clear_tx_gpio(gpio_config->gpio_num);
616 break;
617 default:
618 acpigen_write_debug_string("Unsupported GPIO action");
619 printk(BIOS_ERR, "Unsupported GPIO action: %x\n"
620 "OS camera driver will likely not work\n", action);
621 }
622}
623
624static void add_power_operation(const struct resource_config *res_config)
625{
626 const struct clk_config *clk_config;
627 const struct gpio_config *gpio_config;
628 enum ctrl_type type = resource_get_ctrl_type(res_config);
629 enum action_type action = resource_get_action_type(res_config);
630
631 if (res_config == NULL)
632 return;
633
634 switch (type) {
635 case IMGCLK:
636 clk_config = resource_clk_config(res_config);
637 add_clk_op(clk_config, action);
638 break;
639 case GPIO:
640 gpio_config = resource_gpio_config(res_config);
641 add_gpio_op(gpio_config, action);
642 break;
643 default:
644 printk(BIOS_ERR, "Unsupported power operation: %x\n"
645 "OS camera driver will likely not work\n", type);
646 break;
647 }
648}
649
650static void write_guard_variable(uint8_t res_index)
651{
652 char varname[ACPI_NAME_BUFFER_SIZE];
653
654 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
655 acpigen_write_name_integer(varname, 0);
656}
657
658static void write_enable_method(struct resource_config *res_config, uint8_t res_index)
659{
660 char method_name[ACPI_NAME_BUFFER_SIZE];
661 char varname[ACPI_NAME_BUFFER_SIZE];
662
663 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
664
665 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
666
667 acpigen_write_method_serialized(method_name, 0);
668 acpigen_write_if_lequal_namestr_int(varname, 0);
669 resource_set_action_type(res_config, ENABLE);
670 add_power_operation(res_config);
671 acpigen_pop_len(); /* if */
672
673 acpigen_emit_byte(INCREMENT_OP);
674 acpigen_emit_namestring(varname);
675 acpigen_pop_len(); /* method_name */
676}
677
678static void write_disable_method(struct resource_config *res_config, uint8_t res_index)
679{
680 char method_name[ACPI_NAME_BUFFER_SIZE];
681 char varname[ACPI_NAME_BUFFER_SIZE];
682
683 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
684
685 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
686
687 acpigen_write_method_serialized(method_name, 0);
688 acpigen_write_if();
689 acpigen_emit_byte(LGREATER_OP);
690 acpigen_emit_namestring(varname);
691 acpigen_write_integer(0x0);
692 acpigen_emit_byte(DECREMENT_OP);
693 acpigen_emit_namestring(varname);
694 acpigen_pop_len(); /* if */
695
696 acpigen_write_if_lequal_namestr_int(varname, 0);
697 resource_set_action_type(res_config, DISABLE);
698 add_power_operation(res_config);
699 acpigen_pop_len(); /* if */
700 acpigen_pop_len(); /* method_name */
701}
702
703static void add_guarded_operations(const struct drivers_intel_mipi_camera_config *config,
704 const struct operation_seq *seq)
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530705{
706 unsigned int i;
707 uint8_t index;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530708 uint8_t res_id;
709 struct resource_config res_config;
710 int res_index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530711
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530712 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
713 index = seq->ops[i].index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530714 switch (seq->ops[i].type) {
715 case IMGCLK:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530716 res_id = config->clk_panel.clks[index].clknum;
717 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530718 break;
719 case GPIO:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530720 res_id = config->gpio_panel.gpio[index].gpio_num;
721 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530722 break;
723 default:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530724 printk(BIOS_ERR, "Unsupported power operation: %x\n"
725 "OS camera driver will likely not work\n",
726 seq->ops[i].type);
727 return;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530728 }
729
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530730 res_index = get_resource_index(&res_config);
731
732 if (res_index == -1) {
733 if (res_mgr.cnt >= MAX_GUARDED_RESOURCES) {
734 printk(BIOS_ERR, "Unable to add guarded camera resource\n"
735 "OS camera driver will likely not work\n");
736 return;
737 }
738
739 res_mgr.resource[res_mgr.cnt].id = res_id;
740 res_mgr.resource[res_mgr.cnt].type = seq->ops[i].type;
741
742 write_guard_variable(res_mgr.cnt);
743 write_enable_method(&res_config, res_mgr.cnt);
744 write_disable_method(&res_config, res_mgr.cnt);
745
746 res_mgr.cnt++;
747 }
748 }
749}
750
751static void fill_power_res_sequence(struct drivers_intel_mipi_camera_config *config,
752 struct operation_seq *seq)
753{
754 struct resource_config res_config;
755 unsigned int i;
756 uint8_t index;
757
758 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
759 index = seq->ops[i].index;
760
761 switch (seq->ops[i].type) {
762 case IMGCLK:
763 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
764 break;
765 case GPIO:
766 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
767 break;
768 default:
769 printk(BIOS_ERR, "Unsupported power operation: %x\n"
770 "OS camera driver will likely not work\n",
771 seq->ops[i].type);
772 return;
773 }
774
775 resource_set_action_type(&res_config, seq->ops[i].action);
776 call_guarded_method(&res_config);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530777 if (seq->ops[i].delay_ms)
778 acpigen_write_sleep(seq->ops[i].delay_ms);
779 }
780}
781
Matt Delco7d002932020-06-16 11:39:52 +0530782static void write_pci_camera_device(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530783{
Matt Delco7d002932020-06-16 11:39:52 +0530784 if (dev->path.type != DEVICE_PATH_PCI) {
785 printk(BIOS_ERR, "CIO2/IMGU devices require PCI\n");
786 return;
787 }
788
789 acpigen_write_device(acpi_device_name(dev));
790 acpigen_write_ADR_pci_device(dev);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530791 acpigen_write_name_string("_DDN", "Camera and Imaging Subsystem");
Matt Delco7d002932020-06-16 11:39:52 +0530792}
793
794static void write_i2c_camera_device(const struct device *dev, const char *scope)
795{
796 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
V Sowmya9f8023a2017-02-28 17:52:05 +0530797 struct acpi_i2c i2c = {
798 .address = dev->path.i2c.device,
799 .mode_10bit = dev->path.i2c.mode_10bit,
800 .speed = I2C_SPEED_FAST,
801 .resource = scope,
802 };
803
V Sowmya9f8023a2017-02-28 17:52:05 +0530804 acpigen_write_device(acpi_device_name(dev));
Matt Delco7d002932020-06-16 11:39:52 +0530805
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530806 /* add power resource */
807 if (config->has_power_resource) {
808 acpigen_write_power_res(POWER_RESOURCE_NAME, 0, 0, NULL, 0);
809 acpigen_write_name_integer("STA", 0);
810 acpigen_write_STA_ext("STA");
811
812 acpigen_write_method_serialized("_ON", 0);
813 acpigen_write_if();
814 acpigen_emit_byte(LEQUAL_OP);
815 acpigen_emit_namestring("STA");
816 acpigen_write_integer(0);
817
818 fill_power_res_sequence(config, &config->on_seq);
819
820 acpigen_write_store_op_to_namestr(1, "STA");
821 acpigen_pop_len(); /* if */
822 acpigen_pop_len(); /* _ON */
823
824 /* _OFF operations */
825 acpigen_write_method_serialized("_OFF", 0);
826 acpigen_write_if();
827 acpigen_emit_byte(LEQUAL_OP);
828 acpigen_emit_namestring("STA");
829 acpigen_write_integer(1);
830
831 fill_power_res_sequence(config, &config->off_seq);
832
833 acpigen_write_store_op_to_namestr(0, "STA");
834 acpigen_pop_len(); /* if */
835 acpigen_pop_len(); /* _ON */
836
837 acpigen_pop_len(); /* Power Resource */
838 }
839
Matt Delco7d002932020-06-16 11:39:52 +0530840 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR)
841 acpigen_write_name_integer("_ADR", 0);
842
843 if (config->acpi_hid)
844 acpigen_write_name_string("_HID", config->acpi_hid);
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530845 else if (config->device_type == INTEL_ACPI_CAMERA_VCM ||
846 config->device_type == INTEL_ACPI_CAMERA_NVM)
Matt Delco7d002932020-06-16 11:39:52 +0530847 acpigen_write_name_string("_HID", ACPI_DT_NAMESPACE_HID);
Matt Delco7d002932020-06-16 11:39:52 +0530848
V Sowmya9f8023a2017-02-28 17:52:05 +0530849 acpigen_write_name_integer("_UID", config->acpi_uid);
850 acpigen_write_name_string("_DDN", config->chip_name);
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800851 acpigen_write_STA(acpi_device_status(dev));
Varshit B Pandya04e8c2b2021-10-27 10:41:32 +0530852 acpigen_write_method("_DSC", 0);
853 acpigen_write_return_integer(config->max_dstate_for_probe);
854 acpigen_pop_len(); /* Method _DSC */
V Sowmya9f8023a2017-02-28 17:52:05 +0530855
856 /* Resources */
857 acpigen_write_name("_CRS");
858 acpigen_write_resourcetemplate_header();
859 acpi_device_write_i2c(&i2c);
V Sowmya9f8023a2017-02-28 17:52:05 +0530860
Matt Delco7d002932020-06-16 11:39:52 +0530861 /*
862 * The optional vcm/nvram devices are presumed to be on the same I2C bus as the camera
863 * sensor.
864 */
865 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
866 config->ssdb.vcm_type && config->vcm_address) {
867 struct acpi_i2c i2c_vcm = i2c;
868 i2c_vcm.address = config->vcm_address;
869 acpi_device_write_i2c(&i2c_vcm);
V Sowmya9f8023a2017-02-28 17:52:05 +0530870 }
871
Matt Delco7d002932020-06-16 11:39:52 +0530872 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
873 config->ssdb.rom_type && config->rom_address) {
874 struct acpi_i2c i2c_rom = i2c;
875 i2c_rom.address = config->rom_address;
876 acpi_device_write_i2c(&i2c_rom);
877 }
878
879 acpigen_write_resourcetemplate_footer();
880}
881
882static void write_camera_device_common(const struct device *dev)
883{
884 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
885
886 /* Mark it as Camera related device */
887 if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
888 config->device_type == INTEL_ACPI_CAMERA_IMGU ||
889 config->device_type == INTEL_ACPI_CAMERA_SENSOR ||
890 config->device_type == INTEL_ACPI_CAMERA_VCM) {
891 acpigen_write_name_integer("CAMD", config->device_type);
892 }
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530893
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530894 if (config->pr0 || config->has_power_resource) {
895 acpigen_write_name("_PR0");
896 acpigen_write_package(1);
897 if (config->pr0)
898 acpigen_emit_namestring(config->pr0); /* External power resource */
899 else
900 acpigen_emit_namestring(POWER_RESOURCE_NAME);
901
902 acpigen_pop_len(); /* _PR0 */
903 }
904
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530905 switch (config->device_type) {
Matt Delco879b3c12020-06-17 13:10:22 +0530906 case INTEL_ACPI_CAMERA_CIO2:
907 camera_fill_cio2(dev);
908 break;
Matt Delco1245b1e2020-06-17 07:26:55 +0530909 case INTEL_ACPI_CAMERA_SENSOR:
910 camera_fill_sensor(dev);
911 break;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530912 case INTEL_ACPI_CAMERA_VCM:
913 camera_fill_vcm(dev);
914 break;
915 case INTEL_ACPI_CAMERA_NVM:
916 camera_fill_nvm(dev);
917 break;
918 default:
919 break;
920 }
Matt Delco7d002932020-06-16 11:39:52 +0530921}
922
923static void camera_fill_ssdt(const struct device *dev)
924{
925 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530926 const char *scope = NULL;
927 const struct device *pdev;
Matt Delco7d002932020-06-16 11:39:52 +0530928
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530929 if (config->has_power_resource) {
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200930 pdev = dev->upstream->dev;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530931 if (!pdev || !pdev->enabled)
932 return;
933
934 scope = acpi_device_scope(pdev);
935 if (!scope)
936 return;
937
938 acpigen_write_scope(scope);
939 add_guarded_operations(config, &config->on_seq);
940 add_guarded_operations(config, &config->off_seq);
941 acpigen_pop_len(); /* Guarded power resource operations scope */
942 }
943
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530944 switch (dev->path.type) {
945 case DEVICE_PATH_I2C:
946 scope = acpi_device_scope(dev);
947 if (!scope)
948 return;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530949
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530950 acpigen_write_scope(scope);
Matt Delco7d002932020-06-16 11:39:52 +0530951 write_i2c_camera_device(dev, scope);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530952 break;
953 case DEVICE_PATH_GENERIC:
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200954 pdev = dev->upstream->dev;
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530955 scope = acpi_device_scope(pdev);
956 if (!scope)
957 return;
958
959 acpigen_write_scope(scope);
960 write_pci_camera_device(pdev);
961 break;
962 default:
963 printk(BIOS_ERR, "Unsupported device type: %x\n"
964 "OS camera driver will likely not work\n", dev->path.type);
965 return;
966 }
Matt Delco7d002932020-06-16 11:39:52 +0530967
968 write_camera_device_common(dev);
V Sowmya9f8023a2017-02-28 17:52:05 +0530969
970 acpigen_pop_len(); /* Device */
971 acpigen_pop_len(); /* Scope */
Matt Delco7d002932020-06-16 11:39:52 +0530972
973 if (dev->path.type == DEVICE_PATH_PCI) {
974 printk(BIOS_INFO, "%s: %s PCI address 0%x\n", acpi_device_path(dev),
975 dev->chip_ops->name, dev->path.pci.devfn);
976 } else {
977 printk(BIOS_INFO, "%s: %s I2C address 0%xh\n", acpi_device_path(dev),
978 dev->chip_ops->name, dev->path.i2c.device);
979 }
V Sowmya9f8023a2017-02-28 17:52:05 +0530980}
981
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600982static const char *camera_acpi_name(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530983{
Matt Delco7d002932020-06-16 11:39:52 +0530984 const char *prefix = NULL;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530985 static char name[ACPI_NAME_BUFFER_SIZE];
V Sowmya9f8023a2017-02-28 17:52:05 +0530986 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Matt Delco7d002932020-06-16 11:39:52 +0530987
988 if (config->acpi_name)
989 return config->acpi_name;
990
991 switch (config->device_type) {
992 case INTEL_ACPI_CAMERA_CIO2:
993 return "CIO2";
994 case INTEL_ACPI_CAMERA_IMGU:
995 return "IMGU";
996 case INTEL_ACPI_CAMERA_PMIC:
997 return "PMIC";
998 case INTEL_ACPI_CAMERA_SENSOR:
999 prefix = "CAM";
1000 break;
1001 case INTEL_ACPI_CAMERA_VCM:
1002 prefix = "VCM";
1003 break;
1004 case INTEL_ACPI_CAMERA_NVM:
1005 prefix = "NVM";
1006 break;
1007 default:
1008 printk(BIOS_ERR, "Invalid device type: %x\n", config->device_type);
1009 return NULL;
1010 }
1011
1012 /*
1013 * The camera # knows which link # they use, so that's used as the basis for the
1014 * instance #. The VCM and NVM don't have this information, so the best we can go on is
1015 * the _UID.
1016 */
1017 snprintf(name, sizeof(name), "%s%1u", prefix,
1018 config->device_type == INTEL_ACPI_CAMERA_SENSOR ?
1019 config->ssdb.link_used : config->acpi_uid);
1020 return name;
V Sowmya9f8023a2017-02-28 17:52:05 +05301021}
1022
1023static struct device_operations camera_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +02001024 .read_resources = noop_read_resources,
1025 .set_resources = noop_set_resources,
Nico Huber68680dd2020-03-31 17:34:52 +02001026 .acpi_name = camera_acpi_name,
1027 .acpi_fill_ssdt = camera_fill_ssdt,
V Sowmya9f8023a2017-02-28 17:52:05 +05301028};
1029
1030static void camera_enable(struct device *dev)
1031{
1032 dev->ops = &camera_ops;
1033}
1034
1035struct chip_operations drivers_intel_mipi_camera_ops = {
Nicholas Sudsgaardbfb11be2024-01-30 09:53:46 +09001036 .name = "Intel MIPI Camera Device",
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +01001037 .enable_dev = camera_enable
V Sowmya9f8023a2017-02-28 17:52:05 +05301038};