1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2021 Fuzhou Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun * Author: Algea Cao <algea.cao@rock-chips.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <malloc.h>
9*4882a593Smuzhiyun #include <syscon.h>
10*4882a593Smuzhiyun #include <asm/arch-rockchip/clock.h>
11*4882a593Smuzhiyun #include <asm/arch/vendor.h>
12*4882a593Smuzhiyun #include <edid.h>
13*4882a593Smuzhiyun #include <dm/device.h>
14*4882a593Smuzhiyun #include <dm/of_access.h>
15*4882a593Smuzhiyun #include <dm/ofnode.h>
16*4882a593Smuzhiyun #include <dm/read.h>
17*4882a593Smuzhiyun #include <linux/hdmi.h>
18*4882a593Smuzhiyun #include <linux/media-bus-format.h>
19*4882a593Smuzhiyun #include <linux/dw_hdmi.h>
20*4882a593Smuzhiyun #include <asm/io.h>
21*4882a593Smuzhiyun #include "rockchip_display.h"
22*4882a593Smuzhiyun #include "rockchip_crtc.h"
23*4882a593Smuzhiyun #include "rockchip_connector.h"
24*4882a593Smuzhiyun #include "dw_hdmi_qp.h"
25*4882a593Smuzhiyun #include "rockchip_phy.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun enum frl_mask {
28*4882a593Smuzhiyun FRL_3GBPS_3LANE = 1,
29*4882a593Smuzhiyun FRL_6GBPS_3LANE,
30*4882a593Smuzhiyun FRL_6GBPS_4LANE,
31*4882a593Smuzhiyun FRL_8GBPS_4LANE,
32*4882a593Smuzhiyun FRL_10GBPS_4LANE,
33*4882a593Smuzhiyun FRL_12GBPS_4LANE,
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define DDC_CI_ADDR 0x37
37*4882a593Smuzhiyun #define DDC_SEGMENT_ADDR 0x30
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define HDMI_EDID_LEN 512
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */
42*4882a593Smuzhiyun #define SCDC_MIN_SOURCE_VERSION 0x1
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define HDMI14_MAX_TMDSCLK 340000000
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun struct hdmi_vmode {
47*4882a593Smuzhiyun bool mdataenablepolarity;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun unsigned int mpixelclock;
50*4882a593Smuzhiyun unsigned int mpixelrepetitioninput;
51*4882a593Smuzhiyun unsigned int mpixelrepetitionoutput;
52*4882a593Smuzhiyun unsigned int mtmdsclock;
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct hdmi_data_info {
56*4882a593Smuzhiyun unsigned int enc_in_bus_format;
57*4882a593Smuzhiyun unsigned int enc_out_bus_format;
58*4882a593Smuzhiyun unsigned int enc_in_encoding;
59*4882a593Smuzhiyun unsigned int enc_out_encoding;
60*4882a593Smuzhiyun unsigned int quant_range;
61*4882a593Smuzhiyun unsigned int pix_repet_factor;
62*4882a593Smuzhiyun struct hdmi_vmode video_mode;
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun struct dw_hdmi_phy_data {
66*4882a593Smuzhiyun enum dw_hdmi_phy_type type;
67*4882a593Smuzhiyun const char *name;
68*4882a593Smuzhiyun unsigned int gen;
69*4882a593Smuzhiyun bool has_svsret;
70*4882a593Smuzhiyun int (*configure)(struct dw_hdmi *hdmi,
71*4882a593Smuzhiyun const struct dw_hdmi_plat_data *pdata,
72*4882a593Smuzhiyun unsigned long mpixelclock);
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun struct dw_hdmi_i2c {
76*4882a593Smuzhiyun u8 slave_reg;
77*4882a593Smuzhiyun bool is_regaddr;
78*4882a593Smuzhiyun bool is_segment;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun unsigned int scl_high_ns;
81*4882a593Smuzhiyun unsigned int scl_low_ns;
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun struct dw_hdmi_qp {
85*4882a593Smuzhiyun enum dw_hdmi_devtype dev_type;
86*4882a593Smuzhiyun unsigned int version;
87*4882a593Smuzhiyun struct hdmi_data_info hdmi_data;
88*4882a593Smuzhiyun struct hdmi_edid_data edid_data;
89*4882a593Smuzhiyun const struct dw_hdmi_plat_data *plat_data;
90*4882a593Smuzhiyun struct ddc_adapter adap;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun int vic;
93*4882a593Smuzhiyun int id;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun unsigned long bus_format;
96*4882a593Smuzhiyun bool cable_plugin;
97*4882a593Smuzhiyun bool sink_is_hdmi;
98*4882a593Smuzhiyun bool sink_has_audio;
99*4882a593Smuzhiyun void *regs;
100*4882a593Smuzhiyun void *rk_hdmi;
101*4882a593Smuzhiyun struct dw_hdmi_i2c *i2c;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun struct {
104*4882a593Smuzhiyun const struct dw_hdmi_qp_phy_ops *ops;
105*4882a593Smuzhiyun const char *name;
106*4882a593Smuzhiyun void *data;
107*4882a593Smuzhiyun bool enabled;
108*4882a593Smuzhiyun } phy;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun struct drm_display_mode previous_mode;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun unsigned int sample_rate;
113*4882a593Smuzhiyun unsigned int audio_cts;
114*4882a593Smuzhiyun unsigned int audio_n;
115*4882a593Smuzhiyun bool audio_enable;
116*4882a593Smuzhiyun bool scramble_low_rates;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun void (*write)(struct dw_hdmi_qp *hdmi, u32 val, int offset);
119*4882a593Smuzhiyun u8 (*read)(struct dw_hdmi_qp *hdmi, int offset);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun bool hdcp1x_enable;
122*4882a593Smuzhiyun bool output_bus_format_rgb;
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun
hdmi_writel(struct dw_hdmi_qp * hdmi,u32 val,int offset)125*4882a593Smuzhiyun static inline void hdmi_writel(struct dw_hdmi_qp *hdmi, u32 val, int offset)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun writel(val, hdmi->regs + offset);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
hdmi_readl(struct dw_hdmi_qp * hdmi,int offset)130*4882a593Smuzhiyun static inline u32 hdmi_readl(struct dw_hdmi_qp *hdmi, int offset)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun return readl(hdmi->regs + offset);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun static void
hdmi_modb(struct dw_hdmi_qp * hdmi,u32 data,u32 mask,unsigned int reg)136*4882a593Smuzhiyun hdmi_modb(struct dw_hdmi_qp *hdmi, u32 data, u32 mask, unsigned int reg)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun u32 val = hdmi_readl(hdmi, reg) & ~mask;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun val |= data & mask;
141*4882a593Smuzhiyun hdmi_writel(hdmi, val, reg);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
hdmi_bus_fmt_is_rgb(unsigned int bus_format)144*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun switch (bus_format) {
147*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB888_1X24:
148*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB101010_1X30:
149*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB121212_1X36:
150*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB161616_1X48:
151*4882a593Smuzhiyun return true;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun default:
154*4882a593Smuzhiyun return false;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
hdmi_bus_fmt_is_yuv444(unsigned int bus_format)158*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun switch (bus_format) {
161*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV8_1X24:
162*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV10_1X30:
163*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV12_1X36:
164*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV16_1X48:
165*4882a593Smuzhiyun return true;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun default:
168*4882a593Smuzhiyun return false;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
hdmi_bus_fmt_is_yuv422(unsigned int bus_format)172*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun switch (bus_format) {
175*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY8_1X16:
176*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY10_1X20:
177*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY12_1X24:
178*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV8_1X16:
179*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV10_1X20:
180*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV12_1X24:
181*4882a593Smuzhiyun return true;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun default:
184*4882a593Smuzhiyun return false;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
hdmi_bus_fmt_is_yuv420(unsigned int bus_format)188*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun switch (bus_format) {
191*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
192*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
193*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
194*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
195*4882a593Smuzhiyun return true;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun default:
198*4882a593Smuzhiyun return false;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
hdmi_bus_fmt_color_depth(unsigned int bus_format)202*4882a593Smuzhiyun static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun switch (bus_format) {
205*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB888_1X24:
206*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV8_1X24:
207*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY8_1X16:
208*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
209*4882a593Smuzhiyun return 8;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB101010_1X30:
212*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV10_1X30:
213*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY10_1X20:
214*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
215*4882a593Smuzhiyun return 10;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB121212_1X36:
218*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV12_1X36:
219*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY12_1X24:
220*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
221*4882a593Smuzhiyun return 12;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB161616_1X48:
224*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV16_1X48:
225*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
226*4882a593Smuzhiyun return 16;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun default:
229*4882a593Smuzhiyun return 0;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
drm_scdc_set_scrambling(struct ddc_adapter * adapter,bool enable)233*4882a593Smuzhiyun static bool drm_scdc_set_scrambling(struct ddc_adapter *adapter, bool enable)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun u8 config;
236*4882a593Smuzhiyun int ret;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
239*4882a593Smuzhiyun if (ret < 0) {
240*4882a593Smuzhiyun debug("Failed to read TMDS config: %d\n", ret);
241*4882a593Smuzhiyun return false;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (enable)
245*4882a593Smuzhiyun config |= SCDC_SCRAMBLING_ENABLE;
246*4882a593Smuzhiyun else
247*4882a593Smuzhiyun config &= ~SCDC_SCRAMBLING_ENABLE;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
250*4882a593Smuzhiyun if (ret < 0) {
251*4882a593Smuzhiyun debug("Failed to enable scrambling: %d\n", ret);
252*4882a593Smuzhiyun return false;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun return true;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun static bool
drm_scdc_set_high_tmds_clock_ratio(struct ddc_adapter * adapter,bool set)259*4882a593Smuzhiyun drm_scdc_set_high_tmds_clock_ratio(struct ddc_adapter *adapter, bool set)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun u8 config;
262*4882a593Smuzhiyun int ret;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
265*4882a593Smuzhiyun if (ret < 0) {
266*4882a593Smuzhiyun debug("Failed to read TMDS config: %d\n", ret);
267*4882a593Smuzhiyun return false;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (set)
271*4882a593Smuzhiyun config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
272*4882a593Smuzhiyun else
273*4882a593Smuzhiyun config &= ~SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
276*4882a593Smuzhiyun if (ret < 0) {
277*4882a593Smuzhiyun debug("Failed to set TMDS clock ratio: %d\n", ret);
278*4882a593Smuzhiyun return false;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun /*
282*4882a593Smuzhiyun * The spec says that a source should wait minimum 1ms and maximum
283*4882a593Smuzhiyun * 100ms after writing the TMDS config for clock ratio. Lets allow a
284*4882a593Smuzhiyun * wait of up to 2ms here.
285*4882a593Smuzhiyun */
286*4882a593Smuzhiyun udelay(2000);
287*4882a593Smuzhiyun return true;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
dw_hdmi_i2c_init(struct dw_hdmi_qp * hdmi)290*4882a593Smuzhiyun static void dw_hdmi_i2c_init(struct dw_hdmi_qp *hdmi)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun /* Software reset */
293*4882a593Smuzhiyun hdmi_writel(hdmi, 0x01, I2CM_CONTROL0);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun hdmi_writel(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun hdmi_modb(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun /* Clear DONE and ERROR interrupts */
300*4882a593Smuzhiyun hdmi_writel(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,
301*4882a593Smuzhiyun MAINUNIT_1_INT_CLEAR);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
dw_hdmi_i2c_read(struct dw_hdmi_qp * hdmi,unsigned char * buf,unsigned int length)304*4882a593Smuzhiyun static int dw_hdmi_i2c_read(struct dw_hdmi_qp *hdmi,
305*4882a593Smuzhiyun unsigned char *buf, unsigned int length)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun struct dw_hdmi_i2c *i2c = hdmi->i2c;
308*4882a593Smuzhiyun int i = 20;
309*4882a593Smuzhiyun u32 intr = 0;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun if (!i2c->is_regaddr) {
312*4882a593Smuzhiyun printf("set read register address to 0\n");
313*4882a593Smuzhiyun i2c->slave_reg = 0x00;
314*4882a593Smuzhiyun i2c->is_regaddr = true;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun while (length--) {
318*4882a593Smuzhiyun hdmi_modb(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR,
319*4882a593Smuzhiyun I2CM_INTERFACE_CONTROL0);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun hdmi_modb(hdmi, I2CM_FM_READ, I2CM_WR_MASK,
322*4882a593Smuzhiyun I2CM_INTERFACE_CONTROL0);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun while (i--) {
325*4882a593Smuzhiyun udelay(1000);
326*4882a593Smuzhiyun intr = hdmi_readl(hdmi, MAINUNIT_1_INT_STATUS) &
327*4882a593Smuzhiyun (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ |
328*4882a593Smuzhiyun I2CM_NACK_RCVD_IRQ);
329*4882a593Smuzhiyun if (intr) {
330*4882a593Smuzhiyun hdmi_writel(hdmi, intr, MAINUNIT_1_INT_CLEAR);
331*4882a593Smuzhiyun break;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (!i) {
336*4882a593Smuzhiyun printf("i2c read time out!\n");
337*4882a593Smuzhiyun hdmi_writel(hdmi, 0x01, I2CM_CONTROL0);
338*4882a593Smuzhiyun return -EAGAIN;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun /* Check for error condition on the bus */
342*4882a593Smuzhiyun if (intr & I2CM_NACK_RCVD_IRQ) {
343*4882a593Smuzhiyun printf("i2c read err!\n");
344*4882a593Smuzhiyun hdmi_writel(hdmi, 0x01, I2CM_CONTROL0);
345*4882a593Smuzhiyun return -EIO;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun *buf++ = hdmi_readl(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff;
349*4882a593Smuzhiyun hdmi_modb(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0);
350*4882a593Smuzhiyun i = 20;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun i2c->is_segment = false;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun return 0;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
dw_hdmi_i2c_write(struct dw_hdmi_qp * hdmi,unsigned char * buf,unsigned int length)357*4882a593Smuzhiyun static int dw_hdmi_i2c_write(struct dw_hdmi_qp *hdmi,
358*4882a593Smuzhiyun unsigned char *buf, unsigned int length)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun struct dw_hdmi_i2c *i2c = hdmi->i2c;
361*4882a593Smuzhiyun int i = 20;
362*4882a593Smuzhiyun u32 intr = 0;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun if (!i2c->is_regaddr) {
365*4882a593Smuzhiyun /* Use the first write byte as register address */
366*4882a593Smuzhiyun i2c->slave_reg = buf[0];
367*4882a593Smuzhiyun length--;
368*4882a593Smuzhiyun buf++;
369*4882a593Smuzhiyun i2c->is_regaddr = true;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun while (length--) {
373*4882a593Smuzhiyun hdmi_writel(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3);
374*4882a593Smuzhiyun hdmi_modb(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR,
375*4882a593Smuzhiyun I2CM_INTERFACE_CONTROL0);
376*4882a593Smuzhiyun hdmi_modb(hdmi, I2CM_FM_WRITE, I2CM_WR_MASK,
377*4882a593Smuzhiyun I2CM_INTERFACE_CONTROL0);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun while (i--) {
380*4882a593Smuzhiyun udelay(1000);
381*4882a593Smuzhiyun intr = hdmi_readl(hdmi, MAINUNIT_1_INT_STATUS) &
382*4882a593Smuzhiyun (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ |
383*4882a593Smuzhiyun I2CM_NACK_RCVD_IRQ);
384*4882a593Smuzhiyun if (intr) {
385*4882a593Smuzhiyun hdmi_writel(hdmi, intr, MAINUNIT_1_INT_CLEAR);
386*4882a593Smuzhiyun break;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (!i) {
391*4882a593Smuzhiyun printf("i2c write time out!\n");
392*4882a593Smuzhiyun hdmi_writel(hdmi, 0x01, I2CM_CONTROL0);
393*4882a593Smuzhiyun return -EAGAIN;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun /* Check for error condition on the bus */
397*4882a593Smuzhiyun if (intr & I2CM_NACK_RCVD_IRQ) {
398*4882a593Smuzhiyun printf("i2c write nack!\n");
399*4882a593Smuzhiyun hdmi_writel(hdmi, 0x01, I2CM_CONTROL0);
400*4882a593Smuzhiyun return -EIO;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun hdmi_modb(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0);
403*4882a593Smuzhiyun i = 20;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun return 0;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
dw_hdmi_i2c_xfer(struct ddc_adapter * adap,struct i2c_msg * msgs,int num)409*4882a593Smuzhiyun static int dw_hdmi_i2c_xfer(struct ddc_adapter *adap,
410*4882a593Smuzhiyun struct i2c_msg *msgs, int num)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = container_of(adap, struct dw_hdmi_qp, adap);
413*4882a593Smuzhiyun struct dw_hdmi_i2c *i2c = hdmi->i2c;
414*4882a593Smuzhiyun u8 addr = msgs[0].addr;
415*4882a593Smuzhiyun int i, ret = 0;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun debug("i2c xfer: num: %d, addr: %#x\n", num, addr);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun for (i = 0; i < num; i++) {
420*4882a593Smuzhiyun if (msgs[i].len == 0) {
421*4882a593Smuzhiyun printf("unsupported transfer %d/%d, no data\n",
422*4882a593Smuzhiyun i + 1, num);
423*4882a593Smuzhiyun return -EOPNOTSUPP;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun /* Unmute DONE and ERROR interrupts */
428*4882a593Smuzhiyun hdmi_modb(hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N,
429*4882a593Smuzhiyun I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N,
430*4882a593Smuzhiyun MAINUNIT_1_INT_MASK_N);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun /* Set slave device address taken from the first I2C message */
433*4882a593Smuzhiyun if (addr == DDC_SEGMENT_ADDR && msgs[0].len == 1)
434*4882a593Smuzhiyun addr = DDC_ADDR;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun hdmi_modb(hdmi, addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun /* Set slave device register address on transfer */
439*4882a593Smuzhiyun i2c->is_regaddr = false;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /* Set segment pointer for I2C extended read mode operation */
442*4882a593Smuzhiyun i2c->is_segment = false;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun for (i = 0; i < num; i++) {
445*4882a593Smuzhiyun debug("xfer: num: %d/%d, len: %d, flags: %#x\n",
446*4882a593Smuzhiyun i + 1, num, msgs[i].len, msgs[i].flags);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) {
449*4882a593Smuzhiyun i2c->is_segment = true;
450*4882a593Smuzhiyun hdmi_modb(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR,
451*4882a593Smuzhiyun I2CM_INTERFACE_CONTROL1);
452*4882a593Smuzhiyun hdmi_modb(hdmi, *msgs[i].buf, I2CM_SEG_PTR,
453*4882a593Smuzhiyun I2CM_INTERFACE_CONTROL1);
454*4882a593Smuzhiyun } else {
455*4882a593Smuzhiyun if (msgs[i].flags & I2C_M_RD)
456*4882a593Smuzhiyun ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf,
457*4882a593Smuzhiyun msgs[i].len);
458*4882a593Smuzhiyun else
459*4882a593Smuzhiyun ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf,
460*4882a593Smuzhiyun msgs[i].len);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun if (ret < 0)
463*4882a593Smuzhiyun break;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun if (!ret)
467*4882a593Smuzhiyun ret = num;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* Mute DONE and ERROR interrupts */
470*4882a593Smuzhiyun hdmi_modb(hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N,
471*4882a593Smuzhiyun MAINUNIT_1_INT_MASK_N);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun return ret;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
dw_hdmi_detect_phy(struct dw_hdmi_qp * hdmi)476*4882a593Smuzhiyun static int dw_hdmi_detect_phy(struct dw_hdmi_qp *hdmi)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun /* Vendor PHYs require support from the glue layer. */
479*4882a593Smuzhiyun if (!hdmi->plat_data->qp_phy_ops || !hdmi->plat_data->phy_name) {
480*4882a593Smuzhiyun dev_err(hdmi->dev,
481*4882a593Smuzhiyun "Vendor HDMI PHY not supported by glue layer\n");
482*4882a593Smuzhiyun return -ENODEV;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun hdmi->phy.ops = hdmi->plat_data->qp_phy_ops;
486*4882a593Smuzhiyun hdmi->phy.data = hdmi->plat_data->phy_data;
487*4882a593Smuzhiyun hdmi->phy.name = hdmi->plat_data->phy_name;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun return 0;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun static unsigned int
hdmi_get_tmdsclock(struct dw_hdmi_qp * hdmi,unsigned long mpixelclock)493*4882a593Smuzhiyun hdmi_get_tmdsclock(struct dw_hdmi_qp *hdmi, unsigned long mpixelclock)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun unsigned int tmdsclock = mpixelclock;
496*4882a593Smuzhiyun unsigned int depth =
497*4882a593Smuzhiyun hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
500*4882a593Smuzhiyun switch (depth) {
501*4882a593Smuzhiyun case 16:
502*4882a593Smuzhiyun tmdsclock = mpixelclock * 2;
503*4882a593Smuzhiyun break;
504*4882a593Smuzhiyun case 12:
505*4882a593Smuzhiyun tmdsclock = mpixelclock * 3 / 2;
506*4882a593Smuzhiyun break;
507*4882a593Smuzhiyun case 10:
508*4882a593Smuzhiyun tmdsclock = mpixelclock * 5 / 4;
509*4882a593Smuzhiyun break;
510*4882a593Smuzhiyun default:
511*4882a593Smuzhiyun break;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun return tmdsclock;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
hdmi_infoframe_set_checksum(u8 * ptr,int size)518*4882a593Smuzhiyun static void hdmi_infoframe_set_checksum(u8 *ptr, int size)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun u8 csum = 0;
521*4882a593Smuzhiyun int i;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun ptr[3] = 0;
524*4882a593Smuzhiyun /* compute checksum */
525*4882a593Smuzhiyun for (i = 0; i < size; i++)
526*4882a593Smuzhiyun csum += ptr[i];
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun ptr[3] = 256 - csum;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
is_hdmi2_sink(struct dw_hdmi_qp * hdmi)531*4882a593Smuzhiyun static bool is_hdmi2_sink(struct dw_hdmi_qp *hdmi)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun return hdmi->edid_data.display_info.hdmi.scdc.supported ||
534*4882a593Smuzhiyun hdmi->edid_data.display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
hdmi_config_AVI(struct dw_hdmi_qp * hdmi,struct drm_display_mode * mode)537*4882a593Smuzhiyun static void hdmi_config_AVI(struct dw_hdmi_qp *hdmi, struct drm_display_mode *mode)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun struct hdmi_avi_infoframe frame;
540*4882a593Smuzhiyun u32 val, i, j;
541*4882a593Smuzhiyun u8 buff[17];
542*4882a593Smuzhiyun bool is_hdmi2 = false;
543*4882a593Smuzhiyun enum hdmi_quantization_range rgb_quant_range =
544*4882a593Smuzhiyun hdmi->hdmi_data.quant_range;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) ||
547*4882a593Smuzhiyun hdmi->edid_data.display_info.hdmi.scdc.supported)
548*4882a593Smuzhiyun is_hdmi2 = true;
549*4882a593Smuzhiyun /* Initialise info frame from DRM mode */
550*4882a593Smuzhiyun drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun /*
553*4882a593Smuzhiyun * Ignore monitor selectable quantization, use quantization set
554*4882a593Smuzhiyun * by the user
555*4882a593Smuzhiyun */
556*4882a593Smuzhiyun drm_hdmi_avi_infoframe_quant_range(&frame, mode, rgb_quant_range,
557*4882a593Smuzhiyun true);
558*4882a593Smuzhiyun if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
559*4882a593Smuzhiyun frame.colorspace = HDMI_COLORSPACE_YUV444;
560*4882a593Smuzhiyun else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
561*4882a593Smuzhiyun frame.colorspace = HDMI_COLORSPACE_YUV422;
562*4882a593Smuzhiyun else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
563*4882a593Smuzhiyun frame.colorspace = HDMI_COLORSPACE_YUV420;
564*4882a593Smuzhiyun else
565*4882a593Smuzhiyun frame.colorspace = HDMI_COLORSPACE_RGB;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /* Set up colorimetry and quant range */
568*4882a593Smuzhiyun if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
569*4882a593Smuzhiyun switch (hdmi->hdmi_data.enc_out_encoding) {
570*4882a593Smuzhiyun case V4L2_YCBCR_ENC_601:
571*4882a593Smuzhiyun if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
572*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
573*4882a593Smuzhiyun else
574*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
575*4882a593Smuzhiyun frame.extended_colorimetry =
576*4882a593Smuzhiyun HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
577*4882a593Smuzhiyun break;
578*4882a593Smuzhiyun case V4L2_YCBCR_ENC_709:
579*4882a593Smuzhiyun if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
580*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
581*4882a593Smuzhiyun else
582*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
583*4882a593Smuzhiyun frame.extended_colorimetry =
584*4882a593Smuzhiyun HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
585*4882a593Smuzhiyun break;
586*4882a593Smuzhiyun case V4L2_YCBCR_ENC_BT2020:
587*4882a593Smuzhiyun if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_BT2020)
588*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
589*4882a593Smuzhiyun else
590*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
591*4882a593Smuzhiyun frame.extended_colorimetry =
592*4882a593Smuzhiyun HDMI_EXTENDED_COLORIMETRY_BT2020;
593*4882a593Smuzhiyun break;
594*4882a593Smuzhiyun default: /* Carries no data */
595*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
596*4882a593Smuzhiyun frame.extended_colorimetry =
597*4882a593Smuzhiyun HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
598*4882a593Smuzhiyun break;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
602*4882a593Smuzhiyun } else {
603*4882a593Smuzhiyun if (hdmi->hdmi_data.enc_out_encoding == V4L2_YCBCR_ENC_BT2020) {
604*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
605*4882a593Smuzhiyun frame.extended_colorimetry =
606*4882a593Smuzhiyun HDMI_EXTENDED_COLORIMETRY_BT2020;
607*4882a593Smuzhiyun } else {
608*4882a593Smuzhiyun frame.colorimetry = HDMI_COLORIMETRY_NONE;
609*4882a593Smuzhiyun frame.extended_colorimetry =
610*4882a593Smuzhiyun HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun if (is_hdmi2_sink(hdmi) &&
614*4882a593Smuzhiyun frame.quantization_range == HDMI_QUANTIZATION_RANGE_FULL)
615*4882a593Smuzhiyun frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_FULL;
616*4882a593Smuzhiyun else
617*4882a593Smuzhiyun frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun frame.scan_mode = HDMI_SCAN_MODE_NONE;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun hdmi_avi_infoframe_pack_only(&frame, buff, 17);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /* mode which vic >= 128 must use avi version 3 */
625*4882a593Smuzhiyun if (hdmi->vic >= 128) {
626*4882a593Smuzhiyun frame.version = 3;
627*4882a593Smuzhiyun buff[1] = frame.version;
628*4882a593Smuzhiyun buff[4] &= 0x1f;
629*4882a593Smuzhiyun buff[4] |= ((frame.colorspace & 0x7) << 5);
630*4882a593Smuzhiyun buff[7] = hdmi->vic;
631*4882a593Smuzhiyun hdmi_infoframe_set_checksum(buff, 17);
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun /*
635*4882a593Smuzhiyun * The Designware IP uses a different byte format from standard
636*4882a593Smuzhiyun * AVI info frames, though generally the bits are in the correct
637*4882a593Smuzhiyun * bytes.
638*4882a593Smuzhiyun */
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun val = (frame.version << 8) | (frame.length << 16);
641*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT_AVI_CONTENTS0);
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
644*4882a593Smuzhiyun for (j = 0; j < 4; j++) {
645*4882a593Smuzhiyun if (i * 4 + j >= 14)
646*4882a593Smuzhiyun break;
647*4882a593Smuzhiyun if (!j)
648*4882a593Smuzhiyun val = buff[i * 4 + j + 3];
649*4882a593Smuzhiyun val |= buff[i * 4 + j + 3] << (8 * j);
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT_AVI_CONTENTS1 + i * 4);
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun hdmi_modb(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun hdmi_modb(hdmi, PKTSCHED_AVI_TX_EN, PKTSCHED_AVI_TX_EN,
658*4882a593Smuzhiyun PKTSCHED_PKT_EN);
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun #define VSI_PKT_TYPE 0x81
662*4882a593Smuzhiyun #define VSI_PKT_VERSION 1
663*4882a593Smuzhiyun #define HDMI_FORUM_OUI 0xc45dd8
664*4882a593Smuzhiyun #define ALLM_MODE BIT(1)
665*4882a593Smuzhiyun #define HDMI_FORUM_LEN 9
666*4882a593Smuzhiyun
hdmi_config_vendor_specific_infoframe(struct dw_hdmi_qp * hdmi,struct drm_display_mode * mode)667*4882a593Smuzhiyun static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi_qp *hdmi,
668*4882a593Smuzhiyun struct drm_display_mode *mode)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun struct hdmi_vendor_infoframe frame;
671*4882a593Smuzhiyun struct dw_hdmi_link_config *link_cfg = NULL;
672*4882a593Smuzhiyun u8 buffer[10];
673*4882a593Smuzhiyun u32 val;
674*4882a593Smuzhiyun ssize_t err;
675*4882a593Smuzhiyun int i, reg;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun link_cfg = dw_hdmi_rockchip_get_link_cfg(hdmi->rk_hdmi);
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun hdmi_modb(hdmi, 0, PKTSCHED_VSI_TX_EN, PKTSCHED_PKT_EN);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun for (i = 0; i <= 7; i++)
682*4882a593Smuzhiyun hdmi_writel(hdmi, 0, PKT_VSI_CONTENTS0 + i * 4);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (link_cfg->allm_en) {
685*4882a593Smuzhiyun buffer[0] = VSI_PKT_TYPE;
686*4882a593Smuzhiyun buffer[1] = VSI_PKT_VERSION;
687*4882a593Smuzhiyun buffer[2] = 5;
688*4882a593Smuzhiyun buffer[4] = HDMI_FORUM_OUI & 0xff;
689*4882a593Smuzhiyun buffer[5] = (HDMI_FORUM_OUI >> 8) & 0xff;
690*4882a593Smuzhiyun buffer[6] = (HDMI_FORUM_OUI >> 16) & 0xff;
691*4882a593Smuzhiyun buffer[7] = VSI_PKT_VERSION;
692*4882a593Smuzhiyun buffer[8] = ALLM_MODE;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun hdmi_infoframe_set_checksum(buffer, HDMI_FORUM_LEN);
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun err = 9;
697*4882a593Smuzhiyun } else {
698*4882a593Smuzhiyun err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, mode);
699*4882a593Smuzhiyun if (err < 0)
700*4882a593Smuzhiyun /*
701*4882a593Smuzhiyun * Going into that statement does not means vendor infoframe
702*4882a593Smuzhiyun * fails. It just informed us that vendor infoframe is not
703*4882a593Smuzhiyun * needed for the selected mode. Only 4k or stereoscopic 3D
704*4882a593Smuzhiyun * mode requires vendor infoframe. So just simply return.
705*4882a593Smuzhiyun */
706*4882a593Smuzhiyun return;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer));
709*4882a593Smuzhiyun if (err < 0) {
710*4882a593Smuzhiyun dev_err(hdmi->dev, "Failed to pack vendor infoframe: %zd\n",
711*4882a593Smuzhiyun err);
712*4882a593Smuzhiyun return;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun /* vsi header */
717*4882a593Smuzhiyun val = (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
718*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT_VSI_CONTENTS0);
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun reg = PKT_VSI_CONTENTS1;
721*4882a593Smuzhiyun for (i = 3; i < err; i++) {
722*4882a593Smuzhiyun if (i % 4 == 3)
723*4882a593Smuzhiyun val = buffer[i];
724*4882a593Smuzhiyun if (i % 4 == 0)
725*4882a593Smuzhiyun val |= buffer[i] << 8;
726*4882a593Smuzhiyun if (i % 4 == 1)
727*4882a593Smuzhiyun val |= buffer[i] << 16;
728*4882a593Smuzhiyun if (i % 4 == 2)
729*4882a593Smuzhiyun val |= buffer[i] << 24;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun if ((i % 4 == 2) || (i == (err - 1))) {
732*4882a593Smuzhiyun hdmi_writel(hdmi, val, reg);
733*4882a593Smuzhiyun reg += 4;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun hdmi_writel(hdmi, 0, PKT_VSI_CONTENTS7);
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun hdmi_modb(hdmi, 0, PKTSCHED_VSI_FIELDRATE, PKTSCHED_PKT_CONFIG1);
740*4882a593Smuzhiyun hdmi_modb(hdmi, PKTSCHED_VSI_TX_EN, PKTSCHED_VSI_TX_EN,
741*4882a593Smuzhiyun PKTSCHED_PKT_EN);
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
hdmi_config_CVTEM(struct dw_hdmi_qp * hdmi,struct dw_hdmi_link_config * link_cfg)744*4882a593Smuzhiyun static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi,
745*4882a593Smuzhiyun struct dw_hdmi_link_config *link_cfg)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun u8 ds_type = 0;
748*4882a593Smuzhiyun u8 sync = 1;
749*4882a593Smuzhiyun u8 vfr = 1;
750*4882a593Smuzhiyun u8 afr = 0;
751*4882a593Smuzhiyun u8 new = 1;
752*4882a593Smuzhiyun u8 end = 0;
753*4882a593Smuzhiyun u8 data_set_length = 136;
754*4882a593Smuzhiyun u8 hb1[6] = { 0x80, 0, 0, 0, 0, 0x40 };
755*4882a593Smuzhiyun u8 *pps_body;
756*4882a593Smuzhiyun u32 val, i, reg;
757*4882a593Smuzhiyun struct drm_display_mode *mode = &hdmi->previous_mode;
758*4882a593Smuzhiyun int hsync, hfront, hback;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun hdmi_modb(hdmi, 0, PKTSCHED_EMP_CVTEM_TX_EN, PKTSCHED_PKT_EN);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun if (!link_cfg->dsc_mode) {
763*4882a593Smuzhiyun printf("don't use dsc mode\n");
764*4882a593Smuzhiyun return;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun pps_body = link_cfg->pps_payload;
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun hsync = mode->hsync_end - mode->hsync_start;
770*4882a593Smuzhiyun hback = mode->htotal - mode->hsync_end;
771*4882a593Smuzhiyun hfront = mode->hsync_start - mode->hdisplay;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun for (i = 0; i < 6; i++) {
774*4882a593Smuzhiyun val = i << 16 | hb1[i] << 8;
775*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS0 + i * 0x20);
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun val = new << 7 | end << 6 | ds_type << 4 | afr << 3 |
779*4882a593Smuzhiyun vfr << 2 | sync << 1;
780*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS1);
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun val = data_set_length << 16 | pps_body[0] << 24;
783*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS2);
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun reg = PKT0_EMP_CVTEM_CONTENTS3;
786*4882a593Smuzhiyun for (i = 1; i < 125; i++) {
787*4882a593Smuzhiyun if (reg == PKT1_EMP_CVTEM_CONTENTS0 ||
788*4882a593Smuzhiyun reg == PKT2_EMP_CVTEM_CONTENTS0 ||
789*4882a593Smuzhiyun reg == PKT3_EMP_CVTEM_CONTENTS0 ||
790*4882a593Smuzhiyun reg == PKT4_EMP_CVTEM_CONTENTS0 ||
791*4882a593Smuzhiyun reg == PKT5_EMP_CVTEM_CONTENTS0) {
792*4882a593Smuzhiyun reg += 4;
793*4882a593Smuzhiyun i--;
794*4882a593Smuzhiyun continue;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun if (i % 4 == 1)
797*4882a593Smuzhiyun val = pps_body[i];
798*4882a593Smuzhiyun if (i % 4 == 2)
799*4882a593Smuzhiyun val |= pps_body[i] << 8;
800*4882a593Smuzhiyun if (i % 4 == 3)
801*4882a593Smuzhiyun val |= pps_body[i] << 16;
802*4882a593Smuzhiyun if (!(i % 4)) {
803*4882a593Smuzhiyun val |= pps_body[i] << 24;
804*4882a593Smuzhiyun hdmi_writel(hdmi, val, reg);
805*4882a593Smuzhiyun reg += 4;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun val = (hfront & 0xff) << 24 | pps_body[127] << 16 |
810*4882a593Smuzhiyun pps_body[126] << 8 | pps_body[125];
811*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT4_EMP_CVTEM_CONTENTS6);
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun val = (hback & 0xff) << 24 | ((hsync >> 8) & 0xff) << 16 |
814*4882a593Smuzhiyun (hsync & 0xff) << 8 | ((hfront >> 8) & 0xff);
815*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT4_EMP_CVTEM_CONTENTS7);
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun val = link_cfg->hcactive << 8 | ((hback >> 8) & 0xff);
818*4882a593Smuzhiyun hdmi_writel(hdmi, val, PKT5_EMP_CVTEM_CONTENTS1);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun for (i = PKT5_EMP_CVTEM_CONTENTS2; i <= PKT5_EMP_CVTEM_CONTENTS7; i += 4)
821*4882a593Smuzhiyun hdmi_writel(hdmi, 0, i);
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun hdmi_modb(hdmi, PKTSCHED_EMP_CVTEM_TX_EN, PKTSCHED_EMP_CVTEM_TX_EN,
824*4882a593Smuzhiyun PKTSCHED_PKT_EN);
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun
hdmi_set_frl_mask(int frl_rate)827*4882a593Smuzhiyun static int hdmi_set_frl_mask(int frl_rate)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun switch (frl_rate) {
830*4882a593Smuzhiyun case 48:
831*4882a593Smuzhiyun return FRL_12GBPS_4LANE;
832*4882a593Smuzhiyun case 40:
833*4882a593Smuzhiyun return FRL_10GBPS_4LANE;
834*4882a593Smuzhiyun case 32:
835*4882a593Smuzhiyun return FRL_8GBPS_4LANE;
836*4882a593Smuzhiyun case 24:
837*4882a593Smuzhiyun return FRL_6GBPS_4LANE;
838*4882a593Smuzhiyun case 18:
839*4882a593Smuzhiyun return FRL_6GBPS_3LANE;
840*4882a593Smuzhiyun case 9:
841*4882a593Smuzhiyun return FRL_3GBPS_3LANE;
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun return 0;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun
hdmi_start_flt(struct dw_hdmi_qp * hdmi,u8 rate)847*4882a593Smuzhiyun static int hdmi_start_flt(struct dw_hdmi_qp *hdmi, u8 rate)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun u8 val;
850*4882a593Smuzhiyun u32 value;
851*4882a593Smuzhiyun u8 ffe_lv = 0;
852*4882a593Smuzhiyun int i = 0;
853*4882a593Smuzhiyun bool ltsp = false;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun hdmi_modb(hdmi, AVP_DATAPATH_VIDEO_SWDISABLE,
856*4882a593Smuzhiyun AVP_DATAPATH_VIDEO_SWDISABLE, GLOBAL_SWDISABLE);
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun hdmi_writel(hdmi, AVP_DATAPATH_SWINIT_P, GLOBAL_SWRESET_REQUEST);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun /* clear flt flags */
861*4882a593Smuzhiyun drm_scdc_writeb(&hdmi->adap, 0x10, 0xff);
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun /* FLT_READY & FFE_LEVELS read */
864*4882a593Smuzhiyun for (i = 0; i < 20; i++) {
865*4882a593Smuzhiyun drm_scdc_readb(&hdmi->adap, SCDC_STATUS_FLAGS_0, &val);
866*4882a593Smuzhiyun if (val & BIT(6))
867*4882a593Smuzhiyun break;
868*4882a593Smuzhiyun mdelay(20);
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun if (i == 20) {
872*4882a593Smuzhiyun printf("sink flt isn't ready\n");
873*4882a593Smuzhiyun return -EINVAL;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun /* max ffe level 3 */
877*4882a593Smuzhiyun val = 0 << 4 | hdmi_set_frl_mask(rate);
878*4882a593Smuzhiyun drm_scdc_writeb(&hdmi->adap, 0x31, val);
879*4882a593Smuzhiyun /* select FRL_RATE & FFE_LEVELS */
880*4882a593Smuzhiyun hdmi_writel(hdmi, ffe_lv, FLT_CONFIG0);
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun i = 500;
883*4882a593Smuzhiyun while (i--) {
884*4882a593Smuzhiyun mdelay(4);
885*4882a593Smuzhiyun drm_scdc_readb(&hdmi->adap, 0x10, &val);
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun if (!(val & 0x30))
888*4882a593Smuzhiyun continue;
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun if (val & BIT(5)) {
891*4882a593Smuzhiyun u8 reg_val, ln0, ln1, ln2, ln3;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun drm_scdc_readb(&hdmi->adap, 0x41, ®_val);
894*4882a593Smuzhiyun ln0 = reg_val & 0xf;
895*4882a593Smuzhiyun ln1 = (reg_val >> 4) & 0xf;
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun drm_scdc_readb(&hdmi->adap, 0x42, ®_val);
898*4882a593Smuzhiyun ln2 = reg_val & 0xf;
899*4882a593Smuzhiyun ln3 = (reg_val >> 4) & 0xf;
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun if (!ln0 && !ln1 && !ln2 && !ln3) {
902*4882a593Smuzhiyun printf("goto ltsp\n");
903*4882a593Smuzhiyun ltsp = true;
904*4882a593Smuzhiyun hdmi_writel(hdmi, 0, FLT_CONFIG1);
905*4882a593Smuzhiyun } else if ((ln0 == 0xf) | (ln1 == 0xf) | (ln2 == 0xf) | (ln3 == 0xf)) {
906*4882a593Smuzhiyun printf("goto lts4\n");
907*4882a593Smuzhiyun break;
908*4882a593Smuzhiyun } else if ((ln0 == 0xe) | (ln1 == 0xe) | (ln2 == 0xe) | (ln3 == 0xe)) {
909*4882a593Smuzhiyun printf("goto ffe\n");
910*4882a593Smuzhiyun break;
911*4882a593Smuzhiyun } else {
912*4882a593Smuzhiyun value = (ln3 << 16) | (ln2 << 12) | (ln1 << 8) | (ln0 << 4) | 0xf;
913*4882a593Smuzhiyun hdmi_writel(hdmi, value, FLT_CONFIG1);
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun drm_scdc_writeb(&hdmi->adap, 0x10, val);
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun if ((val & BIT(4)) && ltsp) {
920*4882a593Smuzhiyun hdmi_modb(hdmi, 0, AVP_DATAPATH_VIDEO_SWDISABLE, GLOBAL_SWDISABLE);
921*4882a593Smuzhiyun printf("flt success\n");
922*4882a593Smuzhiyun break;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun if (i < 0) {
927*4882a593Smuzhiyun printf("flt time out\n");
928*4882a593Smuzhiyun return -ETIMEDOUT;
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun return 0;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun #define HDMI_MODE_FRL_MASK BIT(30)
935*4882a593Smuzhiyun
hdmi_set_op_mode(struct dw_hdmi_qp * hdmi,struct dw_hdmi_link_config * link_cfg,struct display_state * state,struct rockchip_connector * conn)936*4882a593Smuzhiyun static void hdmi_set_op_mode(struct dw_hdmi_qp *hdmi,
937*4882a593Smuzhiyun struct dw_hdmi_link_config *link_cfg,
938*4882a593Smuzhiyun struct display_state *state,
939*4882a593Smuzhiyun struct rockchip_connector *conn)
940*4882a593Smuzhiyun {
941*4882a593Smuzhiyun int frl_rate;
942*4882a593Smuzhiyun int i, ret;
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun if (!link_cfg->frl_mode) {
945*4882a593Smuzhiyun printf("dw hdmi qp use tmds mode\n");
946*4882a593Smuzhiyun hdmi_modb(hdmi, 0, OPMODE_FRL, LINK_CONFIG0);
947*4882a593Smuzhiyun hdmi_modb(hdmi, 0, OPMODE_FRL_4LANES, LINK_CONFIG0);
948*4882a593Smuzhiyun hdmi->phy.ops->init(conn, hdmi->rk_hdmi, state);
949*4882a593Smuzhiyun hdmi->phy.enabled = true;
950*4882a593Smuzhiyun return;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun if (link_cfg->frl_lanes == 4)
954*4882a593Smuzhiyun hdmi_modb(hdmi, OPMODE_FRL_4LANES, OPMODE_FRL_4LANES,
955*4882a593Smuzhiyun LINK_CONFIG0);
956*4882a593Smuzhiyun else
957*4882a593Smuzhiyun hdmi_modb(hdmi, 0, OPMODE_FRL_4LANES, LINK_CONFIG0);
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun hdmi_modb(hdmi, 1, OPMODE_FRL, LINK_CONFIG0);
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun frl_rate = link_cfg->frl_lanes * link_cfg->rate_per_lane;
962*4882a593Smuzhiyun hdmi->phy.ops->init(conn, hdmi->rk_hdmi, state);
963*4882a593Smuzhiyun hdmi->phy.enabled = true;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun mdelay(200);
966*4882a593Smuzhiyun ret = hdmi_start_flt(hdmi, frl_rate);
967*4882a593Smuzhiyun if (ret) {
968*4882a593Smuzhiyun hdmi_writel(hdmi, 0, FLT_CONFIG0);
969*4882a593Smuzhiyun drm_scdc_writeb(&hdmi->adap, 0x31, 0);
970*4882a593Smuzhiyun hdmi_modb(hdmi, 0, AVP_DATAPATH_VIDEO_SWDISABLE, GLOBAL_SWDISABLE);
971*4882a593Smuzhiyun return;
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun for (i = 0; i < 200; i++) {
975*4882a593Smuzhiyun hdmi_modb(hdmi, PKTSCHED_NULL_TX_EN, PKTSCHED_NULL_TX_EN, PKTSCHED_PKT_EN);
976*4882a593Smuzhiyun udelay(50);
977*4882a593Smuzhiyun hdmi_modb(hdmi, 0, PKTSCHED_NULL_TX_EN, PKTSCHED_PKT_EN);
978*4882a593Smuzhiyun udelay(50);
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun
dw_hdmi_setup(struct dw_hdmi_qp * hdmi,struct rockchip_connector * conn,struct drm_display_mode * mode,struct display_state * state)982*4882a593Smuzhiyun static int dw_hdmi_setup(struct dw_hdmi_qp *hdmi,
983*4882a593Smuzhiyun struct rockchip_connector *conn,
984*4882a593Smuzhiyun struct drm_display_mode *mode,
985*4882a593Smuzhiyun struct display_state *state)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun int ret;
988*4882a593Smuzhiyun void *data = hdmi->plat_data->phy_data;
989*4882a593Smuzhiyun struct dw_hdmi_link_config *link_cfg;
990*4882a593Smuzhiyun struct drm_hdmi_info *hdmi_info = &hdmi->edid_data.display_info.hdmi;
991*4882a593Smuzhiyun struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
992*4882a593Smuzhiyun u8 bytes = 0;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun if (!hdmi->vic)
995*4882a593Smuzhiyun printf("Non-CEA mode used in HDMI\n");
996*4882a593Smuzhiyun else
997*4882a593Smuzhiyun printf("CEA mode used vic=%d\n", hdmi->vic);
998*4882a593Smuzhiyun
999*4882a593Smuzhiyun vmode->mpixelclock = mode->clock * 1000;
1000*4882a593Smuzhiyun vmode->mtmdsclock = hdmi_get_tmdsclock(hdmi, vmode->mpixelclock);
1001*4882a593Smuzhiyun if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
1002*4882a593Smuzhiyun vmode->mtmdsclock /= 2;
1003*4882a593Smuzhiyun printf("mtmdsclock:%d\n", vmode->mtmdsclock);
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun if (hdmi->plat_data->get_enc_out_encoding)
1006*4882a593Smuzhiyun hdmi->hdmi_data.enc_out_encoding =
1007*4882a593Smuzhiyun hdmi->plat_data->get_enc_out_encoding(data);
1008*4882a593Smuzhiyun else if (hdmi->vic == 6 || hdmi->vic == 7 ||
1009*4882a593Smuzhiyun hdmi->vic == 21 || hdmi->vic == 22 ||
1010*4882a593Smuzhiyun hdmi->vic == 2 || hdmi->vic == 3 ||
1011*4882a593Smuzhiyun hdmi->vic == 17 || hdmi->vic == 18)
1012*4882a593Smuzhiyun hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601;
1013*4882a593Smuzhiyun else
1014*4882a593Smuzhiyun hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709;
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
1017*4882a593Smuzhiyun hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
1018*4882a593Smuzhiyun hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 1;
1019*4882a593Smuzhiyun } else {
1020*4882a593Smuzhiyun hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
1021*4882a593Smuzhiyun hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun /* TOFIX: Get input encoding from plat data or fallback to none */
1025*4882a593Smuzhiyun if (hdmi->plat_data->get_enc_in_encoding)
1026*4882a593Smuzhiyun hdmi->hdmi_data.enc_in_encoding =
1027*4882a593Smuzhiyun hdmi->plat_data->get_enc_in_encoding(data);
1028*4882a593Smuzhiyun else if (hdmi->plat_data->input_bus_encoding)
1029*4882a593Smuzhiyun hdmi->hdmi_data.enc_in_encoding =
1030*4882a593Smuzhiyun hdmi->plat_data->input_bus_encoding;
1031*4882a593Smuzhiyun else
1032*4882a593Smuzhiyun hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun if (hdmi->plat_data->get_quant_range)
1035*4882a593Smuzhiyun hdmi->hdmi_data.quant_range =
1036*4882a593Smuzhiyun hdmi->plat_data->get_quant_range(data);
1037*4882a593Smuzhiyun else
1038*4882a593Smuzhiyun hdmi->hdmi_data.quant_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun /*
1041*4882a593Smuzhiyun * According to the dw-hdmi specification 6.4.2
1042*4882a593Smuzhiyun * vp_pr_cd[3:0]:
1043*4882a593Smuzhiyun * 0000b: No pixel repetition (pixel sent only once)
1044*4882a593Smuzhiyun * 0001b: Pixel sent two times (pixel repeated once)
1045*4882a593Smuzhiyun */
1046*4882a593Smuzhiyun hdmi->hdmi_data.pix_repet_factor =
1047*4882a593Smuzhiyun (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 1 : 0;
1048*4882a593Smuzhiyun hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun /* HDMI Initialization Step B.2 */
1051*4882a593Smuzhiyun hdmi->phy.ops->set_pll(conn, hdmi->rk_hdmi, state);
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun /* Mark yuv422 10bit */
1054*4882a593Smuzhiyun if (hdmi->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_YUYV10_1X20)
1055*4882a593Smuzhiyun hdmi_writel(hdmi, BIT(20), VIDEO_INTERFACE_CONFIG0);
1056*4882a593Smuzhiyun rk3588_set_grf_cfg(hdmi->rk_hdmi);
1057*4882a593Smuzhiyun link_cfg = dw_hdmi_rockchip_get_link_cfg(hdmi->rk_hdmi);
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun /* not for DVI mode */
1060*4882a593Smuzhiyun if (hdmi->sink_is_hdmi) {
1061*4882a593Smuzhiyun printf("%s HDMI mode\n", __func__);
1062*4882a593Smuzhiyun hdmi_modb(hdmi, 0, OPMODE_DVI, LINK_CONFIG0);
1063*4882a593Smuzhiyun hdmi_modb(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
1064*4882a593Smuzhiyun hdmi_modb(hdmi, KEEPOUT_REKEY_ALWAYS, KEEPOUT_REKEY_CFG, FRAME_COMPOSER_CONFIG9);
1065*4882a593Smuzhiyun hdmi_writel(hdmi, 0, FLT_CONFIG0);
1066*4882a593Smuzhiyun if (hdmi_info->scdc.supported)
1067*4882a593Smuzhiyun drm_scdc_writeb(&hdmi->adap, 0x31, 0);
1068*4882a593Smuzhiyun if (!link_cfg->frl_mode) {
1069*4882a593Smuzhiyun if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK) {
1070*4882a593Smuzhiyun drm_scdc_readb(&hdmi->adap, SCDC_SINK_VERSION, &bytes);
1071*4882a593Smuzhiyun drm_scdc_writeb(&hdmi->adap, SCDC_SOURCE_VERSION,
1072*4882a593Smuzhiyun min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
1073*4882a593Smuzhiyun drm_scdc_set_high_tmds_clock_ratio(&hdmi->adap, 1);
1074*4882a593Smuzhiyun drm_scdc_set_scrambling(&hdmi->adap, 1);
1075*4882a593Smuzhiyun hdmi_writel(hdmi, 1, SCRAMB_CONFIG0);
1076*4882a593Smuzhiyun mdelay(100);
1077*4882a593Smuzhiyun } else {
1078*4882a593Smuzhiyun if (hdmi_info->scdc.supported) {
1079*4882a593Smuzhiyun drm_scdc_set_high_tmds_clock_ratio(&hdmi->adap, 0);
1080*4882a593Smuzhiyun drm_scdc_set_scrambling(&hdmi->adap, 0);
1081*4882a593Smuzhiyun }
1082*4882a593Smuzhiyun hdmi_writel(hdmi, 0, SCRAMB_CONFIG0);
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun }
1085*4882a593Smuzhiyun /* HDMI Initialization Step F - Configure AVI InfoFrame */
1086*4882a593Smuzhiyun hdmi_config_AVI(hdmi, mode);
1087*4882a593Smuzhiyun hdmi_config_vendor_specific_infoframe(hdmi, mode);
1088*4882a593Smuzhiyun hdmi_config_CVTEM(hdmi, link_cfg);
1089*4882a593Smuzhiyun hdmi_set_op_mode(hdmi, link_cfg, state, conn);
1090*4882a593Smuzhiyun /* clear avmute */
1091*4882a593Smuzhiyun mdelay(50);
1092*4882a593Smuzhiyun hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0);
1093*4882a593Smuzhiyun hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN,
1094*4882a593Smuzhiyun PKTSCHED_PKT_EN);
1095*4882a593Smuzhiyun } else {
1096*4882a593Smuzhiyun hdmi_modb(hdmi, OPMODE_DVI, OPMODE_DVI, LINK_CONFIG0);
1097*4882a593Smuzhiyun ret = hdmi->phy.ops->init(conn, hdmi->rk_hdmi, state);
1098*4882a593Smuzhiyun if (ret)
1099*4882a593Smuzhiyun return ret;
1100*4882a593Smuzhiyun hdmi->phy.enabled = true;
1101*4882a593Smuzhiyun printf("%s DVI mode\n", __func__);
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun /* Mark uboot hdmi is enabled */
1105*4882a593Smuzhiyun hdmi_writel(hdmi, BIT(21), VIDEO_INTERFACE_CONFIG0);
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun return 0;
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun
dw_hdmi_detect_hotplug(struct dw_hdmi_qp * hdmi,struct display_state * state)1110*4882a593Smuzhiyun int dw_hdmi_detect_hotplug(struct dw_hdmi_qp *hdmi,
1111*4882a593Smuzhiyun struct display_state *state)
1112*4882a593Smuzhiyun {
1113*4882a593Smuzhiyun struct connector_state *conn_state = &state->conn_state;
1114*4882a593Smuzhiyun int ret;
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun ret = hdmi->phy.ops->read_hpd(hdmi->rk_hdmi);
1117*4882a593Smuzhiyun if (ret || state->force_output) {
1118*4882a593Smuzhiyun if (!hdmi->id)
1119*4882a593Smuzhiyun conn_state->output_if |= VOP_OUTPUT_IF_HDMI0;
1120*4882a593Smuzhiyun else
1121*4882a593Smuzhiyun conn_state->output_if |= VOP_OUTPUT_IF_HDMI1;
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun return ret;
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_init(struct rockchip_connector * conn,struct display_state * state)1127*4882a593Smuzhiyun int rockchip_dw_hdmi_qp_init(struct rockchip_connector *conn, struct display_state *state)
1128*4882a593Smuzhiyun {
1129*4882a593Smuzhiyun struct connector_state *conn_state = &state->conn_state;
1130*4882a593Smuzhiyun const struct dw_hdmi_plat_data *pdata =
1131*4882a593Smuzhiyun (const struct dw_hdmi_plat_data *)dev_get_driver_data(conn->dev);
1132*4882a593Smuzhiyun void *rk_hdmi = dev_get_priv(conn->dev);
1133*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi;
1134*4882a593Smuzhiyun struct drm_display_mode *mode_buf;
1135*4882a593Smuzhiyun ofnode hdmi_node = conn->dev->node;
1136*4882a593Smuzhiyun struct device_node *ddc_node;
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun hdmi = malloc(sizeof(struct dw_hdmi_qp));
1139*4882a593Smuzhiyun if (!hdmi)
1140*4882a593Smuzhiyun return -ENOMEM;
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun memset(hdmi, 0, sizeof(struct dw_hdmi_qp));
1143*4882a593Smuzhiyun mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode));
1144*4882a593Smuzhiyun if (!mode_buf)
1145*4882a593Smuzhiyun return -ENOMEM;
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun hdmi->rk_hdmi = rk_hdmi;
1148*4882a593Smuzhiyun hdmi->id = of_alias_get_id(ofnode_to_np(hdmi_node), "hdmi");
1149*4882a593Smuzhiyun if (hdmi->id < 0)
1150*4882a593Smuzhiyun hdmi->id = 0;
1151*4882a593Smuzhiyun conn_state->disp_info = rockchip_get_disp_info(conn_state->type, hdmi->id);
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode));
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun hdmi->regs = dev_read_addr_ptr(conn->dev);
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun ddc_node = of_parse_phandle(ofnode_to_np(hdmi_node), "ddc-i2c-bus", 0);
1158*4882a593Smuzhiyun if (ddc_node) {
1159*4882a593Smuzhiyun uclass_get_device_by_ofnode(UCLASS_I2C, np_to_ofnode(ddc_node),
1160*4882a593Smuzhiyun &hdmi->adap.i2c_bus);
1161*4882a593Smuzhiyun if (hdmi->adap.i2c_bus)
1162*4882a593Smuzhiyun hdmi->adap.ops = i2c_get_ops(hdmi->adap.i2c_bus);
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun hdmi->i2c = malloc(sizeof(struct dw_hdmi_i2c));
1166*4882a593Smuzhiyun if (!hdmi->i2c)
1167*4882a593Smuzhiyun return -ENOMEM;
1168*4882a593Smuzhiyun hdmi->adap.ddc_xfer = dw_hdmi_i2c_xfer;
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun /*
1171*4882a593Smuzhiyun * Read high and low time from device tree. If not available use
1172*4882a593Smuzhiyun * the default timing scl clock rate is about 99.6KHz.
1173*4882a593Smuzhiyun */
1174*4882a593Smuzhiyun hdmi->i2c->scl_high_ns =
1175*4882a593Smuzhiyun ofnode_read_s32_default(hdmi_node,
1176*4882a593Smuzhiyun "ddc-i2c-scl-high-time-ns", 4708);
1177*4882a593Smuzhiyun hdmi->i2c->scl_low_ns =
1178*4882a593Smuzhiyun ofnode_read_s32_default(hdmi_node,
1179*4882a593Smuzhiyun "ddc-i2c-scl-low-time-ns", 4916);
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun dw_hdmi_i2c_init(hdmi);
1182*4882a593Smuzhiyun conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun hdmi->dev_type = pdata->dev_type;
1185*4882a593Smuzhiyun hdmi->plat_data = pdata;
1186*4882a593Smuzhiyun hdmi->edid_data.mode_buf = mode_buf;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun conn->data = hdmi;
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun dw_hdmi_detect_phy(hdmi);
1191*4882a593Smuzhiyun hdmi_writel(hdmi, 0, MAINUNIT_0_INT_MASK_N);
1192*4882a593Smuzhiyun hdmi_writel(hdmi, 0, MAINUNIT_1_INT_MASK_N);
1193*4882a593Smuzhiyun hdmi_writel(hdmi, 428571429, TIMER_BASE_CONFIG0);
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun dw_hdmi_qp_set_iomux(hdmi->rk_hdmi);
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun return 0;
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_deinit(struct rockchip_connector * conn,struct display_state * state)1200*4882a593Smuzhiyun void rockchip_dw_hdmi_qp_deinit(struct rockchip_connector *conn, struct display_state *state)
1201*4882a593Smuzhiyun {
1202*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = conn->data;
1203*4882a593Smuzhiyun
1204*4882a593Smuzhiyun if (hdmi->i2c)
1205*4882a593Smuzhiyun free(hdmi->i2c);
1206*4882a593Smuzhiyun if (hdmi->edid_data.mode_buf)
1207*4882a593Smuzhiyun free(hdmi->edid_data.mode_buf);
1208*4882a593Smuzhiyun if (hdmi)
1209*4882a593Smuzhiyun free(hdmi);
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_prepare(struct rockchip_connector * conn,struct display_state * state)1212*4882a593Smuzhiyun int rockchip_dw_hdmi_qp_prepare(struct rockchip_connector *conn, struct display_state *state)
1213*4882a593Smuzhiyun {
1214*4882a593Smuzhiyun return 0;
1215*4882a593Smuzhiyun }
1216*4882a593Smuzhiyun
dw_hdmi_disable(struct rockchip_connector * conn,struct dw_hdmi_qp * hdmi,struct display_state * state)1217*4882a593Smuzhiyun static void dw_hdmi_disable(struct rockchip_connector *conn, struct dw_hdmi_qp *hdmi,
1218*4882a593Smuzhiyun struct display_state *state)
1219*4882a593Smuzhiyun {
1220*4882a593Smuzhiyun if (hdmi->phy.enabled) {
1221*4882a593Smuzhiyun hdmi->phy.ops->disable(conn, hdmi->rk_hdmi, state);
1222*4882a593Smuzhiyun hdmi->phy.enabled = false;
1223*4882a593Smuzhiyun }
1224*4882a593Smuzhiyun }
1225*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_enable(struct rockchip_connector * conn,struct display_state * state)1226*4882a593Smuzhiyun int rockchip_dw_hdmi_qp_enable(struct rockchip_connector *conn, struct display_state *state)
1227*4882a593Smuzhiyun {
1228*4882a593Smuzhiyun struct connector_state *conn_state = &state->conn_state;
1229*4882a593Smuzhiyun struct drm_display_mode *mode = &conn_state->mode;
1230*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = conn->data;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun if (!hdmi)
1233*4882a593Smuzhiyun return -EFAULT;
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun /* Store the display mode for plugin/DKMS poweron events */
1236*4882a593Smuzhiyun memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
1237*4882a593Smuzhiyun
1238*4882a593Smuzhiyun dw_hdmi_setup(hdmi, conn, mode, state);
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun return 0;
1241*4882a593Smuzhiyun }
1242*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_disable(struct rockchip_connector * conn,struct display_state * state)1243*4882a593Smuzhiyun int rockchip_dw_hdmi_qp_disable(struct rockchip_connector *conn, struct display_state *state)
1244*4882a593Smuzhiyun {
1245*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = conn->data;
1246*4882a593Smuzhiyun
1247*4882a593Smuzhiyun dw_hdmi_disable(conn, hdmi, state);
1248*4882a593Smuzhiyun return 0;
1249*4882a593Smuzhiyun }
1250*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_mode_valid(struct dw_hdmi_qp * hdmi)1251*4882a593Smuzhiyun static void rockchip_dw_hdmi_qp_mode_valid(struct dw_hdmi_qp *hdmi)
1252*4882a593Smuzhiyun {
1253*4882a593Smuzhiyun struct hdmi_edid_data *edid_data = &hdmi->edid_data;
1254*4882a593Smuzhiyun int i;
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun for (i = 0; i < edid_data->modes; i++) {
1257*4882a593Smuzhiyun if (edid_data->mode_buf[i].invalid)
1258*4882a593Smuzhiyun continue;
1259*4882a593Smuzhiyun if (edid_data->mode_buf[i].clock <= 25000)
1260*4882a593Smuzhiyun edid_data->mode_buf[i].invalid = true;
1261*4882a593Smuzhiyun }
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun
_rockchip_dw_hdmi_qp_get_timing(struct rockchip_connector * conn,struct display_state * state,int edid_status)1264*4882a593Smuzhiyun static int _rockchip_dw_hdmi_qp_get_timing(struct rockchip_connector *conn,
1265*4882a593Smuzhiyun struct display_state *state, int edid_status)
1266*4882a593Smuzhiyun {
1267*4882a593Smuzhiyun int i;
1268*4882a593Smuzhiyun struct connector_state *conn_state = &state->conn_state;
1269*4882a593Smuzhiyun struct drm_display_mode *mode = &conn_state->mode;
1270*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = conn->data;
1271*4882a593Smuzhiyun struct edid *edid = (struct edid *)conn_state->edid;
1272*4882a593Smuzhiyun unsigned int bus_format;
1273*4882a593Smuzhiyun unsigned long enc_out_encoding;
1274*4882a593Smuzhiyun struct overscan *overscan = &conn_state->overscan;
1275*4882a593Smuzhiyun const u8 def_modes_vic[6] = {4, 16, 2, 17, 31, 19};
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun if (!hdmi)
1278*4882a593Smuzhiyun return -EFAULT;
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun if (!edid_status) {
1281*4882a593Smuzhiyun hdmi->sink_is_hdmi =
1282*4882a593Smuzhiyun drm_detect_hdmi_monitor(edid);
1283*4882a593Smuzhiyun hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
1284*4882a593Smuzhiyun edid_status = drm_add_edid_modes(&hdmi->edid_data, conn_state->edid);
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun if (edid_status < 0) {
1287*4882a593Smuzhiyun hdmi->sink_is_hdmi = true;
1288*4882a593Smuzhiyun hdmi->sink_has_audio = true;
1289*4882a593Smuzhiyun do_cea_modes(&hdmi->edid_data, def_modes_vic,
1290*4882a593Smuzhiyun sizeof(def_modes_vic));
1291*4882a593Smuzhiyun hdmi->edid_data.preferred_mode = &hdmi->edid_data.mode_buf[0];
1292*4882a593Smuzhiyun printf("failed to get edid\n");
1293*4882a593Smuzhiyun }
1294*4882a593Smuzhiyun drm_rk_filter_whitelist(&hdmi->edid_data);
1295*4882a593Smuzhiyun rockchip_dw_hdmi_qp_mode_valid(hdmi);
1296*4882a593Smuzhiyun drm_mode_max_resolution_filter(&hdmi->edid_data,
1297*4882a593Smuzhiyun &state->crtc_state.max_output);
1298*4882a593Smuzhiyun if (!drm_mode_prune_invalid(&hdmi->edid_data)) {
1299*4882a593Smuzhiyun printf("can't find valid hdmi mode\n");
1300*4882a593Smuzhiyun return -EINVAL;
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun for (i = 0; i < hdmi->edid_data.modes; i++)
1304*4882a593Smuzhiyun hdmi->edid_data.mode_buf[i].vrefresh =
1305*4882a593Smuzhiyun drm_mode_vrefresh(&hdmi->edid_data.mode_buf[i]);
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun drm_mode_sort(&hdmi->edid_data);
1308*4882a593Smuzhiyun dw_hdmi_qp_selete_output(&hdmi->edid_data, conn, &bus_format,
1309*4882a593Smuzhiyun overscan, hdmi->dev_type,
1310*4882a593Smuzhiyun hdmi->output_bus_format_rgb, hdmi->rk_hdmi,
1311*4882a593Smuzhiyun state);
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun *mode = *hdmi->edid_data.preferred_mode;
1314*4882a593Smuzhiyun hdmi->vic = drm_match_cea_mode(mode);
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun printf("mode:%dx%d bus_format:0x%x\n", mode->hdisplay, mode->vdisplay, bus_format);
1317*4882a593Smuzhiyun conn_state->bus_format = bus_format;
1318*4882a593Smuzhiyun hdmi->hdmi_data.enc_in_bus_format = bus_format;
1319*4882a593Smuzhiyun hdmi->hdmi_data.enc_out_bus_format = bus_format;
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun switch (bus_format) {
1322*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV10_1X20:
1323*4882a593Smuzhiyun conn_state->bus_format = MEDIA_BUS_FMT_YUYV10_1X20;
1324*4882a593Smuzhiyun hdmi->hdmi_data.enc_in_bus_format =
1325*4882a593Smuzhiyun MEDIA_BUS_FMT_YUYV10_1X20;
1326*4882a593Smuzhiyun conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422;
1327*4882a593Smuzhiyun break;
1328*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV8_1X16:
1329*4882a593Smuzhiyun conn_state->bus_format = MEDIA_BUS_FMT_YUYV8_1X16;
1330*4882a593Smuzhiyun hdmi->hdmi_data.enc_in_bus_format =
1331*4882a593Smuzhiyun MEDIA_BUS_FMT_YUYV8_1X16;
1332*4882a593Smuzhiyun conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422;
1333*4882a593Smuzhiyun break;
1334*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
1335*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
1336*4882a593Smuzhiyun conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420;
1337*4882a593Smuzhiyun break;
1338*4882a593Smuzhiyun }
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun if (hdmi->vic == 6 || hdmi->vic == 7 || hdmi->vic == 21 ||
1341*4882a593Smuzhiyun hdmi->vic == 22 || hdmi->vic == 2 || hdmi->vic == 3 ||
1342*4882a593Smuzhiyun hdmi->vic == 17 || hdmi->vic == 18)
1343*4882a593Smuzhiyun enc_out_encoding = V4L2_YCBCR_ENC_601;
1344*4882a593Smuzhiyun else
1345*4882a593Smuzhiyun enc_out_encoding = V4L2_YCBCR_ENC_709;
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun if (enc_out_encoding == V4L2_YCBCR_ENC_BT2020)
1348*4882a593Smuzhiyun conn_state->color_space = V4L2_COLORSPACE_BT2020;
1349*4882a593Smuzhiyun else if (bus_format == MEDIA_BUS_FMT_RGB888_1X24 ||
1350*4882a593Smuzhiyun bus_format == MEDIA_BUS_FMT_RGB101010_1X30)
1351*4882a593Smuzhiyun conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
1352*4882a593Smuzhiyun else if (enc_out_encoding == V4L2_YCBCR_ENC_709)
1353*4882a593Smuzhiyun conn_state->color_space = V4L2_COLORSPACE_REC709;
1354*4882a593Smuzhiyun else
1355*4882a593Smuzhiyun conn_state->color_space = V4L2_COLORSPACE_SMPTE170M;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun return 0;
1358*4882a593Smuzhiyun }
1359*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_get_timing(struct rockchip_connector * conn,struct display_state * state)1360*4882a593Smuzhiyun int rockchip_dw_hdmi_qp_get_timing(struct rockchip_connector *conn, struct display_state *state)
1361*4882a593Smuzhiyun {
1362*4882a593Smuzhiyun struct connector_state *conn_state = &state->conn_state;
1363*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = conn->data;
1364*4882a593Smuzhiyun int ret;
1365*4882a593Smuzhiyun
1366*4882a593Smuzhiyun ret = drm_do_get_edid(&hdmi->adap, conn_state->edid);
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun if (conn_state->secondary)
1369*4882a593Smuzhiyun _rockchip_dw_hdmi_qp_get_timing(conn_state->secondary, state, ret);
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun return _rockchip_dw_hdmi_qp_get_timing(conn, state, ret);
1372*4882a593Smuzhiyun }
1373*4882a593Smuzhiyun
1374*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_detect(struct rockchip_connector * conn,struct display_state * state)1375*4882a593Smuzhiyun int rockchip_dw_hdmi_qp_detect(struct rockchip_connector *conn, struct display_state *state)
1376*4882a593Smuzhiyun {
1377*4882a593Smuzhiyun int ret;
1378*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = conn->data;
1379*4882a593Smuzhiyun
1380*4882a593Smuzhiyun if (!hdmi)
1381*4882a593Smuzhiyun return -EFAULT;
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun ret = dw_hdmi_detect_hotplug(hdmi, state);
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun return ret;
1386*4882a593Smuzhiyun }
1387*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_get_edid(struct rockchip_connector * conn,struct display_state * state)1388*4882a593Smuzhiyun int rockchip_dw_hdmi_qp_get_edid(struct rockchip_connector *conn, struct display_state *state)
1389*4882a593Smuzhiyun {
1390*4882a593Smuzhiyun int ret;
1391*4882a593Smuzhiyun struct connector_state *conn_state = &state->conn_state;
1392*4882a593Smuzhiyun struct dw_hdmi_qp *hdmi = conn->data;
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun ret = drm_do_get_edid(&hdmi->adap, conn_state->edid);
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun return ret;
1397*4882a593Smuzhiyun }
1398