video: rockchip: dp: do no support 4k when use vop1
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / dp / rockchip_dp.c
1 #include "rockchip_dp.h"
2 #include <linux/delay.h>
3
4 static int rockchip_dp_removed(struct hdmi *hdmi_drv)
5 {
6         struct dp_dev *dp_dev = hdmi_drv->property->priv;
7         int ret;
8
9         ret = cdn_dp_encoder_disable(dp_dev->dp);
10         if (ret)
11                 dev_warn(hdmi_drv->dev, "dp has been removed twice:%d\n", ret);
12         return HDMI_ERROR_SUCCESS;
13 }
14
15 static int rockchip_dp_enable(struct hdmi *hdmi_drv)
16 {
17         return 0;
18 }
19
20 static int rockchip_dp_disable(struct hdmi *hdmi_drv)
21 {
22         return 0;
23 }
24
25 static int rockchip_dp_control_output(struct hdmi *hdmi_drv, int enable)
26 {
27         struct dp_dev *dp_dev = hdmi_drv->property->priv;
28         int ret;
29
30         if (enable == HDMI_AV_UNMUTE) {
31                 if (!dp_dev->early_suspended) {
32                         ret = cdn_dp_encoder_enable(dp_dev->dp);
33                         if (ret) {
34                                 dev_err(hdmi_drv->dev,
35                                         "dp enable video and audio output error:%d\n", ret);
36                                 return HDMI_ERROR_FALSE;
37                         }
38                 } else
39                         dev_warn(hdmi_drv->dev,
40                                 "don't output video and audio after dp has been suspended!\n");
41         } else if (enable & HDMI_VIDEO_MUTE)
42                 dev_dbg(hdmi_drv->dev, "dp disable video and audio output !\n");
43
44         return 0;
45 }
46
47 static int rockchip_dp_config_audio(struct hdmi *hdmi_drv,
48                                     struct hdmi_audio *audio)
49 {
50         return 0;
51 }
52
53 static int rockchip_dp_config_video(struct hdmi *hdmi_drv,
54                                     struct hdmi_video *vpara)
55 {
56         struct hdmi_video_timing *timing = NULL;
57         struct dp_dev *dp_dev = hdmi_drv->property->priv;
58         struct dp_disp_info *disp_info = &dp_dev->disp_info;
59         int ret;
60
61         if (dp_dev->early_suspended) {
62                 dev_warn(hdmi_drv->dev,
63                         "don't config video after dp has been suspended!\n");
64                 return 0;
65         }
66
67         timing = (struct hdmi_video_timing *)hdmi_vic2timing(vpara->vic);
68         if (!timing) {
69                 dev_err(hdmi_drv->dev,
70                         "[%s] not found vic %d\n", __func__, vpara->vic);
71                 return -ENOENT;
72         }
73         disp_info->mode = &timing->mode;
74
75         disp_info->color_depth = vpara->color_output_depth;
76         disp_info->vsync_polarity = 1;
77         disp_info->hsync_polarity = 1;
78
79         ret = cdn_dp_encoder_mode_set(dp_dev->dp, disp_info);
80         if (ret) {
81                 dev_err(hdmi_drv->dev, "dp config video mode error:%d\n", ret);
82                 return HDMI_ERROR_FALSE;
83         }
84
85         return 0;
86 }
87
88 static int rockchip_dp_detect_hotplug(struct hdmi *hdmi_drv)
89 {
90         struct dp_dev *dp_dev = hdmi_drv->property->priv;
91
92         if (cdn_dp_connector_detect(dp_dev->dp))
93                 return HDMI_HPD_ACTIVED;
94         return HDMI_HPD_REMOVED;
95 }
96
97 static int rockchip_dp_read_edid(struct hdmi *hdmi_drv, int block, u8 *buf)
98 {
99         int ret = 0;
100         struct dp_dev *dp_dev = hdmi_drv->property->priv;
101
102         if (dp_dev->lanes == 4)
103                 dp_dev->hdmi->property->feature |= SUPPORT_TMDS_600M;
104         else
105                 dp_dev->hdmi->property->feature &= ~SUPPORT_TMDS_600M;
106
107         ret = cdn_dp_get_edid(dp_dev->dp, buf, block);
108         if (ret)
109                 dev_err(hdmi_drv->dev, "dp config video mode error:%d\n", ret);
110
111         return ret;
112 }
113
114 static int rockchip_dp_insert(struct hdmi *hdmi_drv)
115 {
116         return 0;
117 }
118
119 static int rockchip_dp_config_vsi(struct hdmi *hdmi,
120                                   unsigned char vic_3d,
121                                   unsigned char format)
122 {
123         return 0;
124 }
125
126 static void rockchip_dp_dev_init_ops(struct hdmi_ops *ops)
127 {
128         if (ops) {
129                 ops->disable = rockchip_dp_disable;
130                 ops->enable = rockchip_dp_enable;
131                 ops->remove = rockchip_dp_removed;
132                 ops->setmute = rockchip_dp_control_output;
133                 ops->setvideo = rockchip_dp_config_video;
134                 ops->setaudio = rockchip_dp_config_audio;
135                 ops->getstatus = rockchip_dp_detect_hotplug;
136                 ops->getedid = rockchip_dp_read_edid;
137                 ops->insert     = rockchip_dp_insert;
138                 ops->setvsi = rockchip_dp_config_vsi;
139         }
140 }
141
142 void hpd_change(struct device *dev, int lanes)
143 {
144         struct dp_dev *dp_dev = dev_get_drvdata(dev);
145
146         if (lanes)
147                 dp_dev->lanes = lanes;
148
149         if (dp_dev->hdmi->enable) {
150                 if (dp_dev->early_suspended)
151                         dev_warn(dp_dev->hdmi->dev,
152                                 "hpd triggered after early suspend, so don't send hpd change event !\n");
153                 else
154                         hdmi_submit_work(dp_dev->hdmi, HDMI_HPD_CHANGE, 10, 0);
155         }
156 }
157
158 static void rockchip_dp_early_suspend(struct dp_dev *dp_dev)
159 {
160         hdmi_submit_work(dp_dev->hdmi, HDMI_SUSPEND_CTL, 0, 1);
161         cdn_dp_suspend(dp_dev->dp);
162 }
163
164 static void rockchip_dp_early_resume(struct dp_dev *dp_dev)
165 {
166         cdn_dp_resume(dp_dev->dp);
167         hdmi_submit_work(dp_dev->hdmi, HDMI_RESUME_CTL, 0, 0);
168 }
169
170 static int rockchip_dp_fb_event_notify(struct notifier_block *self,
171                                        unsigned long action,
172                                            void *data)
173 {
174         struct fb_event *event = data;
175         int blank_mode = *((int *)event->data);
176         struct dp_dev *dp_dev = container_of(self, struct dp_dev, fb_notif);
177
178         if (action == FB_EARLY_EVENT_BLANK) {
179                 switch (blank_mode) {
180                 case FB_BLANK_UNBLANK:
181                         break;
182                 default:
183                         if (!dp_dev->hdmi->sleep) {
184                                 rockchip_dp_early_suspend(dp_dev);
185                                 dp_dev->early_suspended = true;
186                         }
187                         break;
188                 }
189         } else if (action == FB_EVENT_BLANK) {
190                 switch (blank_mode) {
191                 case FB_BLANK_UNBLANK:
192                         if (dp_dev->hdmi->sleep) {
193                                 dp_dev->early_suspended = false;
194                                 rockchip_dp_early_resume(dp_dev);
195                         }
196                         break;
197                 default:
198                         break;
199                 }
200         }
201
202         return NOTIFY_OK;
203 }
204
205 int cdn_dp_fb_register(struct platform_device *pdev, void *dp)
206 {
207         struct hdmi_ops *rk_dp_ops;
208         struct hdmi_property *rk_cdn_dp_prop;
209         struct device *dev = &pdev->dev;
210         struct dp_dev *dp_dev;
211         struct device_node *np = dev->of_node;
212         int val = 0;
213
214         rk_dp_ops = devm_kzalloc(dev, sizeof(struct hdmi_ops), GFP_KERNEL);
215         if (!rk_dp_ops)
216                 return -ENOMEM;
217
218         rk_cdn_dp_prop = devm_kzalloc(dev, sizeof(struct hdmi_property),
219                                       GFP_KERNEL);
220         if (!rk_cdn_dp_prop)
221                 return -ENOMEM;
222
223         dp_dev = devm_kzalloc(dev, sizeof(struct dp_dev), GFP_KERNEL);
224         if (!dp_dev)
225                 return -ENOMEM;
226
227         if (!of_property_read_u32(np, "dp_vop_sel", &val))
228                 dp_dev->disp_info.vop_sel = val;
229
230         rockchip_dp_dev_init_ops(rk_dp_ops);
231         rk_cdn_dp_prop->videosrc = dp_dev->disp_info.vop_sel;
232         rk_cdn_dp_prop->display = DISPLAY_MAIN;
233         rk_cdn_dp_prop->defaultmode = HDMI_VIDEO_DEFAULT_MODE;
234         rk_cdn_dp_prop->name = (char *)pdev->name;
235         rk_cdn_dp_prop->priv = dp_dev;
236         rk_cdn_dp_prop->feature |=
237                                 SUPPORT_DEEP_10BIT |
238                                 SUPPORT_YCBCR_INPUT |
239                                 SUPPORT_1080I |
240                                 SUPPORT_480I_576I |
241                                 SUPPORT_RK_DISCRETE_VR;
242
243         if (!rk_cdn_dp_prop->videosrc) {
244                 rk_cdn_dp_prop->feature |=
245                                         SUPPORT_4K |
246                                         SUPPORT_4K_4096 |
247                                         SUPPORT_YUV420 |
248                                         SUPPORT_YCBCR_INPUT |
249                                         SUPPORT_TMDS_600M;
250         }
251
252         dp_dev->hdmi = rockchip_hdmi_register(rk_cdn_dp_prop,
253                                                 rk_dp_ops);
254         dp_dev->hdmi->dev = dev;
255         dp_dev->hdmi->enable = 1;
256         dp_dev->early_suspended = 0;
257         dp_dev->hdmi->sleep = 0;
258         dp_dev->hdmi->colormode = HDMI_COLOR_RGB_0_255;
259         dp_dev->dp = dp;
260
261         dp_dev->fb_notif.notifier_call = rockchip_dp_fb_event_notify;
262         fb_register_client(&dp_dev->fb_notif);
263         dev_set_drvdata(dev, dp_dev);
264
265         hdmi_submit_work(dp_dev->hdmi, HDMI_HPD_CHANGE, 20, 0);
266         return 0;
267 }