1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3  * Rockchip ISP1 Driver - Base driver
4  *
5  * Copyright (C) 2019 Collabora, Ltd.
6  *
7  * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
8  * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
9  */
10 
11 #include <linux/clk.h>
12 #include <linux/debugfs.h>
13 #include <linux/interrupt.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/of_graph.h>
17 #include <linux/of_platform.h>
18 #include <linux/pinctrl/consumer.h>
19 #include <linux/phy/phy.h>
20 #include <linux/phy/phy-mipi-dphy.h>
21 #include <media/v4l2-fwnode.h>
22 
23 #include "rkisp1-common.h"
24 
25 /*
26  * ISP Details
27  * -----------
28  *
29  * ISP Comprises with:
30  *	MIPI serial camera interface
31  *	Image Signal Processing
32  *	Many Image Enhancement Blocks
33  *	Crop
34  *	Resizer
35  *	RBG display ready image
36  *	Image Rotation
37  *
38  * ISP Block Diagram
39  * -----------------
40  *                                                             rkisp1-resizer.c          rkisp1-capture.c
41  *                                                          |====================|  |=======================|
42  *                                rkisp1-isp.c                              Main Picture Path
43  *                        |==========================|      |===============================================|
44  *                        +-----------+  +--+--+--+--+      +--------+  +--------+              +-----------+
45  *                        |           |  |  |  |  |  |      |        |  |        |              |           |
46  * +--------+    |\       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |------------->|           |
47  * |  MIPI  |--->|  \     |           |  |  |  |  |  |   |  |        |  |        |              |           |
48  * +--------+    |   |    |           |  |IE|IE|IE|IE|   |  +--------+  +--------+              |  Memory   |
49  *               |MUX|--->|    ISP    |->|0 |1 |2 |3 |---+                                      | Interface |
50  * +--------+    |   |    |           |  |  |  |  |  |   |  +--------+  +--------+  +--------+  |           |
51  * |Parallel|--->|  /     |           |  |  |  |  |  |   |  |        |  |        |  |        |  |           |
52  * +--------+    |/       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |->|  RGB   |->|           |
53  *                        |           |  |  |  |  |  |      |        |  |        |  | Rotate |  |           |
54  *                        +-----------+  +--+--+--+--+      +--------+  +--------+  +--------+  +-----------+
55  *                                               ^
56  * +--------+                                    |          |===============================================|
57  * |  DMA   |------------------------------------+                          Self Picture Path
58  * +--------+
59  *
60  *         rkisp1-stats.c        rkisp1-params.c
61  *       |===============|      |===============|
62  *       +---------------+      +---------------+
63  *       |               |      |               |
64  *       |      ISP      |      |      ISP      |
65  *       |               |      |               |
66  *       +---------------+      +---------------+
67  *
68  *
69  * Media Topology
70  * --------------
71  *      +----------+     +----------+
72  *      | Sensor 2 |     | Sensor X |
73  *      ------------ ... ------------
74  *      |    0     |     |    0     |
75  *      +----------+     +----------+      +-----------+
76  *                  \      |               |  params   |
77  *                   \     |               | (output)  |
78  *    +----------+    \    |               +-----------+
79  *    | Sensor 1 |     v   v                     |
80  *    ------------      +------+------+          |
81  *    |    0     |----->|  0   |  1   |<---------+
82  *    +----------+      |------+------|
83  *                      |     ISP     |
84  *                      |------+------|
85  *        +-------------|  2   |  3   |----------+
86  *        |             +------+------+          |
87  *        |                |                     |
88  *        v                v                     v
89  *  +- ---------+    +-----------+         +-----------+
90  *  |     0     |    |     0     |         |   stats   |
91  *  -------------    -------------         | (capture) |
92  *  |  Resizer  |    |  Resizer  |         +-----------+
93  *  ------------|    ------------|
94  *  |     1     |    |     1     |
95  *  +-----------+    +-----------+
96  *        |                |
97  *        v                v
98  *  +-----------+    +-----------+
99  *  | selfpath  |    | mainpath  |
100  *  | (capture) |    | (capture) |
101  *  +-----------+    +-----------+
102  */
103 
104 struct rkisp1_isr_data {
105 	const char *name;
106 	irqreturn_t (*isr)(int irq, void *ctx);
107 };
108 
109 struct rkisp1_match_data {
110 	const char * const *clks;
111 	unsigned int clk_size;
112 	const struct rkisp1_isr_data *isrs;
113 	unsigned int isr_size;
114 	enum rkisp1_cif_isp_version isp_ver;
115 };
116 
117 /* ----------------------------------------------------------------------------
118  * Sensor DT bindings
119  */
120 
121 static int rkisp1_create_links(struct rkisp1_device *rkisp1)
122 {
123 	struct media_entity *source, *sink;
124 	unsigned int flags, source_pad;
125 	struct v4l2_subdev *sd;
126 	unsigned int i;
127 	int ret;
128 
129 	/* sensor links */
130 	flags = MEDIA_LNK_FL_ENABLED;
131 	list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) {
132 		if (sd == &rkisp1->isp.sd ||
133 		    sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd ||
134 		    sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd)
135 			continue;
136 
137 		ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode,
138 						  MEDIA_PAD_FL_SOURCE);
139 		if (ret < 0) {
140 			dev_err(rkisp1->dev, "failed to find src pad for %s\n",
141 				sd->name);
142 			return ret;
143 		}
144 		source_pad = ret;
145 
146 		ret = media_create_pad_link(&sd->entity, source_pad,
147 					    &rkisp1->isp.sd.entity,
148 					    RKISP1_ISP_PAD_SINK_VIDEO,
149 					    flags);
150 		if (ret)
151 			return ret;
152 
153 		flags = 0;
154 	}
155 
156 	flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
157 
158 	/* create ISP->RSZ->CAP links */
159 	for (i = 0; i < 2; i++) {
160 		source = &rkisp1->isp.sd.entity;
161 		sink = &rkisp1->resizer_devs[i].sd.entity;
162 		ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO,
163 					    sink, RKISP1_RSZ_PAD_SINK,
164 					    MEDIA_LNK_FL_ENABLED);
165 		if (ret)
166 			return ret;
167 
168 		source = sink;
169 		sink = &rkisp1->capture_devs[i].vnode.vdev.entity;
170 		ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC,
171 					    sink, 0, flags);
172 		if (ret)
173 			return ret;
174 	}
175 
176 	/* params links */
177 	source = &rkisp1->params.vnode.vdev.entity;
178 	sink = &rkisp1->isp.sd.entity;
179 	ret = media_create_pad_link(source, 0, sink,
180 				    RKISP1_ISP_PAD_SINK_PARAMS, flags);
181 	if (ret)
182 		return ret;
183 
184 	/* 3A stats links */
185 	source = &rkisp1->isp.sd.entity;
186 	sink = &rkisp1->stats.vnode.vdev.entity;
187 	return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS,
188 				     sink, 0, flags);
189 }
190 
191 static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
192 					struct v4l2_subdev *sd,
193 					struct v4l2_async_subdev *asd)
194 {
195 	struct rkisp1_device *rkisp1 =
196 		container_of(notifier, struct rkisp1_device, notifier);
197 	struct rkisp1_sensor_async *s_asd =
198 		container_of(asd, struct rkisp1_sensor_async, asd);
199 
200 	s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler,
201 						V4L2_CID_PIXEL_RATE);
202 	s_asd->sd = sd;
203 	s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy");
204 	if (IS_ERR(s_asd->dphy)) {
205 		if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER)
206 			dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n");
207 		return PTR_ERR(s_asd->dphy);
208 	}
209 
210 	phy_init(s_asd->dphy);
211 
212 	return 0;
213 }
214 
215 static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier,
216 					  struct v4l2_subdev *sd,
217 					  struct v4l2_async_subdev *asd)
218 {
219 	struct rkisp1_sensor_async *s_asd =
220 		container_of(asd, struct rkisp1_sensor_async, asd);
221 
222 	phy_exit(s_asd->dphy);
223 }
224 
225 static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
226 {
227 	struct rkisp1_device *rkisp1 =
228 		container_of(notifier, struct rkisp1_device, notifier);
229 	int ret;
230 
231 	ret = rkisp1_create_links(rkisp1);
232 	if (ret)
233 		return ret;
234 
235 	ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
236 	if (ret)
237 		return ret;
238 
239 	dev_dbg(rkisp1->dev, "Async subdev notifier completed\n");
240 
241 	return 0;
242 }
243 
244 static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = {
245 	.bound = rkisp1_subdev_notifier_bound,
246 	.unbind = rkisp1_subdev_notifier_unbind,
247 	.complete = rkisp1_subdev_notifier_complete,
248 };
249 
250 static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1)
251 {
252 	struct v4l2_async_notifier *ntf = &rkisp1->notifier;
253 	unsigned int next_id = 0;
254 	int ret;
255 
256 	v4l2_async_nf_init(ntf);
257 
258 	while (1) {
259 		struct v4l2_fwnode_endpoint vep = {
260 			.bus_type = V4L2_MBUS_CSI2_DPHY
261 		};
262 		struct rkisp1_sensor_async *rk_asd;
263 		struct fwnode_handle *ep;
264 
265 		ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev),
266 						     0, next_id,
267 						     FWNODE_GRAPH_ENDPOINT_NEXT);
268 		if (!ep)
269 			break;
270 
271 		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
272 		if (ret)
273 			goto err_parse;
274 
275 		rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep,
276 							 struct
277 							 rkisp1_sensor_async);
278 		if (IS_ERR(rk_asd)) {
279 			ret = PTR_ERR(rk_asd);
280 			goto err_parse;
281 		}
282 
283 		rk_asd->mbus_type = vep.bus_type;
284 		rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
285 		rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
286 
287 		dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n",
288 			vep.base.id, rk_asd->lanes);
289 
290 		next_id = vep.base.id + 1;
291 
292 		fwnode_handle_put(ep);
293 
294 		continue;
295 err_parse:
296 		fwnode_handle_put(ep);
297 		v4l2_async_nf_cleanup(ntf);
298 		return ret;
299 	}
300 
301 	if (next_id == 0)
302 		dev_dbg(rkisp1->dev, "no remote subdevice found\n");
303 	ntf->ops = &rkisp1_subdev_notifier_ops;
304 	ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf);
305 	if (ret) {
306 		v4l2_async_nf_cleanup(ntf);
307 		return ret;
308 	}
309 	return 0;
310 }
311 
312 /* ----------------------------------------------------------------------------
313  * Power
314  */
315 
316 static int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
317 {
318 	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
319 
320 	clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks);
321 	return pinctrl_pm_select_sleep_state(dev);
322 }
323 
324 static int __maybe_unused rkisp1_runtime_resume(struct device *dev)
325 {
326 	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
327 	int ret;
328 
329 	ret = pinctrl_pm_select_default_state(dev);
330 	if (ret)
331 		return ret;
332 	ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks);
333 	if (ret)
334 		return ret;
335 
336 	return 0;
337 }
338 
339 static const struct dev_pm_ops rkisp1_pm_ops = {
340 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
341 				pm_runtime_force_resume)
342 	SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL)
343 };
344 
345 /* ----------------------------------------------------------------------------
346  * Core
347  */
348 
349 static int rkisp1_entities_register(struct rkisp1_device *rkisp1)
350 {
351 	int ret;
352 
353 	ret = rkisp1_isp_register(rkisp1);
354 	if (ret)
355 		return ret;
356 
357 	ret = rkisp1_resizer_devs_register(rkisp1);
358 	if (ret)
359 		goto err_unreg_isp_subdev;
360 
361 	ret = rkisp1_capture_devs_register(rkisp1);
362 	if (ret)
363 		goto err_unreg_resizer_devs;
364 
365 	ret = rkisp1_stats_register(rkisp1);
366 	if (ret)
367 		goto err_unreg_capture_devs;
368 
369 	ret = rkisp1_params_register(rkisp1);
370 	if (ret)
371 		goto err_unreg_stats;
372 
373 	ret = rkisp1_subdev_notifier(rkisp1);
374 	if (ret) {
375 		dev_err(rkisp1->dev,
376 			"Failed to register subdev notifier(%d)\n", ret);
377 		goto err_unreg_params;
378 	}
379 
380 	return 0;
381 err_unreg_params:
382 	rkisp1_params_unregister(rkisp1);
383 err_unreg_stats:
384 	rkisp1_stats_unregister(rkisp1);
385 err_unreg_capture_devs:
386 	rkisp1_capture_devs_unregister(rkisp1);
387 err_unreg_resizer_devs:
388 	rkisp1_resizer_devs_unregister(rkisp1);
389 err_unreg_isp_subdev:
390 	rkisp1_isp_unregister(rkisp1);
391 	return ret;
392 }
393 
394 static irqreturn_t rkisp1_isr(int irq, void *ctx)
395 {
396 	/*
397 	 * Call rkisp1_capture_isr() first to handle the frame that
398 	 * potentially completed using the current frame_sequence number before
399 	 * it is potentially incremented by rkisp1_isp_isr() in the vertical
400 	 * sync.
401 	 */
402 	rkisp1_capture_isr(irq, ctx);
403 	rkisp1_isp_isr(irq, ctx);
404 	rkisp1_mipi_isr(irq, ctx);
405 
406 	return IRQ_HANDLED;
407 }
408 
409 static const char * const px30_isp_clks[] = {
410 	"isp",
411 	"aclk",
412 	"hclk",
413 	"pclk",
414 };
415 
416 static const struct rkisp1_isr_data px30_isp_isrs[] = {
417 	{ "isp", rkisp1_isp_isr },
418 	{ "mi", rkisp1_capture_isr },
419 	{ "mipi", rkisp1_mipi_isr },
420 };
421 
422 static const struct rkisp1_match_data px30_isp_match_data = {
423 	.clks = px30_isp_clks,
424 	.clk_size = ARRAY_SIZE(px30_isp_clks),
425 	.isrs = px30_isp_isrs,
426 	.isr_size = ARRAY_SIZE(px30_isp_isrs),
427 	.isp_ver = RKISP1_V12,
428 };
429 
430 static const char * const rk3399_isp_clks[] = {
431 	"isp",
432 	"aclk",
433 	"hclk",
434 };
435 
436 static const struct rkisp1_isr_data rk3399_isp_isrs[] = {
437 	{ NULL, rkisp1_isr },
438 };
439 
440 static const struct rkisp1_match_data rk3399_isp_match_data = {
441 	.clks = rk3399_isp_clks,
442 	.clk_size = ARRAY_SIZE(rk3399_isp_clks),
443 	.isrs = rk3399_isp_isrs,
444 	.isr_size = ARRAY_SIZE(rk3399_isp_isrs),
445 	.isp_ver = RKISP1_V10,
446 };
447 
448 static const struct of_device_id rkisp1_of_match[] = {
449 	{
450 		.compatible = "rockchip,px30-cif-isp",
451 		.data = &px30_isp_match_data,
452 	},
453 	{
454 		.compatible = "rockchip,rk3399-cif-isp",
455 		.data = &rk3399_isp_match_data,
456 	},
457 	{},
458 };
459 MODULE_DEVICE_TABLE(of, rkisp1_of_match);
460 
461 static void rkisp1_debug_init(struct rkisp1_device *rkisp1)
462 {
463 	struct rkisp1_debug *debug = &rkisp1->debug;
464 
465 	debug->debugfs_dir = debugfs_create_dir(RKISP1_DRIVER_NAME, NULL);
466 	debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir,
467 			     &debug->data_loss);
468 	debugfs_create_ulong("outform_size_err", 0444,  debug->debugfs_dir,
469 			     &debug->outform_size_error);
470 	debugfs_create_ulong("img_stabilization_size_error", 0444,
471 			     debug->debugfs_dir,
472 			     &debug->img_stabilization_size_error);
473 	debugfs_create_ulong("inform_size_error", 0444,  debug->debugfs_dir,
474 			     &debug->inform_size_error);
475 	debugfs_create_ulong("irq_delay", 0444,  debug->debugfs_dir,
476 			     &debug->irq_delay);
477 	debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir,
478 			     &debug->mipi_error);
479 	debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir,
480 			     &debug->stats_error);
481 	debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir,
482 			     &debug->stop_timeout[RKISP1_MAINPATH]);
483 	debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir,
484 			     &debug->stop_timeout[RKISP1_SELFPATH]);
485 	debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir,
486 			     &debug->frame_drop[RKISP1_MAINPATH]);
487 	debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir,
488 			     &debug->frame_drop[RKISP1_SELFPATH]);
489 }
490 
491 static int rkisp1_probe(struct platform_device *pdev)
492 {
493 	const struct rkisp1_match_data *match_data;
494 	struct device *dev = &pdev->dev;
495 	struct rkisp1_device *rkisp1;
496 	struct v4l2_device *v4l2_dev;
497 	unsigned int i;
498 	int ret, irq;
499 
500 	match_data = of_device_get_match_data(&pdev->dev);
501 	if (!match_data)
502 		return -ENODEV;
503 
504 	rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL);
505 	if (!rkisp1)
506 		return -ENOMEM;
507 
508 	dev_set_drvdata(dev, rkisp1);
509 	rkisp1->dev = dev;
510 
511 	mutex_init(&rkisp1->stream_lock);
512 
513 	rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0);
514 	if (IS_ERR(rkisp1->base_addr))
515 		return PTR_ERR(rkisp1->base_addr);
516 
517 	for (i = 0; i < match_data->isr_size; i++) {
518 		irq = (match_data->isrs[i].name) ?
519 				platform_get_irq_byname(pdev, match_data->isrs[i].name) :
520 				platform_get_irq(pdev, i);
521 		if (irq < 0)
522 			return irq;
523 
524 		ret = devm_request_irq(dev, irq, match_data->isrs[i].isr, IRQF_SHARED,
525 				       dev_driver_string(dev), dev);
526 		if (ret) {
527 			dev_err(dev, "request irq failed: %d\n", ret);
528 			return ret;
529 		}
530 	}
531 
532 	for (i = 0; i < match_data->clk_size; i++)
533 		rkisp1->clks[i].id = match_data->clks[i];
534 	ret = devm_clk_bulk_get(dev, match_data->clk_size, rkisp1->clks);
535 	if (ret)
536 		return ret;
537 	rkisp1->clk_size = match_data->clk_size;
538 
539 	pm_runtime_enable(&pdev->dev);
540 
541 	rkisp1->media_dev.hw_revision = match_data->isp_ver;
542 	strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME,
543 		sizeof(rkisp1->media_dev.model));
544 	rkisp1->media_dev.dev = &pdev->dev;
545 	strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO,
546 		sizeof(rkisp1->media_dev.bus_info));
547 	media_device_init(&rkisp1->media_dev);
548 
549 	v4l2_dev = &rkisp1->v4l2_dev;
550 	v4l2_dev->mdev = &rkisp1->media_dev;
551 	strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name));
552 
553 	ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev);
554 	if (ret)
555 		return ret;
556 
557 	ret = media_device_register(&rkisp1->media_dev);
558 	if (ret) {
559 		dev_err(dev, "Failed to register media device: %d\n", ret);
560 		goto err_unreg_v4l2_dev;
561 	}
562 
563 	ret = rkisp1_entities_register(rkisp1);
564 	if (ret)
565 		goto err_unreg_media_dev;
566 
567 	rkisp1_debug_init(rkisp1);
568 
569 	return 0;
570 
571 err_unreg_media_dev:
572 	media_device_unregister(&rkisp1->media_dev);
573 err_unreg_v4l2_dev:
574 	v4l2_device_unregister(&rkisp1->v4l2_dev);
575 	pm_runtime_disable(&pdev->dev);
576 	return ret;
577 }
578 
579 static int rkisp1_remove(struct platform_device *pdev)
580 {
581 	struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev);
582 
583 	v4l2_async_nf_unregister(&rkisp1->notifier);
584 	v4l2_async_nf_cleanup(&rkisp1->notifier);
585 
586 	rkisp1_params_unregister(rkisp1);
587 	rkisp1_stats_unregister(rkisp1);
588 	rkisp1_capture_devs_unregister(rkisp1);
589 	rkisp1_resizer_devs_unregister(rkisp1);
590 	rkisp1_isp_unregister(rkisp1);
591 
592 	media_device_unregister(&rkisp1->media_dev);
593 	v4l2_device_unregister(&rkisp1->v4l2_dev);
594 
595 	pm_runtime_disable(&pdev->dev);
596 
597 	debugfs_remove_recursive(rkisp1->debug.debugfs_dir);
598 	return 0;
599 }
600 
601 static struct platform_driver rkisp1_drv = {
602 	.driver = {
603 		.name = RKISP1_DRIVER_NAME,
604 		.of_match_table = of_match_ptr(rkisp1_of_match),
605 		.pm = &rkisp1_pm_ops,
606 	},
607 	.probe = rkisp1_probe,
608 	.remove = rkisp1_remove,
609 };
610 
611 module_platform_driver(rkisp1_drv);
612 MODULE_DESCRIPTION("Rockchip ISP1 platform driver");
613 MODULE_LICENSE("Dual MIT/GPL");
614