diff options
author | Animesh Kishore <ankishore@nvidia.com> | 2013-05-27 08:37:04 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:04:30 -0400 |
commit | a81db00305a18088d827fa2ce7a76ba0e88d6f40 (patch) | |
tree | d80053728d1e36a4ac9e1985c2a5807d51a429b3 /drivers/video/tegra/dc/dsi.c | |
parent | 454e9969f5036f5ea3e58d6a2b0ad2025026750f (diff) |
video: tegra: dsi: Add panel dt support
Incorporate all support required for default pluto panel.
Bug 1172236
Change-Id: Iebd3ba490a1d10a97a09ca5e0631241b6f9069bc
Signed-off-by: Animesh Kishore <ankishore@nvidia.com>
Reviewed-on: http://git-master/r/232781
Reviewed-by: Mrutyunjay Sawant <msawant@nvidia.com>
Tested-by: Mrutyunjay Sawant <msawant@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/dsi.c')
-rw-r--r-- | drivers/video/tegra/dc/dsi.c | 243 |
1 files changed, 203 insertions, 40 deletions
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c index 4dd3101eb..9045861bc 100644 --- a/drivers/video/tegra/dc/dsi.c +++ b/drivers/video/tegra/dc/dsi.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/nvhost.h> | 31 | #include <linux/nvhost.h> |
32 | #include <linux/lcm.h> | 32 | #include <linux/lcm.h> |
33 | #include <linux/of_address.h> | ||
34 | #include <linux/of_gpio.h> | ||
33 | #include <linux/regulator/consumer.h> | 35 | #include <linux/regulator/consumer.h> |
34 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
35 | 37 | ||
@@ -3550,6 +3552,158 @@ static void __tegra_dc_dsi_init(struct tegra_dc *dc) | |||
3550 | tegra_dsi_init_sw(dc, dsi); | 3552 | tegra_dsi_init_sw(dc, dsi); |
3551 | } | 3553 | } |
3552 | 3554 | ||
3555 | struct tegra_dsi_cmd *tegra_dsi_parse_cmd_dt(struct tegra_dc_dsi_data *dsi, | ||
3556 | const struct device_node *node, | ||
3557 | struct property *prop, | ||
3558 | u32 n_cmd) | ||
3559 | { | ||
3560 | struct tegra_dsi_cmd *dsi_cmd, *temp; | ||
3561 | u32 *prop_val_ptr = prop->value; | ||
3562 | u32 cnt = 0, i = 0; | ||
3563 | u8 arg1, arg2; | ||
3564 | |||
3565 | if (!prop) | ||
3566 | return NULL; | ||
3567 | |||
3568 | dsi_cmd = kzalloc(sizeof(*dsi_cmd) * n_cmd, GFP_KERNEL); | ||
3569 | if (!dsi_cmd) { | ||
3570 | dev_err(&dsi->dc->ndev->dev, | ||
3571 | "dsi: cmd memory allocation failed\n"); | ||
3572 | return ERR_PTR(-ENOMEM); | ||
3573 | } | ||
3574 | temp = dsi_cmd; | ||
3575 | |||
3576 | for (cnt = 0; cnt < n_cmd; cnt++, temp++) { | ||
3577 | temp->cmd_type = be32_to_cpu(*prop_val_ptr++); | ||
3578 | if (temp->cmd_type == TEGRA_DSI_PACKET_CMD) { | ||
3579 | temp->data_id = be32_to_cpu(*prop_val_ptr++); | ||
3580 | arg1 = be32_to_cpu(*prop_val_ptr++); | ||
3581 | arg2 = be32_to_cpu(*prop_val_ptr++); | ||
3582 | prop_val_ptr++; /* skip ecc */ | ||
3583 | if (temp->data_id == DSI_GENERIC_LONG_WRITE || | ||
3584 | temp->data_id == DSI_DCS_LONG_WRITE || | ||
3585 | temp->data_id == DSI_NULL_PKT_NO_DATA || | ||
3586 | temp->data_id == DSI_BLANKING_PKT_NO_DATA) { | ||
3587 | /* long pkt */ | ||
3588 | temp->sp_len_dly.data_len = | ||
3589 | (arg2 << NUMOF_BIT_PER_BYTE) | arg1; | ||
3590 | temp->pdata = kzalloc( | ||
3591 | temp->sp_len_dly.data_len, GFP_KERNEL); | ||
3592 | for (i = 0; i < temp->sp_len_dly.data_len; i++) | ||
3593 | (temp->pdata)[i] = | ||
3594 | be32_to_cpu(*prop_val_ptr++); | ||
3595 | prop_val_ptr += 2; /* skip checksum */ | ||
3596 | } else { | ||
3597 | temp->sp_len_dly.sp.data0 = arg1; | ||
3598 | temp->sp_len_dly.sp.data1 = arg2; | ||
3599 | } | ||
3600 | } else if (temp->cmd_type == TEGRA_DSI_DELAY_MS) { | ||
3601 | temp->sp_len_dly.delay_ms = | ||
3602 | be32_to_cpu(*prop_val_ptr++); | ||
3603 | } | ||
3604 | } | ||
3605 | |||
3606 | return dsi_cmd; | ||
3607 | } | ||
3608 | |||
3609 | struct device_node *tegra_dsi_panel_detect(void) | ||
3610 | { | ||
3611 | /* TODO: currently only lg 720p panel has dt support */ | ||
3612 | return of_find_compatible_node(NULL, NULL, "lg,720p-5"); | ||
3613 | } | ||
3614 | |||
3615 | static int tegra_dc_dsi_cp_info_dt(struct tegra_dc_dsi_data *dsi) | ||
3616 | { | ||
3617 | struct device_node *panel_dt_node = tegra_dsi_panel_detect(); | ||
3618 | struct device_node *dsi_dt_node = | ||
3619 | of_find_compatible_node(NULL, NULL, "nvidia,tegra114-dsi"); | ||
3620 | struct tegra_dsi_out *dsi_pdata = &dsi->info; | ||
3621 | int err = 0; | ||
3622 | |||
3623 | if (!panel_dt_node || !dsi_dt_node) { | ||
3624 | dev_info(&dsi->dc->ndev->dev, | ||
3625 | "dsi dt support not available\n"); | ||
3626 | err = -ENOENT; | ||
3627 | goto fail; | ||
3628 | } | ||
3629 | |||
3630 | if (panel_dt_node && dsi_dt_node) { | ||
3631 | const char *panel_dt_status; | ||
3632 | const char *dsi_dt_status; | ||
3633 | of_property_read_string(panel_dt_node, | ||
3634 | "status", &panel_dt_status); | ||
3635 | of_property_read_string(dsi_dt_node, | ||
3636 | "status", &dsi_dt_status); | ||
3637 | if (strcmp(panel_dt_status, "okay") || | ||
3638 | strcmp(dsi_dt_status, "okay")) { | ||
3639 | dev_info(&dsi->dc->ndev->dev, | ||
3640 | "dsi dt support disabled\n"); | ||
3641 | err = -ENOENT; | ||
3642 | goto fail; | ||
3643 | } | ||
3644 | } | ||
3645 | |||
3646 | of_property_read_u32(panel_dt_node, "nvidia,n-data-lanes", | ||
3647 | (u32 *)&dsi_pdata->n_data_lanes); | ||
3648 | |||
3649 | of_property_read_u32(panel_dt_node, "nvidia,pixel-format", | ||
3650 | (u32 *)&dsi_pdata->pixel_format); | ||
3651 | |||
3652 | of_property_read_u32(panel_dt_node, "nvidia,refresh-rate", | ||
3653 | (u32 *)&dsi_pdata->refresh_rate); | ||
3654 | |||
3655 | of_property_read_u32(panel_dt_node, "nvidia,video-data-type", | ||
3656 | (u32 *)&dsi_pdata->video_data_type); | ||
3657 | |||
3658 | of_property_read_u32(panel_dt_node, "nvidia,video-clock-mode", | ||
3659 | (u32 *)&dsi_pdata->video_clock_mode); | ||
3660 | |||
3661 | of_property_read_u32(panel_dt_node, "nvidia,video-burst-mode", | ||
3662 | (u32 *)&dsi_pdata->video_burst_mode); | ||
3663 | |||
3664 | of_property_read_u32(panel_dt_node, "nvidia,virtual-channel", | ||
3665 | (u32 *)&dsi_pdata->virtual_channel); | ||
3666 | |||
3667 | of_property_read_u32(panel_dt_node, "nvidia,panel-reset", | ||
3668 | (u32 *)&dsi_pdata->panel_reset); | ||
3669 | |||
3670 | dsi_pdata->power_saving_suspend = of_property_read_bool(panel_dt_node, | ||
3671 | "nvidia,power-saving-suspend"); | ||
3672 | |||
3673 | of_property_read_u32(dsi_dt_node, "nvidia,controller-vs", | ||
3674 | (u32 *)&dsi_pdata->controller_vs); | ||
3675 | |||
3676 | dsi_pdata->dsi_panel_rst_gpio = of_get_named_gpio(dsi_dt_node, | ||
3677 | "nvidia,dsi-panel-rst-gpio", 0); | ||
3678 | |||
3679 | dsi_pdata->dsi_panel_bl_en_gpio = of_get_named_gpio(dsi_dt_node, | ||
3680 | "nvidia,dsi-panel-bl-en-gpio", 0); | ||
3681 | |||
3682 | dsi_pdata->dsi_panel_bl_pwm_gpio = of_get_named_gpio(dsi_dt_node, | ||
3683 | "nvidia,dsi-panel-bl-pwm-gpio", 0); | ||
3684 | |||
3685 | of_property_read_u32(panel_dt_node, "nvidia,n-init-cmd", | ||
3686 | (u32 *)&dsi_pdata->n_init_cmd); | ||
3687 | |||
3688 | dsi_pdata->dsi_init_cmd = tegra_dsi_parse_cmd_dt(dsi, panel_dt_node, | ||
3689 | of_find_property( | ||
3690 | panel_dt_node, "nvidia,dsi-init-cmd", NULL), | ||
3691 | dsi_pdata->n_init_cmd); | ||
3692 | if (IS_ERR_OR_NULL(dsi_pdata->dsi_init_cmd)) { | ||
3693 | dev_err(&dsi->dc->ndev->dev, | ||
3694 | "dsi: copy init cmd from dt failed\n"); | ||
3695 | err = PTR_ERR(dsi_pdata->dsi_init_cmd); | ||
3696 | goto fail; | ||
3697 | } | ||
3698 | |||
3699 | dsi->dc->pdata->default_out->dsi = &dsi->info; | ||
3700 | dsi->dc->out->dsi = &dsi->info; | ||
3701 | fail: | ||
3702 | of_node_put(dsi_dt_node); | ||
3703 | of_node_put(panel_dt_node); | ||
3704 | return err; | ||
3705 | } | ||
3706 | |||
3553 | static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd *src, | 3707 | static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd *src, |
3554 | struct tegra_dsi_cmd *dst, u16 n_cmd) | 3708 | struct tegra_dsi_cmd *dst, u16 n_cmd) |
3555 | { | 3709 | { |
@@ -3577,17 +3731,14 @@ free_cmd_pdata: | |||
3577 | return -ENOMEM; | 3731 | return -ENOMEM; |
3578 | } | 3732 | } |
3579 | 3733 | ||
3580 | static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi, | 3734 | static int tegra_dc_dsi_cp_info_board(struct tegra_dc_dsi_data *dsi, |
3581 | struct tegra_dsi_out *p_dsi) | 3735 | struct tegra_dsi_out *p_dsi) |
3582 | { | 3736 | { |
3583 | struct tegra_dsi_cmd *p_init_cmd; | 3737 | struct tegra_dsi_cmd *p_init_cmd; |
3584 | struct tegra_dsi_cmd *p_early_suspend_cmd = NULL; | 3738 | struct tegra_dsi_cmd *p_early_suspend_cmd = NULL; |
3585 | struct tegra_dsi_cmd *p_late_resume_cmd = NULL; | 3739 | struct tegra_dsi_cmd *p_late_resume_cmd = NULL; |
3586 | struct tegra_dsi_cmd *p_suspend_cmd; | 3740 | struct tegra_dsi_cmd *p_suspend_cmd; |
3587 | int err; | 3741 | int err = 0; |
3588 | |||
3589 | if (p_dsi->n_data_lanes > MAX_DSI_DATA_LANES) | ||
3590 | return -EINVAL; | ||
3591 | 3742 | ||
3592 | p_init_cmd = kzalloc(sizeof(*p_init_cmd) * | 3743 | p_init_cmd = kzalloc(sizeof(*p_init_cmd) * |
3593 | p_dsi->n_init_cmd, GFP_KERNEL); | 3744 | p_dsi->n_init_cmd, GFP_KERNEL); |
@@ -3657,10 +3808,48 @@ static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi, | |||
3657 | goto err_free; | 3808 | goto err_free; |
3658 | dsi->info.dsi_suspend_cmd = p_suspend_cmd; | 3809 | dsi->info.dsi_suspend_cmd = p_suspend_cmd; |
3659 | 3810 | ||
3811 | return 0; | ||
3812 | err_free: | ||
3813 | kfree(p_suspend_cmd); | ||
3814 | err_free_p_late_resume_cmd: | ||
3815 | kfree(p_late_resume_cmd); | ||
3816 | err_free_p_early_suspend_cmd: | ||
3817 | kfree(p_early_suspend_cmd); | ||
3818 | err_free_init_cmd: | ||
3819 | kfree(p_init_cmd); | ||
3820 | return err; | ||
3821 | } | ||
3822 | |||
3823 | static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi) | ||
3824 | { | ||
3825 | int err; | ||
3826 | |||
3827 | err = tegra_dc_dsi_cp_info_dt(dsi); | ||
3828 | if (err < 0) { | ||
3829 | /* resort to platform files */ | ||
3830 | struct tegra_dsi_out *p_dsi; | ||
3831 | dev_warn(&dsi->dc->ndev->dev, | ||
3832 | "dsi: copy from dt failed, trying platform file\n"); | ||
3833 | p_dsi = dsi->dc->pdata->default_out->dsi; | ||
3834 | if (!p_dsi) { | ||
3835 | dev_err(&dsi->dc->ndev->dev, | ||
3836 | "dsi: platform dsi data not available\n"); | ||
3837 | return -EINVAL; | ||
3838 | } | ||
3839 | err = tegra_dc_dsi_cp_info_board(dsi, p_dsi); | ||
3840 | if (err < 0) { | ||
3841 | dev_err(&dsi->dc->ndev->dev, | ||
3842 | "dsi: copy from platform files failed\n"); | ||
3843 | return err; | ||
3844 | } | ||
3845 | } | ||
3846 | |||
3847 | if (dsi->info.n_data_lanes > MAX_DSI_DATA_LANES) | ||
3848 | return -EINVAL; | ||
3849 | |||
3660 | if (!dsi->info.panel_reset_timeout_msec) | 3850 | if (!dsi->info.panel_reset_timeout_msec) |
3661 | dsi->info.panel_reset_timeout_msec = | 3851 | dsi->info.panel_reset_timeout_msec = |
3662 | DEFAULT_PANEL_RESET_TIMEOUT; | 3852 | DEFAULT_PANEL_RESET_TIMEOUT; |
3663 | |||
3664 | if (!dsi->info.panel_buffer_size_byte) | 3853 | if (!dsi->info.panel_buffer_size_byte) |
3665 | dsi->info.panel_buffer_size_byte = DEFAULT_PANEL_BUFFER_BYTE; | 3854 | dsi->info.panel_buffer_size_byte = DEFAULT_PANEL_BUFFER_BYTE; |
3666 | 3855 | ||
@@ -3690,16 +3879,6 @@ static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi, | |||
3690 | /* host mode is for testing only */ | 3879 | /* host mode is for testing only */ |
3691 | dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC; | 3880 | dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC; |
3692 | return 0; | 3881 | return 0; |
3693 | |||
3694 | err_free: | ||
3695 | kfree(p_suspend_cmd); | ||
3696 | err_free_p_late_resume_cmd: | ||
3697 | kfree(p_late_resume_cmd); | ||
3698 | err_free_p_early_suspend_cmd: | ||
3699 | kfree(p_early_suspend_cmd); | ||
3700 | err_free_init_cmd: | ||
3701 | kfree(p_init_cmd); | ||
3702 | return err; | ||
3703 | } | 3882 | } |
3704 | 3883 | ||
3705 | /* returns next null enumeration from tegra_dsi_instance */ | 3884 | /* returns next null enumeration from tegra_dsi_instance */ |
@@ -3723,25 +3902,21 @@ static int _tegra_dc_dsi_init(struct tegra_dc *dc) | |||
3723 | struct clk *dsi_clk = NULL; | 3902 | struct clk *dsi_clk = NULL; |
3724 | struct clk *dsi_fixed_clk = NULL; | 3903 | struct clk *dsi_fixed_clk = NULL; |
3725 | struct clk *dsi_lp_clk = NULL; | 3904 | struct clk *dsi_lp_clk = NULL; |
3726 | struct tegra_dsi_out *dsi_pdata; | ||
3727 | int err = 0; | 3905 | int err = 0; |
3728 | int dsi_enum = -1; | 3906 | int dsi_enum = -1; |
3729 | 3907 | ||
3730 | if (dc->pdata->default_out->dsi->dsi_instance) | ||
3731 | dsi_enum = 1; | ||
3732 | else | ||
3733 | dsi_enum = tegra_dsi_get_enumeration(); | ||
3734 | if (dsi_enum < 0) { | ||
3735 | err = -EINVAL; | ||
3736 | dev_err(&dc->ndev->dev, "dsi: invalid enum retured\n"); | ||
3737 | return err; | ||
3738 | } | ||
3739 | |||
3740 | dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); | 3908 | dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); |
3741 | if (!dsi) { | 3909 | if (!dsi) { |
3742 | dev_err(&dc->ndev->dev, "dsi: memory allocation failed\n"); | 3910 | dev_err(&dc->ndev->dev, "dsi: memory allocation failed\n"); |
3743 | return -ENOMEM; | 3911 | return -ENOMEM; |
3744 | } | 3912 | } |
3913 | |||
3914 | dsi->dc = dc; | ||
3915 | err = tegra_dc_dsi_cp_info(dsi); | ||
3916 | if (err < 0) | ||
3917 | goto err_free_dsi; | ||
3918 | |||
3919 | dsi_enum = dsi->info.dsi_instance ? : tegra_dsi_get_enumeration(); | ||
3745 | tegra_dsi_instance[dsi_enum] = dsi; | 3920 | tegra_dsi_instance[dsi_enum] = dsi; |
3746 | 3921 | ||
3747 | if (dc->out->dsi->ganged_type) { | 3922 | if (dc->out->dsi->ganged_type) { |
@@ -3780,11 +3955,6 @@ static int _tegra_dc_dsi_init(struct tegra_dc *dc) | |||
3780 | goto err_release_regs; | 3955 | goto err_release_regs; |
3781 | } | 3956 | } |
3782 | 3957 | ||
3783 | dsi_pdata = dc->pdata->default_out->dsi; | ||
3784 | if (!dsi_pdata) { | ||
3785 | dev_err(&dc->ndev->dev, "dsi: dsi data not available\n"); | ||
3786 | goto err_release_regs; | ||
3787 | } | ||
3788 | if (dsi_enum) { | 3958 | if (dsi_enum) { |
3789 | dsi_clk = clk_get(&dc->ndev->dev, "dsib"); | 3959 | dsi_clk = clk_get(&dc->ndev->dev, "dsib"); |
3790 | dsi_lp_clk = clk_get(&dc->ndev->dev, "dsiblp"); | 3960 | dsi_lp_clk = clk_get(&dc->ndev->dev, "dsiblp"); |
@@ -3811,7 +3981,6 @@ static int _tegra_dc_dsi_init(struct tegra_dc *dc) | |||
3811 | 3981 | ||
3812 | mutex_init(&dsi->lock); | 3982 | mutex_init(&dsi->lock); |
3813 | dsi->controller_index = dsi_enum; | 3983 | dsi->controller_index = dsi_enum; |
3814 | dsi->dc = dc; | ||
3815 | dsi->base = base; | 3984 | dsi->base = base; |
3816 | dsi->base_res = base_res; | 3985 | dsi->base_res = base_res; |
3817 | dsi->dc_clk = dc_clk; | 3986 | dsi->dc_clk = dc_clk; |
@@ -3819,17 +3988,11 @@ static int _tegra_dc_dsi_init(struct tegra_dc *dc) | |||
3819 | dsi->dsi_fixed_clk = dsi_fixed_clk; | 3988 | dsi->dsi_fixed_clk = dsi_fixed_clk; |
3820 | dsi->dsi_lp_clk = dsi_lp_clk; | 3989 | dsi->dsi_lp_clk = dsi_lp_clk; |
3821 | 3990 | ||
3822 | err = tegra_dc_dsi_cp_info(dsi, dsi_pdata); | ||
3823 | if (err < 0) | ||
3824 | goto err_dc_clk_put; | ||
3825 | |||
3826 | tegra_dc_set_outdata(dc, dsi); | 3991 | tegra_dc_set_outdata(dc, dsi); |
3827 | __tegra_dc_dsi_init(dc); | 3992 | __tegra_dc_dsi_init(dc); |
3828 | 3993 | ||
3829 | return 0; | 3994 | return 0; |
3830 | 3995 | ||
3831 | err_dc_clk_put: | ||
3832 | clk_put(dc_clk); | ||
3833 | err_dsi_clk_put: | 3996 | err_dsi_clk_put: |
3834 | clk_put(dsi_clk); | 3997 | clk_put(dsi_clk); |
3835 | clk_put(dsi_fixed_clk); | 3998 | clk_put(dsi_fixed_clk); |