xref: /rk3399_rockchip-uboot/drivers/video/drm/rk628/rk628_lvds.c (revision ab3bc87339b1566ceabcfb54995e11928492c356)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
4  *
5  * Author: Guochun Huang <hero.huang@rock-chips.com>
6  */
7 
8 #include "rk628.h"
9 #include "rk628_lvds.h"
10 #include "rk628_combtxphy.h"
11 #include "panel.h"
12 
lvds_write(struct rk628 * rk628,u32 reg,u32 val)13 static inline void lvds_write(struct rk628 *rk628, u32 reg, u32 val)
14 {
15 	rk628_i2c_write(rk628, reg, val);
16 }
17 
lvds_update_bits(struct rk628 * rk628,u32 reg,u32 mask,u32 val)18 static inline void lvds_update_bits(struct rk628 *rk628, u32 reg,
19 				    u32 mask, u32 val)
20 {
21 	rk628_i2c_update_bits(rk628, reg, mask, val);
22 }
23 
rk628_lvds_parse(struct rk628 * rk628,ofnode lvds_np)24 int rk628_lvds_parse(struct rk628 *rk628, ofnode lvds_np)
25 {
26 	const char *string = NULL;
27 	int ret;
28 
29 	if (!ofnode_valid(lvds_np))
30 		return -EINVAL;
31 
32 	string = ofnode_read_string(lvds_np, "bus-format");
33 	if (!strcmp(string, "jeida_24"))
34 		rk628->lvds.format = LVDS_FORMAT_JEIDA_24BIT;
35 	else if (!strcmp(string, "jeida_18"))
36 		rk628->lvds.format = LVDS_FORMAT_JEIDA_18BIT;
37 	else if (!strcmp(string, "vesa_18"))
38 		rk628->lvds.format = LVDS_FORMAT_VESA_18BIT;
39 	else
40 		rk628->lvds.format = LVDS_FORMAT_VESA_24BIT;
41 
42 	string = ofnode_read_string(lvds_np, "link-type");
43 	if (!strcmp(string, "dual_link_odd_even_pixels"))
44 		rk628->lvds.link_type = LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
45 	else if (!strcmp(string, "dual_link_even_odd_pixels"))
46 		rk628->lvds.link_type = LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
47 	else if (!strcmp(string, "dual_link_left_right_pixels"))
48 		rk628->lvds.link_type = LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS;
49 	else if (!strcmp(string, "dual_link_right_left_pixels"))
50 		rk628->lvds.link_type = LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS;
51 	else
52 		rk628->lvds.link_type = LVDS_SINGLE_LINK;
53 
54 	ret = rk628_panel_info_get(rk628, lvds_np);
55 	if (ret)
56 		return ret;
57 
58 	return 0;
59 }
60 
rk628_lvds_enable(struct rk628 * rk628)61 void rk628_lvds_enable(struct rk628 *rk628)
62 {
63 	enum lvds_link_type link_type = rk628->lvds.link_type;
64 	enum lvds_format format = rk628->lvds.format;
65 	const struct drm_display_mode *mode = &rk628->dst_mode;
66 	u32 val, mask, bus_width;
67 
68 	mask = SW_OUTPUT_MODE_MASK;
69 	val = SW_OUTPUT_MODE(OUTPUT_MODE_LVDS);
70 
71 	if (rk628->version == RK628F_VERSION) {
72 		mask = SW_OUTPUT_COMBTX_MODE_MASK;
73 		val = SW_OUTPUT_COMBTX_MODE(OUTPUT_MODE_LVDS);
74 	}
75 
76 	lvds_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
77 
78 	switch (link_type) {
79 	case LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
80 		val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(0) |
81 		      SW_LVDS_CON_DUAL_SEL(0);
82 		bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
83 		break;
84 	case LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
85 		val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(1) |
86 		      SW_LVDS_CON_DUAL_SEL(0);
87 		bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
88 		break;
89 	case LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS:
90 		val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(0) |
91 		      SW_LVDS_CON_DUAL_SEL(1);
92 		lvds_update_bits(rk628, GRF_POST_PROC_CON,
93 				 SW_SPLIT_EN, SW_SPLIT_EN);
94 		bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
95 		break;
96 	case LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS:
97 		val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(1) |
98 		      SW_LVDS_CON_DUAL_SEL(1);
99 		lvds_update_bits(rk628, GRF_POST_PROC_CON,
100 				 SW_SPLIT_EN, SW_SPLIT_EN);
101 		bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
102 		break;
103 	case LVDS_SINGLE_LINK:
104 	default:
105 		val = SW_LVDS_CON_CHASEL(0) | SW_LVDS_CON_STARTSEL(0) |
106 		      SW_LVDS_CON_DUAL_SEL(0);
107 		bus_width = COMBTXPHY_MODULEA_EN;
108 		break;
109 	}
110 
111 	val |= SW_LVDS_CON_SELECT(format) | SW_LVDS_CON_MSBSEL(0) |
112 	       SW_LVDS_CON_CLKINV(0);
113 	lvds_write(rk628, GRF_LVDS_TX_CON, val);
114 
115 	bus_width |= (mode->clock / 1000) << 8;
116 	rk628_combtxphy_set_bus_width(rk628, bus_width);
117 	rk628_combtxphy_set_mode(rk628, PHY_MODE_VIDEO_LVDS);
118 	rk628_combtxphy_power_on(rk628);
119 	rk628_panel_prepare(rk628);
120 	rk628_panel_enable(rk628);
121 }
122 
rk628_lvds_disable(struct rk628 * rk628)123 void rk628_lvds_disable(struct rk628 *rk628)
124 {
125 	rk628_panel_disable(rk628);
126 	rk628_panel_unprepare(rk628);
127 	rk628_combtxphy_power_off(rk628);
128 }
129