blob: 5230a2ac3fa1a8a127e4a8342c4d71747d31b266 [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
Furquan Shaikh76cedd22020-05-02 10:24:23 -07003#include <acpi/acpi.h>
4#include <acpi/acpi_device.h>
5#include <acpi/acpigen.h>
V Sowmya9f8023a2017-02-28 17:52:05 +05306#include <console/console.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02007#include <device/i2c_simple.h>
V Sowmya9f8023a2017-02-28 17:52:05 +05308#include <device/device.h>
9#include <device/path.h>
Matt Delco7d002932020-06-16 11:39:52 +053010#include <device/pci_def.h>
V Sowmya9f8023a2017-02-28 17:52:05 +053011#include "chip.h"
12
Matt Delco1245b1e2020-06-17 07:26:55 +053013#define SENSOR_NAME_UUID "822ace8f-2814-4174-a56b-5f029fe079ee"
14#define SENSOR_TYPE_UUID "26257549-9271-4ca4-bb43-c4899d5a4881"
15#define DEFAULT_ENDPOINT 0
16
17static void camera_fill_sensor_defaults(struct drivers_intel_mipi_camera_config *config)
18{
19 if (config->disable_ssdb_defaults)
20 return;
21
22 if (!config->ssdb.platform)
23 config->ssdb.platform = PLATFORM_SKC;
24
25 if (!config->ssdb.flash_support)
26 config->ssdb.flash_support = FLASH_DISABLE;
27
28 if (!config->ssdb.privacy_led)
29 config->ssdb.privacy_led = PRIVACY_LED_A_16mA;
30
31 if (!config->ssdb.mipi_define)
32 config->ssdb.mipi_define = MIPI_INFO_ACPI_DEFINED;
33
34 if (!config->ssdb.mclk_speed)
35 config->ssdb.mclk_speed = CLK_FREQ_19_2MHZ;
36}
37
38/*
39 * Adds settings for a camera sensor device (typically at "\_SB.PCI0.I2Cx.CAMy"). The drivers
40 * for Linux tends to expect the camera sensor device and any related nvram / vcm devices to be
41 * separate ACPI devices, while the drivers for Windows want all of these to be grouped
42 * together in the camera sensor ACPI device. This implementation tries to satisfy both,
43 * though the unfortunate tradeoff is that the same I2C address for nvram and vcm is advertised
44 * by multiple devices in ACPI (via "_CRS"). The Windows driver can use the "_DSM" method to
45 * disambiguate the I2C resources in the camera sensor ACPI device. Drivers for Windows
46 * typically query "SSDB" for configuration information (represented as a binary blob dump of
47 * struct), while Linux drivers typically consult individual parameters in "_DSD".
48 *
49 * The tree of tables in "_DSD" is analogous to what's used for the "CIO2" device. The _DSD
50 * specifies a child table for the sensor's port (e.g., PRT0 for "port0"--this implementation
51 * assumes a camera only has 1 port). The PRT0 table specifies a table for each endpoint
52 * (though only 1 endpoint is supported by this implementation so the table only has an
53 * "endpoint0" that points to a EP00 table). The EP00 table primarily describes the # of lanes
54 * in "data-lines", a list of frequencies in "list-frequencies", and specifies the name of the
55 * other side in "remote-endpoint" (typically "\_SB.PCI0.CIO2").
56 */
57static void camera_fill_sensor(const struct device *dev)
58{
59 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
60 struct acpi_dp *ep00 = NULL;
61 struct acpi_dp *prt0 = NULL;
62 struct acpi_dp *dsd = NULL;
63 struct acpi_dp *remote = NULL;
64 const char *vcm_name = NULL;
65 struct acpi_dp *lens_focus = NULL;
66
67 camera_fill_sensor_defaults(config);
68
69 ep00 = acpi_dp_new_table("EP00");
70 acpi_dp_add_integer(ep00, "endpoint", DEFAULT_ENDPOINT);
71 acpi_dp_add_integer(ep00, "clock-lanes", 0);
72
73 if (config->ssdb.lanes_used > 0) {
74 struct acpi_dp *lanes = acpi_dp_new_table("data-lanes");
75 uint32_t i;
76 for (i = 1; i <= config->ssdb.lanes_used; ++i)
77 acpi_dp_add_integer(lanes, NULL, i);
78 acpi_dp_add_array(ep00, lanes);
79 }
80
81 if (config->num_freq_entries) {
82 struct acpi_dp *freq = acpi_dp_new_table("link-frequencies");
83 uint32_t i;
84 for (i = 0; i < config->num_freq_entries && i < MAX_LINK_FREQ_ENTRIES; ++i)
85 acpi_dp_add_integer(freq, NULL, config->link_freq[i]);
86 acpi_dp_add_array(ep00, freq);
87 }
88
89 remote = acpi_dp_new_table("remote-endpoint");
90
91 acpi_dp_add_reference(remote, NULL, config->remote_name);
92 acpi_dp_add_integer(remote, NULL, config->ssdb.link_used);
93 acpi_dp_add_integer(remote, NULL, DEFAULT_ENDPOINT);
94 acpi_dp_add_array(ep00, remote);
95
96 prt0 = acpi_dp_new_table("PRT0");
97
98 acpi_dp_add_integer(prt0, "port", 0);
99 acpi_dp_add_child(prt0, "endpoint0", ep00);
100 dsd = acpi_dp_new_table("_DSD");
101
102 acpi_dp_add_integer(dsd, "clock-frequency", config->ssdb.mclk_speed);
103
104 if (config->ssdb.degree)
105 acpi_dp_add_integer(dsd, "rotation", 180);
106
107 if (config->ssdb.vcm_type) {
108 if (config->vcm_name) {
109 vcm_name = config->vcm_name;
110 } else {
111 const struct device_path path = {
112 .type = DEVICE_PATH_I2C,
113 .i2c.device = config->vcm_address,
114 };
115 struct device *vcm_dev = find_dev_path(dev->bus, &path);
116 struct drivers_intel_mipi_camera_config *vcm_config;
117 vcm_config = vcm_dev ? vcm_dev->chip_info : NULL;
118
119 if (!vcm_config)
120 printk(BIOS_ERR, "Failed to get VCM\n");
121 else if (vcm_config->device_type != INTEL_ACPI_CAMERA_VCM)
122 printk(BIOS_ERR, "Device isn't VCM\n");
123 else
124 vcm_name = acpi_device_path(vcm_dev);
125 }
126 }
127
128 if (vcm_name) {
129 lens_focus = acpi_dp_new_table("lens-focus");
130 acpi_dp_add_reference(lens_focus, NULL, vcm_name);
131 acpi_dp_add_array(dsd, lens_focus);
132 }
133
134 acpi_dp_add_child(dsd, "port0", prt0);
135 acpi_dp_write(dsd);
136
137 acpigen_write_method_serialized("SSDB", 0);
138 acpigen_write_return_byte_buffer((uint8_t *)&config->ssdb, sizeof(config->ssdb));
139 acpigen_pop_len(); /* Method */
140
141 /* Fill Power Sequencing Data */
142 if (config->num_pwdb_entries > 0) {
143 acpigen_write_method_serialized("PWDB", 0);
144 acpigen_write_return_byte_buffer((uint8_t *)&config->pwdb,
145 sizeof(struct intel_pwdb) *
146 config->num_pwdb_entries);
147 acpigen_pop_len(); /* Method */
148 }
149}
150
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530151static void camera_fill_nvm(const struct device *dev)
152{
153 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
154 struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
155
156 /* It might be possible to default size or width based on type. */
157 if (!config->disable_nvm_defaults && !config->nvm_pagesize)
158 config->nvm_pagesize = 1;
159
160 if (!config->disable_nvm_defaults && !config->nvm_readonly)
161 config->nvm_readonly = 1;
162
163 if (config->nvm_size)
164 acpi_dp_add_integer(dsd, "size", config->nvm_size);
165
166 if (config->nvm_pagesize)
167 acpi_dp_add_integer(dsd, "pagesize", config->nvm_pagesize);
168
169 if (config->nvm_readonly)
170 acpi_dp_add_integer(dsd, "read-only", config->nvm_readonly);
171
172 if (config->nvm_width)
173 acpi_dp_add_integer(dsd, "address-width", config->nvm_width);
174
175 acpi_dp_write(dsd);
176}
177
178static void camera_fill_vcm(const struct device *dev)
179{
180 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
181 struct acpi_dp *dsd;
182
183 if (!config->vcm_compat)
184 return;
185
186 dsd = acpi_dp_new_table("_DSD");
187 acpi_dp_add_string(dsd, "compatible", config->vcm_compat);
188 acpi_dp_write(dsd);
189}
190
Matt Delco7d002932020-06-16 11:39:52 +0530191static void write_pci_camera_device(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530192{
193 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Matt Delco7d002932020-06-16 11:39:52 +0530194
195 if (dev->path.type != DEVICE_PATH_PCI) {
196 printk(BIOS_ERR, "CIO2/IMGU devices require PCI\n");
197 return;
198 }
199
200 acpigen_write_device(acpi_device_name(dev));
201 acpigen_write_ADR_pci_device(dev);
202 acpigen_write_name_string("_DDN", config->device_type == INTEL_ACPI_CAMERA_CIO2 ?
203 "Camera and Imaging Subsystem" : "Imaging Unit");
204}
205
206static void write_i2c_camera_device(const struct device *dev, const char *scope)
207{
208 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
V Sowmya9f8023a2017-02-28 17:52:05 +0530209 struct acpi_i2c i2c = {
210 .address = dev->path.i2c.device,
211 .mode_10bit = dev->path.i2c.mode_10bit,
212 .speed = I2C_SPEED_FAST,
213 .resource = scope,
214 };
215
Matt Delco7d002932020-06-16 11:39:52 +0530216 if (dev->path.type != DEVICE_PATH_I2C) {
217 printk(BIOS_ERR, "Non-CIO2/IMGU devices require I2C\n");
V Sowmya9f8023a2017-02-28 17:52:05 +0530218 return;
Matt Delco7d002932020-06-16 11:39:52 +0530219 }
V Sowmya9f8023a2017-02-28 17:52:05 +0530220
V Sowmya9f8023a2017-02-28 17:52:05 +0530221 acpigen_write_device(acpi_device_name(dev));
Matt Delco7d002932020-06-16 11:39:52 +0530222
223 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR)
224 acpigen_write_name_integer("_ADR", 0);
225
226 if (config->acpi_hid)
227 acpigen_write_name_string("_HID", config->acpi_hid);
228 else if (config->device_type == INTEL_ACPI_CAMERA_VCM)
229 acpigen_write_name_string("_HID", ACPI_DT_NAMESPACE_HID);
230 else if (config->device_type == INTEL_ACPI_CAMERA_NVM)
231 acpigen_write_name_string("_HID", "INT3499");
232
V Sowmya9f8023a2017-02-28 17:52:05 +0530233 acpigen_write_name_integer("_UID", config->acpi_uid);
234 acpigen_write_name_string("_DDN", config->chip_name);
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800235 acpigen_write_STA(acpi_device_status(dev));
V Sowmya9f8023a2017-02-28 17:52:05 +0530236
237 /* Resources */
238 acpigen_write_name("_CRS");
239 acpigen_write_resourcetemplate_header();
240 acpi_device_write_i2c(&i2c);
V Sowmya9f8023a2017-02-28 17:52:05 +0530241
Matt Delco7d002932020-06-16 11:39:52 +0530242 /*
243 * The optional vcm/nvram devices are presumed to be on the same I2C bus as the camera
244 * sensor.
245 */
246 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
247 config->ssdb.vcm_type && config->vcm_address) {
248 struct acpi_i2c i2c_vcm = i2c;
249 i2c_vcm.address = config->vcm_address;
250 acpi_device_write_i2c(&i2c_vcm);
V Sowmya9f8023a2017-02-28 17:52:05 +0530251 }
252
Matt Delco7d002932020-06-16 11:39:52 +0530253 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
254 config->ssdb.rom_type && config->rom_address) {
255 struct acpi_i2c i2c_rom = i2c;
256 i2c_rom.address = config->rom_address;
257 acpi_device_write_i2c(&i2c_rom);
258 }
259
260 acpigen_write_resourcetemplate_footer();
261}
262
263static void write_camera_device_common(const struct device *dev)
264{
265 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
266
267 /* Mark it as Camera related device */
268 if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
269 config->device_type == INTEL_ACPI_CAMERA_IMGU ||
270 config->device_type == INTEL_ACPI_CAMERA_SENSOR ||
271 config->device_type == INTEL_ACPI_CAMERA_VCM) {
272 acpigen_write_name_integer("CAMD", config->device_type);
273 }
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530274
275 switch (config->device_type) {
Matt Delco1245b1e2020-06-17 07:26:55 +0530276 case INTEL_ACPI_CAMERA_SENSOR:
277 camera_fill_sensor(dev);
278 break;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530279 case INTEL_ACPI_CAMERA_VCM:
280 camera_fill_vcm(dev);
281 break;
282 case INTEL_ACPI_CAMERA_NVM:
283 camera_fill_nvm(dev);
284 break;
285 default:
286 break;
287 }
Matt Delco7d002932020-06-16 11:39:52 +0530288}
289
290static void camera_fill_ssdt(const struct device *dev)
291{
292 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
293 const char *scope = acpi_device_scope(dev);
294
295 if (!dev->enabled || !scope)
296 return;
297
298 /* Device */
299 acpigen_write_scope(scope);
300
301 if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
302 config->device_type == INTEL_ACPI_CAMERA_IMGU)
303 write_pci_camera_device(dev);
304 else
305 write_i2c_camera_device(dev, scope);
306
307 write_camera_device_common(dev);
V Sowmya9f8023a2017-02-28 17:52:05 +0530308
309 acpigen_pop_len(); /* Device */
310 acpigen_pop_len(); /* Scope */
Matt Delco7d002932020-06-16 11:39:52 +0530311
312 if (dev->path.type == DEVICE_PATH_PCI) {
313 printk(BIOS_INFO, "%s: %s PCI address 0%x\n", acpi_device_path(dev),
314 dev->chip_ops->name, dev->path.pci.devfn);
315 } else {
316 printk(BIOS_INFO, "%s: %s I2C address 0%xh\n", acpi_device_path(dev),
317 dev->chip_ops->name, dev->path.i2c.device);
318 }
V Sowmya9f8023a2017-02-28 17:52:05 +0530319}
320
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600321static const char *camera_acpi_name(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530322{
Matt Delco7d002932020-06-16 11:39:52 +0530323 const char *prefix = NULL;
324 static char name[5];
V Sowmya9f8023a2017-02-28 17:52:05 +0530325 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Matt Delco7d002932020-06-16 11:39:52 +0530326
327 if (config->acpi_name)
328 return config->acpi_name;
329
330 switch (config->device_type) {
331 case INTEL_ACPI_CAMERA_CIO2:
332 return "CIO2";
333 case INTEL_ACPI_CAMERA_IMGU:
334 return "IMGU";
335 case INTEL_ACPI_CAMERA_PMIC:
336 return "PMIC";
337 case INTEL_ACPI_CAMERA_SENSOR:
338 prefix = "CAM";
339 break;
340 case INTEL_ACPI_CAMERA_VCM:
341 prefix = "VCM";
342 break;
343 case INTEL_ACPI_CAMERA_NVM:
344 prefix = "NVM";
345 break;
346 default:
347 printk(BIOS_ERR, "Invalid device type: %x\n", config->device_type);
348 return NULL;
349 }
350
351 /*
352 * The camera # knows which link # they use, so that's used as the basis for the
353 * instance #. The VCM and NVM don't have this information, so the best we can go on is
354 * the _UID.
355 */
356 snprintf(name, sizeof(name), "%s%1u", prefix,
357 config->device_type == INTEL_ACPI_CAMERA_SENSOR ?
358 config->ssdb.link_used : config->acpi_uid);
359 return name;
V Sowmya9f8023a2017-02-28 17:52:05 +0530360}
361
362static struct device_operations camera_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +0200363 .read_resources = noop_read_resources,
364 .set_resources = noop_set_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200365 .acpi_name = camera_acpi_name,
366 .acpi_fill_ssdt = camera_fill_ssdt,
V Sowmya9f8023a2017-02-28 17:52:05 +0530367};
368
369static void camera_enable(struct device *dev)
370{
371 dev->ops = &camera_ops;
372}
373
374struct chip_operations drivers_intel_mipi_camera_ops = {
375 CHIP_NAME("Intel MIPI Camera Device")
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100376 .enable_dev = camera_enable
V Sowmya9f8023a2017-02-28 17:52:05 +0530377};