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