xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/bridge/adv7511/adv7533.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/of_graph.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "adv7511.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun static const struct reg_sequence adv7533_fixed_registers[] = {
11*4882a593Smuzhiyun 	{ 0x16, 0x20 },
12*4882a593Smuzhiyun 	{ 0x9a, 0xe0 },
13*4882a593Smuzhiyun 	{ 0xba, 0x70 },
14*4882a593Smuzhiyun 	{ 0xde, 0x82 },
15*4882a593Smuzhiyun 	{ 0xe4, 0x40 },
16*4882a593Smuzhiyun 	{ 0xe5, 0x80 },
17*4882a593Smuzhiyun };
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static const struct reg_sequence adv7533_cec_fixed_registers[] = {
20*4882a593Smuzhiyun 	{ 0x15, 0xd0 },
21*4882a593Smuzhiyun 	{ 0x17, 0xd0 },
22*4882a593Smuzhiyun 	{ 0x24, 0x20 },
23*4882a593Smuzhiyun 	{ 0x57, 0x11 },
24*4882a593Smuzhiyun 	{ 0x05, 0xc8 },
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun 
adv7511_dsi_config_timing_gen(struct adv7511 * adv)27*4882a593Smuzhiyun static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	struct mipi_dsi_device *dsi = adv->dsi;
30*4882a593Smuzhiyun 	struct drm_display_mode *mode = &adv->curr_mode;
31*4882a593Smuzhiyun 	unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
32*4882a593Smuzhiyun 	u8 clock_div_by_lanes[] = { 6, 4, 3 };	/* 2, 3, 4 lanes */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	hsw = mode->hsync_end - mode->hsync_start;
35*4882a593Smuzhiyun 	hfp = mode->hsync_start - mode->hdisplay;
36*4882a593Smuzhiyun 	hbp = mode->htotal - mode->hsync_end;
37*4882a593Smuzhiyun 	vsw = mode->vsync_end - mode->vsync_start;
38*4882a593Smuzhiyun 	vfp = mode->vsync_start - mode->vdisplay;
39*4882a593Smuzhiyun 	vbp = mode->vtotal - mode->vsync_end;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	/* set pixel clock divider mode */
42*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x16,
43*4882a593Smuzhiyun 		     clock_div_by_lanes[dsi->lanes - 2] << 3);
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	/* horizontal porch params */
46*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4);
47*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x29, (mode->htotal << 4) & 0xff);
48*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x2a, hsw >> 4);
49*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x2b, (hsw << 4) & 0xff);
50*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x2c, hfp >> 4);
51*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x2d, (hfp << 4) & 0xff);
52*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x2e, hbp >> 4);
53*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x2f, (hbp << 4) & 0xff);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* vertical porch params */
56*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x30, mode->vtotal >> 4);
57*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x31, (mode->vtotal << 4) & 0xff);
58*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x32, vsw >> 4);
59*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x33, (vsw << 4) & 0xff);
60*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x34, vfp >> 4);
61*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff);
62*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x36, vbp >> 4);
63*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
adv7533_dsi_power_on(struct adv7511 * adv)66*4882a593Smuzhiyun void adv7533_dsi_power_on(struct adv7511 *adv)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct mipi_dsi_device *dsi = adv->dsi;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	if (adv->use_timing_gen)
71*4882a593Smuzhiyun 		adv7511_dsi_config_timing_gen(adv);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	/* set number of dsi lanes */
74*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (adv->use_timing_gen) {
77*4882a593Smuzhiyun 		/* reset internal timing generator */
78*4882a593Smuzhiyun 		regmap_write(adv->regmap_cec, 0x27, 0xcb);
79*4882a593Smuzhiyun 		regmap_write(adv->regmap_cec, 0x27, 0x8b);
80*4882a593Smuzhiyun 		regmap_write(adv->regmap_cec, 0x27, 0xcb);
81*4882a593Smuzhiyun 	} else {
82*4882a593Smuzhiyun 		/* disable internal timing generator */
83*4882a593Smuzhiyun 		regmap_write(adv->regmap_cec, 0x27, 0x0b);
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	/* enable hdmi */
87*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x03, 0x89);
88*4882a593Smuzhiyun 	/* disable test mode */
89*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x55, 0x00);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,
92*4882a593Smuzhiyun 			      ARRAY_SIZE(adv7533_cec_fixed_registers));
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
adv7533_dsi_power_off(struct adv7511 * adv)95*4882a593Smuzhiyun void adv7533_dsi_power_off(struct adv7511 *adv)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	/* disable hdmi */
98*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x03, 0x0b);
99*4882a593Smuzhiyun 	/* disable internal timing generator */
100*4882a593Smuzhiyun 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
adv7533_mode_set(struct adv7511 * adv,const struct drm_display_mode * mode)103*4882a593Smuzhiyun void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct mipi_dsi_device *dsi = adv->dsi;
106*4882a593Smuzhiyun 	int lanes, ret;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	if (adv->num_dsi_lanes != 4)
109*4882a593Smuzhiyun 		return;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	if (mode->clock > 80000)
112*4882a593Smuzhiyun 		lanes = 4;
113*4882a593Smuzhiyun 	else
114*4882a593Smuzhiyun 		lanes = 3;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (lanes != dsi->lanes) {
117*4882a593Smuzhiyun 		mipi_dsi_detach(dsi);
118*4882a593Smuzhiyun 		dsi->lanes = lanes;
119*4882a593Smuzhiyun 		ret = mipi_dsi_attach(dsi);
120*4882a593Smuzhiyun 		if (ret)
121*4882a593Smuzhiyun 			dev_err(&dsi->dev, "failed to change host lanes\n");
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
adv7533_patch_registers(struct adv7511 * adv)125*4882a593Smuzhiyun int adv7533_patch_registers(struct adv7511 *adv)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	return regmap_register_patch(adv->regmap,
128*4882a593Smuzhiyun 				     adv7533_fixed_registers,
129*4882a593Smuzhiyun 				     ARRAY_SIZE(adv7533_fixed_registers));
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
adv7533_patch_cec_registers(struct adv7511 * adv)132*4882a593Smuzhiyun int adv7533_patch_cec_registers(struct adv7511 *adv)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	return regmap_register_patch(adv->regmap_cec,
135*4882a593Smuzhiyun 				    adv7533_cec_fixed_registers,
136*4882a593Smuzhiyun 				    ARRAY_SIZE(adv7533_cec_fixed_registers));
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
adv7533_attach_dsi(struct adv7511 * adv)139*4882a593Smuzhiyun int adv7533_attach_dsi(struct adv7511 *adv)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	struct device *dev = &adv->i2c_main->dev;
142*4882a593Smuzhiyun 	struct mipi_dsi_host *host;
143*4882a593Smuzhiyun 	struct mipi_dsi_device *dsi;
144*4882a593Smuzhiyun 	int ret = 0;
145*4882a593Smuzhiyun 	const struct mipi_dsi_device_info info = { .type = "adv7533",
146*4882a593Smuzhiyun 						   .channel = 0,
147*4882a593Smuzhiyun 						   .node = NULL,
148*4882a593Smuzhiyun 						 };
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	host = of_find_mipi_dsi_host_by_node(adv->host_node);
151*4882a593Smuzhiyun 	if (!host) {
152*4882a593Smuzhiyun 		dev_err(dev, "failed to find dsi host\n");
153*4882a593Smuzhiyun 		return -EPROBE_DEFER;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	dsi = mipi_dsi_device_register_full(host, &info);
157*4882a593Smuzhiyun 	if (IS_ERR(dsi)) {
158*4882a593Smuzhiyun 		dev_err(dev, "failed to create dsi device\n");
159*4882a593Smuzhiyun 		ret = PTR_ERR(dsi);
160*4882a593Smuzhiyun 		goto err_dsi_device;
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	adv->dsi = dsi;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	dsi->lanes = adv->num_dsi_lanes;
166*4882a593Smuzhiyun 	dsi->format = MIPI_DSI_FMT_RGB888;
167*4882a593Smuzhiyun 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
168*4882a593Smuzhiyun 			  MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	ret = mipi_dsi_attach(dsi);
171*4882a593Smuzhiyun 	if (ret < 0) {
172*4882a593Smuzhiyun 		dev_err(dev, "failed to attach dsi to host\n");
173*4882a593Smuzhiyun 		goto err_dsi_attach;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	return 0;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun err_dsi_attach:
179*4882a593Smuzhiyun 	mipi_dsi_device_unregister(dsi);
180*4882a593Smuzhiyun err_dsi_device:
181*4882a593Smuzhiyun 	return ret;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
adv7533_detach_dsi(struct adv7511 * adv)184*4882a593Smuzhiyun void adv7533_detach_dsi(struct adv7511 *adv)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	mipi_dsi_detach(adv->dsi);
187*4882a593Smuzhiyun 	mipi_dsi_device_unregister(adv->dsi);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
adv7533_parse_dt(struct device_node * np,struct adv7511 * adv)190*4882a593Smuzhiyun int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	u32 num_lanes;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (num_lanes < 1 || num_lanes > 4)
197*4882a593Smuzhiyun 		return -EINVAL;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	adv->num_dsi_lanes = num_lanes;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	adv->host_node = of_graph_get_remote_node(np, 0, 0);
202*4882a593Smuzhiyun 	if (!adv->host_node)
203*4882a593Smuzhiyun 		return -ENODEV;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	of_node_put(adv->host_node);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	adv->use_timing_gen = !of_property_read_bool(np,
208*4882a593Smuzhiyun 						"adi,disable-timing-generator");
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* TODO: Check if these need to be parsed by DT or not */
211*4882a593Smuzhiyun 	adv->rgb = true;
212*4882a593Smuzhiyun 	adv->embedded_sync = false;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	return 0;
215*4882a593Smuzhiyun }
216