diff options
Diffstat (limited to 'drivers/video/omap2/dss/dsi.c')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 144 |
1 files changed, 142 insertions, 2 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 0d82f731d2f0..f3e4e468b49a 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/debugfs.h> | 39 | #include <linux/debugfs.h> |
40 | #include <linux/pm_runtime.h> | 40 | #include <linux/pm_runtime.h> |
41 | #include <linux/of.h> | ||
42 | #include <linux/of_platform.h> | ||
41 | 43 | ||
42 | #include <video/omapdss.h> | 44 | #include <video/omapdss.h> |
43 | #include <video/mipi_display.h> | 45 | #include <video/mipi_display.h> |
@@ -386,6 +388,13 @@ struct dsi_packet_sent_handler_data { | |||
386 | struct completion *completion; | 388 | struct completion *completion; |
387 | }; | 389 | }; |
388 | 390 | ||
391 | struct dsi_module_id_data { | ||
392 | u32 address; | ||
393 | int id; | ||
394 | }; | ||
395 | |||
396 | static const struct of_device_id dsi_of_match[]; | ||
397 | |||
389 | #ifdef DSI_PERF_MEASURE | 398 | #ifdef DSI_PERF_MEASURE |
390 | static bool dsi_perf; | 399 | static bool dsi_perf; |
391 | module_param(dsi_perf, bool, 0644); | 400 | module_param(dsi_perf, bool, 0644); |
@@ -1151,7 +1160,10 @@ static int dsi_regulator_init(struct platform_device *dsidev) | |||
1151 | if (dsi->vdds_dsi_reg != NULL) | 1160 | if (dsi->vdds_dsi_reg != NULL) |
1152 | return 0; | 1161 | return 0; |
1153 | 1162 | ||
1154 | vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi"); | 1163 | if (dsi->pdev->dev.of_node) |
1164 | vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd"); | ||
1165 | else | ||
1166 | vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi"); | ||
1155 | 1167 | ||
1156 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | 1168 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ |
1157 | if (IS_ERR(vdds_dsi)) | 1169 | if (IS_ERR(vdds_dsi)) |
@@ -5370,12 +5382,69 @@ static void dsi_uninit_output(struct platform_device *dsidev) | |||
5370 | omapdss_unregister_output(out); | 5382 | omapdss_unregister_output(out); |
5371 | } | 5383 | } |
5372 | 5384 | ||
5385 | static int dsi_probe_of(struct platform_device *pdev) | ||
5386 | { | ||
5387 | struct device_node *node = pdev->dev.of_node; | ||
5388 | struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); | ||
5389 | struct property *prop; | ||
5390 | u32 lane_arr[10]; | ||
5391 | int len, num_pins; | ||
5392 | int r, i; | ||
5393 | struct device_node *ep; | ||
5394 | struct omap_dsi_pin_config pin_cfg; | ||
5395 | |||
5396 | ep = omapdss_of_get_first_endpoint(node); | ||
5397 | if (!ep) | ||
5398 | return 0; | ||
5399 | |||
5400 | prop = of_find_property(ep, "lanes", &len); | ||
5401 | if (prop == NULL) { | ||
5402 | dev_err(&pdev->dev, "failed to find lane data\n"); | ||
5403 | r = -EINVAL; | ||
5404 | goto err; | ||
5405 | } | ||
5406 | |||
5407 | num_pins = len / sizeof(u32); | ||
5408 | |||
5409 | if (num_pins < 4 || num_pins % 2 != 0 || | ||
5410 | num_pins > dsi->num_lanes_supported * 2) { | ||
5411 | dev_err(&pdev->dev, "bad number of lanes\n"); | ||
5412 | r = -EINVAL; | ||
5413 | goto err; | ||
5414 | } | ||
5415 | |||
5416 | r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins); | ||
5417 | if (r) { | ||
5418 | dev_err(&pdev->dev, "failed to read lane data\n"); | ||
5419 | goto err; | ||
5420 | } | ||
5421 | |||
5422 | pin_cfg.num_pins = num_pins; | ||
5423 | for (i = 0; i < num_pins; ++i) | ||
5424 | pin_cfg.pins[i] = (int)lane_arr[i]; | ||
5425 | |||
5426 | r = dsi_configure_pins(&dsi->output, &pin_cfg); | ||
5427 | if (r) { | ||
5428 | dev_err(&pdev->dev, "failed to configure pins"); | ||
5429 | goto err; | ||
5430 | } | ||
5431 | |||
5432 | of_node_put(ep); | ||
5433 | |||
5434 | return 0; | ||
5435 | |||
5436 | err: | ||
5437 | of_node_put(ep); | ||
5438 | return r; | ||
5439 | } | ||
5440 | |||
5373 | /* DSI1 HW IP initialisation */ | 5441 | /* DSI1 HW IP initialisation */ |
5374 | static int omap_dsihw_probe(struct platform_device *dsidev) | 5442 | static int omap_dsihw_probe(struct platform_device *dsidev) |
5375 | { | 5443 | { |
5376 | u32 rev; | 5444 | u32 rev; |
5377 | int r, i; | 5445 | int r, i; |
5378 | struct dsi_data *dsi; | 5446 | struct dsi_data *dsi; |
5447 | struct resource *dsi_mem; | ||
5379 | struct resource *res; | 5448 | struct resource *res; |
5380 | struct resource temp_res; | 5449 | struct resource temp_res; |
5381 | 5450 | ||
@@ -5383,7 +5452,6 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
5383 | if (!dsi) | 5452 | if (!dsi) |
5384 | return -ENOMEM; | 5453 | return -ENOMEM; |
5385 | 5454 | ||
5386 | dsi->module_id = dsidev->id; | ||
5387 | dsi->pdev = dsidev; | 5455 | dsi->pdev = dsidev; |
5388 | dev_set_drvdata(&dsidev->dev, dsi); | 5456 | dev_set_drvdata(&dsidev->dev, dsi); |
5389 | 5457 | ||
@@ -5421,6 +5489,8 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
5421 | res = &temp_res; | 5489 | res = &temp_res; |
5422 | } | 5490 | } |
5423 | 5491 | ||
5492 | dsi_mem = res; | ||
5493 | |||
5424 | dsi->proto_base = devm_ioremap(&dsidev->dev, res->start, | 5494 | dsi->proto_base = devm_ioremap(&dsidev->dev, res->start, |
5425 | resource_size(res)); | 5495 | resource_size(res)); |
5426 | if (!dsi->proto_base) { | 5496 | if (!dsi->proto_base) { |
@@ -5481,6 +5551,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
5481 | return r; | 5551 | return r; |
5482 | } | 5552 | } |
5483 | 5553 | ||
5554 | if (dsidev->dev.of_node) { | ||
5555 | const struct of_device_id *match; | ||
5556 | const struct dsi_module_id_data *d; | ||
5557 | |||
5558 | match = of_match_node(dsi_of_match, dsidev->dev.of_node); | ||
5559 | if (!match) { | ||
5560 | DSSERR("unsupported DSI module\n"); | ||
5561 | return -ENODEV; | ||
5562 | } | ||
5563 | |||
5564 | d = match->data; | ||
5565 | |||
5566 | while (d->address != 0 && d->address != dsi_mem->start) | ||
5567 | d++; | ||
5568 | |||
5569 | if (d->address == 0) { | ||
5570 | DSSERR("unsupported DSI module\n"); | ||
5571 | return -ENODEV; | ||
5572 | } | ||
5573 | |||
5574 | dsi->module_id = d->id; | ||
5575 | } else { | ||
5576 | dsi->module_id = dsidev->id; | ||
5577 | } | ||
5578 | |||
5484 | /* DSI VCs initialization */ | 5579 | /* DSI VCs initialization */ |
5485 | for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { | 5580 | for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { |
5486 | dsi->vc[i].source = DSI_VC_SOURCE_L4; | 5581 | dsi->vc[i].source = DSI_VC_SOURCE_L4; |
@@ -5516,6 +5611,19 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
5516 | 5611 | ||
5517 | dsi_init_output(dsidev); | 5612 | dsi_init_output(dsidev); |
5518 | 5613 | ||
5614 | if (dsidev->dev.of_node) { | ||
5615 | r = dsi_probe_of(dsidev); | ||
5616 | if (r) { | ||
5617 | DSSERR("Invalid DSI DT data\n"); | ||
5618 | goto err_probe_of; | ||
5619 | } | ||
5620 | |||
5621 | r = of_platform_populate(dsidev->dev.of_node, NULL, NULL, | ||
5622 | &dsidev->dev); | ||
5623 | if (r) | ||
5624 | DSSERR("Failed to populate DSI child devices: %d\n", r); | ||
5625 | } | ||
5626 | |||
5519 | dsi_runtime_put(dsidev); | 5627 | dsi_runtime_put(dsidev); |
5520 | 5628 | ||
5521 | if (dsi->module_id == 0) | 5629 | if (dsi->module_id == 0) |
@@ -5529,17 +5637,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
5529 | else if (dsi->module_id == 1) | 5637 | else if (dsi->module_id == 1) |
5530 | dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); | 5638 | dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); |
5531 | #endif | 5639 | #endif |
5640 | |||
5532 | return 0; | 5641 | return 0; |
5533 | 5642 | ||
5643 | err_probe_of: | ||
5644 | dsi_uninit_output(dsidev); | ||
5645 | dsi_runtime_put(dsidev); | ||
5646 | |||
5534 | err_runtime_get: | 5647 | err_runtime_get: |
5535 | pm_runtime_disable(&dsidev->dev); | 5648 | pm_runtime_disable(&dsidev->dev); |
5536 | return r; | 5649 | return r; |
5537 | } | 5650 | } |
5538 | 5651 | ||
5652 | static int dsi_unregister_child(struct device *dev, void *data) | ||
5653 | { | ||
5654 | struct platform_device *pdev = to_platform_device(dev); | ||
5655 | platform_device_unregister(pdev); | ||
5656 | return 0; | ||
5657 | } | ||
5658 | |||
5539 | static int __exit omap_dsihw_remove(struct platform_device *dsidev) | 5659 | static int __exit omap_dsihw_remove(struct platform_device *dsidev) |
5540 | { | 5660 | { |
5541 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 5661 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
5542 | 5662 | ||
5663 | device_for_each_child(&dsidev->dev, NULL, dsi_unregister_child); | ||
5664 | |||
5543 | WARN_ON(dsi->scp_clk_refcount > 0); | 5665 | WARN_ON(dsi->scp_clk_refcount > 0); |
5544 | 5666 | ||
5545 | dsi_uninit_output(dsidev); | 5667 | dsi_uninit_output(dsidev); |
@@ -5577,6 +5699,23 @@ static const struct dev_pm_ops dsi_pm_ops = { | |||
5577 | .runtime_resume = dsi_runtime_resume, | 5699 | .runtime_resume = dsi_runtime_resume, |
5578 | }; | 5700 | }; |
5579 | 5701 | ||
5702 | static const struct dsi_module_id_data dsi_of_data_omap3[] = { | ||
5703 | { .address = 0x4804fc00, .id = 0, }, | ||
5704 | { }, | ||
5705 | }; | ||
5706 | |||
5707 | static const struct dsi_module_id_data dsi_of_data_omap4[] = { | ||
5708 | { .address = 0x58004000, .id = 0, }, | ||
5709 | { .address = 0x58005000, .id = 1, }, | ||
5710 | { }, | ||
5711 | }; | ||
5712 | |||
5713 | static const struct of_device_id dsi_of_match[] = { | ||
5714 | { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, }, | ||
5715 | { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, }, | ||
5716 | {}, | ||
5717 | }; | ||
5718 | |||
5580 | static struct platform_driver omap_dsihw_driver = { | 5719 | static struct platform_driver omap_dsihw_driver = { |
5581 | .probe = omap_dsihw_probe, | 5720 | .probe = omap_dsihw_probe, |
5582 | .remove = __exit_p(omap_dsihw_remove), | 5721 | .remove = __exit_p(omap_dsihw_remove), |
@@ -5584,6 +5723,7 @@ static struct platform_driver omap_dsihw_driver = { | |||
5584 | .name = "omapdss_dsi", | 5723 | .name = "omapdss_dsi", |
5585 | .owner = THIS_MODULE, | 5724 | .owner = THIS_MODULE, |
5586 | .pm = &dsi_pm_ops, | 5725 | .pm = &dsi_pm_ops, |
5726 | .of_match_table = dsi_of_match, | ||
5587 | }, | 5727 | }, |
5588 | }; | 5728 | }; |
5589 | 5729 | ||