1186f8572SMark Yao /*
2186f8572SMark Yao * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3186f8572SMark Yao *
4186f8572SMark Yao * SPDX-License-Identifier: GPL-2.0+
5186f8572SMark Yao */
6186f8572SMark Yao
7186f8572SMark Yao #include <config.h>
8186f8572SMark Yao #include <common.h>
9186f8572SMark Yao #include <errno.h>
10186f8572SMark Yao #include <dm/device.h>
119aa59efbSKever Yang #include <dm/read.h>
129aa59efbSKever Yang #include <dm/ofnode.h>
13cb17ca6cSSandy Huang #include <dm/of_access.h>
14186f8572SMark Yao #include <syscon.h>
15b69d3ed4SWyon Bi #include <regmap.h>
16b69d3ed4SWyon Bi #include <dm/device.h>
17b69d3ed4SWyon Bi #include <dm/read.h>
18b69d3ed4SWyon Bi #include <linux/media-bus-format.h>
19186f8572SMark Yao
20186f8572SMark Yao #include "rockchip_display.h"
21186f8572SMark Yao #include "rockchip_connector.h"
22b69d3ed4SWyon Bi #include "rockchip_phy.h"
231a8d717cSWyon Bi #include "rockchip_panel.h"
24dcebcd68SChaoyi Chen #include "drm_of.h"
251953e619SWyon Bi
261953e619SWyon Bi #define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16))
27186f8572SMark Yao
28b69d3ed4SWyon Bi #define PX30_GRF_PD_VO_CON1 0x0438
29b69d3ed4SWyon Bi #define PX30_LVDS_SELECT(x) HIWORD_UPDATE(x, 14, 13)
30b69d3ed4SWyon Bi #define PX30_LVDS_MODE_EN(x) HIWORD_UPDATE(x, 12, 12)
31b69d3ed4SWyon Bi #define PX30_LVDS_MSBSEL(x) HIWORD_UPDATE(x, 11, 11)
3231018a86SWyon Bi #define PX30_LVDS_P2S_EN(x) HIWORD_UPDATE(x, 6, 6)
33b69d3ed4SWyon Bi #define PX30_LVDS_VOP_SEL(x) HIWORD_UPDATE(x, 1, 1)
34b69d3ed4SWyon Bi
35b69d3ed4SWyon Bi #define RK3126_GRF_LVDS_CON0 0x0150
36b69d3ed4SWyon Bi #define RK3126_LVDS_P2S_EN(x) HIWORD_UPDATE(x, 9, 9)
37b69d3ed4SWyon Bi #define RK3126_LVDS_MODE_EN(x) HIWORD_UPDATE(x, 6, 6)
38b69d3ed4SWyon Bi #define RK3126_LVDS_MSBSEL(x) HIWORD_UPDATE(x, 3, 3)
39b69d3ed4SWyon Bi #define RK3126_LVDS_SELECT(x) HIWORD_UPDATE(x, 2, 1)
40b69d3ed4SWyon Bi
41b69d3ed4SWyon Bi #define RK3288_GRF_SOC_CON6 0x025c
42b69d3ed4SWyon Bi #define RK3288_LVDS_LCDC_SEL(x) HIWORD_UPDATE(x, 3, 3)
43b69d3ed4SWyon Bi #define RK3288_GRF_SOC_CON7 0x0260
44b69d3ed4SWyon Bi #define RK3288_LVDS_PWRDWN(x) HIWORD_UPDATE(x, 15, 15)
45b69d3ed4SWyon Bi #define RK3288_LVDS_CON_ENABLE_2(x) HIWORD_UPDATE(x, 12, 12)
46b69d3ed4SWyon Bi #define RK3288_LVDS_CON_ENABLE_1(x) HIWORD_UPDATE(x, 11, 11)
47b69d3ed4SWyon Bi #define RK3288_LVDS_CON_DEN_POL(x) HIWORD_UPDATE(x, 10, 10)
48b69d3ed4SWyon Bi #define RK3288_LVDS_CON_HS_POL(x) HIWORD_UPDATE(x, 9, 9)
49b69d3ed4SWyon Bi #define RK3288_LVDS_CON_CLKINV(x) HIWORD_UPDATE(x, 8, 8)
50b69d3ed4SWyon Bi #define RK3288_LVDS_CON_STARTPHASE(x) HIWORD_UPDATE(x, 7, 7)
51b69d3ed4SWyon Bi #define RK3288_LVDS_CON_TTL_EN(x) HIWORD_UPDATE(x, 6, 6)
52b69d3ed4SWyon Bi #define RK3288_LVDS_CON_STARTSEL(x) HIWORD_UPDATE(x, 5, 5)
53b69d3ed4SWyon Bi #define RK3288_LVDS_CON_CHASEL(x) HIWORD_UPDATE(x, 4, 4)
54b69d3ed4SWyon Bi #define RK3288_LVDS_CON_MSBSEL(x) HIWORD_UPDATE(x, 3, 3)
55b69d3ed4SWyon Bi #define RK3288_LVDS_CON_SELECT(x) HIWORD_UPDATE(x, 2, 0)
56b69d3ed4SWyon Bi
57b69d3ed4SWyon Bi #define RK3368_GRF_SOC_CON7 0x041c
58b69d3ed4SWyon Bi #define RK3368_LVDS_SELECT(x) HIWORD_UPDATE(x, 14, 13)
59b69d3ed4SWyon Bi #define RK3368_LVDS_MODE_EN(x) HIWORD_UPDATE(x, 12, 12)
60b69d3ed4SWyon Bi #define RK3368_LVDS_MSBSEL(x) HIWORD_UPDATE(x, 11, 11)
61b69d3ed4SWyon Bi #define RK3368_LVDS_P2S_EN(x) HIWORD_UPDATE(x, 6, 6)
62b69d3ed4SWyon Bi
63cc341c3bSZhang Yubing #define RK3562_GRF_VO_CON0 0x05d0
64cc341c3bSZhang Yubing #define RK3562_GRF_VO_CON1 0x05d4
65cc341c3bSZhang Yubing
66aeb5dd22SSandy Huang #define RK3568_GRF_VO_CON0 0x0360
67aeb5dd22SSandy Huang #define RK3568_LVDS1_SELECT(x) HIWORD_UPDATE(x, 13, 12)
68aeb5dd22SSandy Huang #define RK3568_LVDS1_MSBSEL(x) HIWORD_UPDATE(x, 11, 11)
69aeb5dd22SSandy Huang #define RK3568_LVDS0_SELECT(x) HIWORD_UPDATE(x, 5, 4)
70aeb5dd22SSandy Huang #define RK3568_LVDS0_MSBSEL(x) HIWORD_UPDATE(x, 3, 3)
71aeb5dd22SSandy Huang #define RK3568_GRF_VO_CON2 0x0368
72aeb5dd22SSandy Huang #define RK3568_LVDS0_DCLK_INV_SEL(x) HIWORD_UPDATE(x, 9, 9)
73aeb5dd22SSandy Huang #define RK3568_LVDS0_DCLK_DIV2_SEL(x) HIWORD_UPDATE(x, 8, 8)
74aeb5dd22SSandy Huang #define RK3568_LVDS0_MODE_EN(x) HIWORD_UPDATE(x, 1, 1)
75aeb5dd22SSandy Huang #define RK3568_LVDS0_P2S_EN(x) HIWORD_UPDATE(x, 0, 0)
76aeb5dd22SSandy Huang #define RK3568_GRF_VO_CON3 0x036c
77aeb5dd22SSandy Huang #define RK3568_LVDS1_DCLK_INV_SEL(x) HIWORD_UPDATE(x, 9, 9)
78aeb5dd22SSandy Huang #define RK3568_LVDS1_DCLK_DIV2_SEL(x) HIWORD_UPDATE(x, 8, 8)
79aeb5dd22SSandy Huang #define RK3568_LVDS1_MODE_EN(x) HIWORD_UPDATE(x, 1, 1)
80aeb5dd22SSandy Huang #define RK3568_LVDS1_P2S_EN(x) HIWORD_UPDATE(x, 0, 0)
81aeb5dd22SSandy Huang
82b69d3ed4SWyon Bi enum lvds_format {
83b69d3ed4SWyon Bi LVDS_8BIT_MODE_FORMAT_1,
84b69d3ed4SWyon Bi LVDS_8BIT_MODE_FORMAT_2,
85b69d3ed4SWyon Bi LVDS_8BIT_MODE_FORMAT_3,
86b69d3ed4SWyon Bi LVDS_6BIT_MODE,
87e2721f29SGuochun Huang LVDS_10BIT_MODE_FORMAT_1,
88e2721f29SGuochun Huang LVDS_10BIT_MODE_FORMAT_2,
89186f8572SMark Yao };
90186f8572SMark Yao
91b69d3ed4SWyon Bi struct rockchip_lvds;
92b69d3ed4SWyon Bi
93b69d3ed4SWyon Bi struct rockchip_lvds_funcs {
94dcebcd68SChaoyi Chen int (*probe)(struct rockchip_lvds *lvds);
95b69d3ed4SWyon Bi void (*enable)(struct rockchip_lvds *lvds, int pipe);
96b69d3ed4SWyon Bi void (*disable)(struct rockchip_lvds *lvds);
97186f8572SMark Yao };
98186f8572SMark Yao
99b69d3ed4SWyon Bi struct rockchip_lvds {
1000594ce39SZhang Yubing struct rockchip_connector connector;
101cb17ca6cSSandy Huang int id;
102b69d3ed4SWyon Bi struct udevice *dev;
103b69d3ed4SWyon Bi struct regmap *grf;
104b69d3ed4SWyon Bi struct rockchip_phy *phy;
105b69d3ed4SWyon Bi const struct drm_display_mode *mode;
106b69d3ed4SWyon Bi const struct rockchip_lvds_funcs *funcs;
107b69d3ed4SWyon Bi enum lvds_format format;
108b69d3ed4SWyon Bi bool data_swap;
109b69d3ed4SWyon Bi bool dual_channel;
110dcebcd68SChaoyi Chen enum drm_lvds_dual_link_pixels pixel_order;
111186f8572SMark Yao };
112186f8572SMark Yao
rockchip_lvds_connector_init(struct rockchip_connector * conn,struct display_state * state)1130594ce39SZhang Yubing static int rockchip_lvds_connector_init(struct rockchip_connector *conn,
1140594ce39SZhang Yubing struct display_state *state)
115186f8572SMark Yao {
1160594ce39SZhang Yubing struct rockchip_lvds *lvds = dev_get_priv(conn->dev);
117dcebcd68SChaoyi Chen struct rockchip_lvds *primary_lvds = NULL;
118186f8572SMark Yao struct connector_state *conn_state = &state->conn_state;
1190594ce39SZhang Yubing struct rockchip_panel *panel = conn->panel;
120186f8572SMark Yao
121b69d3ed4SWyon Bi lvds->mode = &conn_state->mode;
1220594ce39SZhang Yubing lvds->phy = conn->phy;
123cb17ca6cSSandy Huang conn_state->disp_info = rockchip_get_disp_info(conn_state->type, lvds->id);
124186f8572SMark Yao
125dcebcd68SChaoyi Chen if (conn_state->secondary)
126dcebcd68SChaoyi Chen primary_lvds = dev_get_priv(conn_state->connector->dev);
127dcebcd68SChaoyi Chen
128b69d3ed4SWyon Bi switch (panel->bus_format) {
1294888f8a4SWyon Bi case MEDIA_BUS_FMT_RGB666_1X7X3_JEIDA: /* jeida-18 */
130b69d3ed4SWyon Bi lvds->format = LVDS_6BIT_MODE;
131b69d3ed4SWyon Bi break;
132b69d3ed4SWyon Bi case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: /* jeida-24 */
133b69d3ed4SWyon Bi lvds->format = LVDS_8BIT_MODE_FORMAT_2;
134b69d3ed4SWyon Bi break;
135e2721f29SGuochun Huang case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA: /* jeida-30 */
136e2721f29SGuochun Huang lvds->format = LVDS_10BIT_MODE_FORMAT_1;
1374888f8a4SWyon Bi case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: /* vesa-18 */
1384888f8a4SWyon Bi lvds->format = LVDS_8BIT_MODE_FORMAT_3;
1394888f8a4SWyon Bi break;
140e2721f29SGuochun Huang case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG: /* vesa-30 */
141e2721f29SGuochun Huang lvds->format = LVDS_10BIT_MODE_FORMAT_2;
142e2721f29SGuochun Huang break;
143b69d3ed4SWyon Bi case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: /* vesa-24 */
144b69d3ed4SWyon Bi default:
145b69d3ed4SWyon Bi lvds->format = LVDS_8BIT_MODE_FORMAT_1;
146b69d3ed4SWyon Bi break;
147186f8572SMark Yao }
148186f8572SMark Yao
149dcebcd68SChaoyi Chen conn_state->bus_format = panel->bus_format;
150186f8572SMark Yao conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
151e2721f29SGuochun Huang
152e2721f29SGuochun Huang if ((lvds->format == LVDS_10BIT_MODE_FORMAT_1) ||
153e2721f29SGuochun Huang (lvds->format == LVDS_10BIT_MODE_FORMAT_2))
154e2721f29SGuochun Huang conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
155e2721f29SGuochun Huang
156*df0a5c43SDamon Ding conn_state->color_encoding = DRM_COLOR_YCBCR_BT709;
157*df0a5c43SDamon Ding conn_state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
158dcebcd68SChaoyi Chen if (primary_lvds) {
159dcebcd68SChaoyi Chen conn_state->output_flags = 0;
160dcebcd68SChaoyi Chen conn_state->output_if = 0;
161dcebcd68SChaoyi Chen
162dcebcd68SChaoyi Chen switch (primary_lvds->pixel_order) {
163dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
164dcebcd68SChaoyi Chen conn_state->output_flags |=
165dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE;
166dcebcd68SChaoyi Chen conn_state->output_if |=
167dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
168dcebcd68SChaoyi Chen break;
169dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
170dcebcd68SChaoyi Chen conn_state->output_flags |=
171dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE;
172dcebcd68SChaoyi Chen conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
173dcebcd68SChaoyi Chen conn_state->output_if |=
174dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
175dcebcd68SChaoyi Chen break;
176dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS:
177dcebcd68SChaoyi Chen conn_state->output_flags |=
178dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE;
179dcebcd68SChaoyi Chen conn_state->output_if |=
180dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
181dcebcd68SChaoyi Chen break;
182dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS:
183dcebcd68SChaoyi Chen conn_state->output_flags |=
184dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE;
185dcebcd68SChaoyi Chen conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
186dcebcd68SChaoyi Chen conn_state->output_if |=
187dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
188dcebcd68SChaoyi Chen break;
189dcebcd68SChaoyi Chen default:
190dcebcd68SChaoyi Chen break;
191dcebcd68SChaoyi Chen }
192dcebcd68SChaoyi Chen }
193dcebcd68SChaoyi Chen
194dcebcd68SChaoyi Chen if (lvds->id)
195dcebcd68SChaoyi Chen conn_state->output_if |= VOP_OUTPUT_IF_LVDS1;
196dcebcd68SChaoyi Chen else
197dcebcd68SChaoyi Chen conn_state->output_if |= VOP_OUTPUT_IF_LVDS0;
198186f8572SMark Yao
199186f8572SMark Yao return 0;
200186f8572SMark Yao }
201186f8572SMark Yao
rockchip_lvds_connector_enable(struct rockchip_connector * conn,struct display_state * state)2020594ce39SZhang Yubing static int rockchip_lvds_connector_enable(struct rockchip_connector *conn,
2030594ce39SZhang Yubing struct display_state *state)
204186f8572SMark Yao {
2050594ce39SZhang Yubing struct rockchip_lvds *lvds = dev_get_priv(conn->dev);
206b69d3ed4SWyon Bi struct crtc_state *crtc_state = &state->crtc_state;
207b69d3ed4SWyon Bi int pipe = crtc_state->crtc_id;
208b69d3ed4SWyon Bi int ret;
209186f8572SMark Yao
210b69d3ed4SWyon Bi if (lvds->funcs->enable)
211b69d3ed4SWyon Bi lvds->funcs->enable(lvds, pipe);
212b69d3ed4SWyon Bi
2139e3ffb10SGuochun Huang ret = rockchip_phy_set_mode(lvds->phy, PHY_MODE_VIDEO_LVDS);
214b69d3ed4SWyon Bi if (ret) {
215b69d3ed4SWyon Bi dev_err(lvds->dev, "failed to set phy mode: %d\n", ret);
216b69d3ed4SWyon Bi return ret;
217186f8572SMark Yao }
218186f8572SMark Yao
219b69d3ed4SWyon Bi rockchip_phy_power_on(lvds->phy);
220186f8572SMark Yao
221186f8572SMark Yao return 0;
222186f8572SMark Yao }
223186f8572SMark Yao
rockchip_lvds_connector_disable(struct rockchip_connector * conn,struct display_state * state)2240594ce39SZhang Yubing static int rockchip_lvds_connector_disable(struct rockchip_connector *conn,
2250594ce39SZhang Yubing struct display_state *state)
226186f8572SMark Yao {
2270594ce39SZhang Yubing struct rockchip_lvds *lvds = dev_get_priv(conn->dev);
228b69d3ed4SWyon Bi
229b69d3ed4SWyon Bi rockchip_phy_power_off(lvds->phy);
230b69d3ed4SWyon Bi
231b69d3ed4SWyon Bi if (lvds->funcs->disable)
232b69d3ed4SWyon Bi lvds->funcs->disable(lvds);
233b69d3ed4SWyon Bi
234b69d3ed4SWyon Bi return 0;
235b69d3ed4SWyon Bi }
236b69d3ed4SWyon Bi
237b69d3ed4SWyon Bi static const struct rockchip_connector_funcs rockchip_lvds_connector_funcs = {
238b69d3ed4SWyon Bi .init = rockchip_lvds_connector_init,
239b69d3ed4SWyon Bi .enable = rockchip_lvds_connector_enable,
240b69d3ed4SWyon Bi .disable = rockchip_lvds_connector_disable,
241b69d3ed4SWyon Bi };
242b69d3ed4SWyon Bi
rockchip_lvds_probe(struct udevice * dev)243b69d3ed4SWyon Bi static int rockchip_lvds_probe(struct udevice *dev)
244b69d3ed4SWyon Bi {
245b69d3ed4SWyon Bi struct rockchip_lvds *lvds = dev_get_priv(dev);
246b69d3ed4SWyon Bi
247b69d3ed4SWyon Bi lvds->dev = dev;
2480594ce39SZhang Yubing lvds->funcs = (const struct rockchip_lvds_funcs *)dev_get_driver_data(dev);
249b69d3ed4SWyon Bi lvds->grf = syscon_get_regmap(dev_get_parent(dev));
250b69d3ed4SWyon Bi lvds->dual_channel = dev_read_bool(dev, "dual-channel");
251b69d3ed4SWyon Bi lvds->data_swap = dev_read_bool(dev, "rockchip,data-swap");
252cb17ca6cSSandy Huang lvds->id = of_alias_get_id(ofnode_to_np(dev->node), "lvds");
253cb17ca6cSSandy Huang if (lvds->id < 0)
254cb17ca6cSSandy Huang lvds->id = 0;
255b69d3ed4SWyon Bi
256dcebcd68SChaoyi Chen lvds->pixel_order = -1;
257dcebcd68SChaoyi Chen if (lvds->funcs->probe)
258dcebcd68SChaoyi Chen lvds->funcs->probe(lvds);
259dcebcd68SChaoyi Chen
2600594ce39SZhang Yubing rockchip_connector_bind(&lvds->connector, dev, lvds->id, &rockchip_lvds_connector_funcs,
2610594ce39SZhang Yubing NULL, DRM_MODE_CONNECTOR_LVDS);
2620594ce39SZhang Yubing
263b69d3ed4SWyon Bi return 0;
264b69d3ed4SWyon Bi }
265b69d3ed4SWyon Bi
px30_lvds_enable(struct rockchip_lvds * lvds,int pipe)266b69d3ed4SWyon Bi static void px30_lvds_enable(struct rockchip_lvds *lvds, int pipe)
267b69d3ed4SWyon Bi {
268b69d3ed4SWyon Bi regmap_write(lvds->grf, PX30_GRF_PD_VO_CON1,
269b69d3ed4SWyon Bi PX30_LVDS_SELECT(lvds->format) |
270b69d3ed4SWyon Bi PX30_LVDS_MODE_EN(1) | PX30_LVDS_MSBSEL(1) |
271b69d3ed4SWyon Bi PX30_LVDS_P2S_EN(1) | PX30_LVDS_VOP_SEL(pipe));
272b69d3ed4SWyon Bi }
273b69d3ed4SWyon Bi
px30_lvds_disable(struct rockchip_lvds * lvds)274b69d3ed4SWyon Bi static void px30_lvds_disable(struct rockchip_lvds *lvds)
275b69d3ed4SWyon Bi {
276b69d3ed4SWyon Bi regmap_write(lvds->grf, PX30_GRF_PD_VO_CON1,
277b69d3ed4SWyon Bi PX30_LVDS_MODE_EN(0) | PX30_LVDS_P2S_EN(0));
278b69d3ed4SWyon Bi }
279b69d3ed4SWyon Bi
280b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs px30_lvds_funcs = {
281b69d3ed4SWyon Bi .enable = px30_lvds_enable,
282b69d3ed4SWyon Bi .disable = px30_lvds_disable,
283b69d3ed4SWyon Bi };
284b69d3ed4SWyon Bi
rk3126_lvds_enable(struct rockchip_lvds * lvds,int pipe)285b69d3ed4SWyon Bi static void rk3126_lvds_enable(struct rockchip_lvds *lvds, int pipe)
286b69d3ed4SWyon Bi {
287b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3126_GRF_LVDS_CON0,
288b69d3ed4SWyon Bi RK3126_LVDS_P2S_EN(1) | RK3126_LVDS_MODE_EN(1) |
289b69d3ed4SWyon Bi RK3126_LVDS_MSBSEL(1) | RK3126_LVDS_SELECT(lvds->format));
290b69d3ed4SWyon Bi }
291b69d3ed4SWyon Bi
rk3126_lvds_disable(struct rockchip_lvds * lvds)292b69d3ed4SWyon Bi static void rk3126_lvds_disable(struct rockchip_lvds *lvds)
293b69d3ed4SWyon Bi {
294b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3126_GRF_LVDS_CON0,
295b69d3ed4SWyon Bi RK3126_LVDS_P2S_EN(0) | RK3126_LVDS_MODE_EN(0));
296b69d3ed4SWyon Bi }
297b69d3ed4SWyon Bi
298b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs rk3126_lvds_funcs = {
299b69d3ed4SWyon Bi .enable = rk3126_lvds_enable,
300b69d3ed4SWyon Bi .disable = rk3126_lvds_disable,
301b69d3ed4SWyon Bi };
302b69d3ed4SWyon Bi
rk3288_lvds_enable(struct rockchip_lvds * lvds,int pipe)303b69d3ed4SWyon Bi static void rk3288_lvds_enable(struct rockchip_lvds *lvds, int pipe)
304b69d3ed4SWyon Bi {
305b69d3ed4SWyon Bi const struct drm_display_mode *mode = lvds->mode;
306186f8572SMark Yao u32 val;
307186f8572SMark Yao
308b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3288_GRF_SOC_CON6,
309b69d3ed4SWyon Bi RK3288_LVDS_LCDC_SEL(pipe));
310b69d3ed4SWyon Bi
311b69d3ed4SWyon Bi val = RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_CLKINV(0) |
312b69d3ed4SWyon Bi RK3288_LVDS_CON_CHASEL(lvds->dual_channel) |
313b69d3ed4SWyon Bi RK3288_LVDS_CON_SELECT(lvds->format);
314b69d3ed4SWyon Bi
315b69d3ed4SWyon Bi if (lvds->dual_channel) {
316b69d3ed4SWyon Bi u32 h_bp = mode->htotal - mode->hsync_start;
317b69d3ed4SWyon Bi
318b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_ENABLE_2(1) |
319b69d3ed4SWyon Bi RK3288_LVDS_CON_ENABLE_1(1) |
320b69d3ed4SWyon Bi RK3288_LVDS_CON_STARTSEL(lvds->data_swap);
321b69d3ed4SWyon Bi
322b69d3ed4SWyon Bi if (h_bp % 2)
323b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_STARTPHASE(1);
324186f8572SMark Yao else
325b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_STARTPHASE(0);
326186f8572SMark Yao } else {
327b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_ENABLE_2(0) |
328b69d3ed4SWyon Bi RK3288_LVDS_CON_ENABLE_1(1);
329186f8572SMark Yao }
330186f8572SMark Yao
331b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3288_GRF_SOC_CON7, val);
332b69d3ed4SWyon Bi
333b69d3ed4SWyon Bi rockchip_phy_set_bus_width(lvds->phy, lvds->dual_channel ? 2 : 1);
334186f8572SMark Yao }
335186f8572SMark Yao
rk3288_lvds_disable(struct rockchip_lvds * lvds)336b69d3ed4SWyon Bi static void rk3288_lvds_disable(struct rockchip_lvds *lvds)
337186f8572SMark Yao {
338b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3288_GRF_SOC_CON7, RK3288_LVDS_PWRDWN(1));
339186f8572SMark Yao }
340186f8572SMark Yao
341b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs rk3288_lvds_funcs = {
342b69d3ed4SWyon Bi .enable = rk3288_lvds_enable,
343b69d3ed4SWyon Bi .disable = rk3288_lvds_disable,
344186f8572SMark Yao };
345186f8572SMark Yao
rk3368_lvds_enable(struct rockchip_lvds * lvds,int pipe)346b69d3ed4SWyon Bi static void rk3368_lvds_enable(struct rockchip_lvds *lvds, int pipe)
347b69d3ed4SWyon Bi {
348b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3368_GRF_SOC_CON7,
349b69d3ed4SWyon Bi RK3368_LVDS_SELECT(lvds->format) |
350b69d3ed4SWyon Bi RK3368_LVDS_MODE_EN(1) | RK3368_LVDS_MSBSEL(1) |
351b69d3ed4SWyon Bi RK3368_LVDS_P2S_EN(1));
352b69d3ed4SWyon Bi }
353b69d3ed4SWyon Bi
rk3368_lvds_disable(struct rockchip_lvds * lvds)354b69d3ed4SWyon Bi static void rk3368_lvds_disable(struct rockchip_lvds *lvds)
355b69d3ed4SWyon Bi {
356b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3368_GRF_SOC_CON7,
357b69d3ed4SWyon Bi RK3368_LVDS_MODE_EN(0) | RK3368_LVDS_P2S_EN(0));
358b69d3ed4SWyon Bi }
359b69d3ed4SWyon Bi
360b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs rk3368_lvds_funcs = {
361b69d3ed4SWyon Bi .enable = rk3368_lvds_enable,
362b69d3ed4SWyon Bi .disable = rk3368_lvds_disable,
36330d6d433SWyon Bi };
36430d6d433SWyon Bi
rk3562_lvds_enable(struct rockchip_lvds * lvds,int pipe)365cc341c3bSZhang Yubing static void rk3562_lvds_enable(struct rockchip_lvds *lvds, int pipe)
366cc341c3bSZhang Yubing {
367cc341c3bSZhang Yubing regmap_write(lvds->grf, RK3562_GRF_VO_CON1,
368cc341c3bSZhang Yubing RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) |
369cc341c3bSZhang Yubing RK3568_LVDS0_DCLK_INV_SEL(1));
370cc341c3bSZhang Yubing regmap_write(lvds->grf, RK3562_GRF_VO_CON0,
371cc341c3bSZhang Yubing RK3568_LVDS0_SELECT(lvds->format) | RK3568_LVDS0_MSBSEL(1));
372cc341c3bSZhang Yubing }
373cc341c3bSZhang Yubing
rk3562_lvds_disable(struct rockchip_lvds * lvds)374cc341c3bSZhang Yubing static void rk3562_lvds_disable(struct rockchip_lvds *lvds)
375cc341c3bSZhang Yubing {
376cc341c3bSZhang Yubing regmap_write(lvds->grf, RK3562_GRF_VO_CON1, RK3568_LVDS0_MODE_EN(0));
377cc341c3bSZhang Yubing }
378cc341c3bSZhang Yubing
379cc341c3bSZhang Yubing static const struct rockchip_lvds_funcs rk3562_lvds_funcs = {
380cc341c3bSZhang Yubing .enable = rk3562_lvds_enable,
381cc341c3bSZhang Yubing .disable = rk3562_lvds_disable,
382cc341c3bSZhang Yubing };
383cc341c3bSZhang Yubing
rk3568_lvds_probe(struct rockchip_lvds * lvds)384dcebcd68SChaoyi Chen static int rk3568_lvds_probe(struct rockchip_lvds *lvds)
385dcebcd68SChaoyi Chen {
386dcebcd68SChaoyi Chen if (lvds->dual_channel) {
387dcebcd68SChaoyi Chen const struct device_node *port0, *port1;
388dcebcd68SChaoyi Chen int pixel_order;
389dcebcd68SChaoyi Chen
390dcebcd68SChaoyi Chen port1 = of_alias_get_dev("lvds", 1);
391dcebcd68SChaoyi Chen if (!port1 || !of_device_is_available(port1)) {
392dcebcd68SChaoyi Chen lvds->pixel_order = 0;
393dcebcd68SChaoyi Chen return 0;
394dcebcd68SChaoyi Chen }
395dcebcd68SChaoyi Chen
396dcebcd68SChaoyi Chen port0 = rockchip_of_graph_get_port_by_id(lvds->dev->node, 1);
397dcebcd68SChaoyi Chen port1 = rockchip_of_graph_get_port_by_id(np_to_ofnode(port1),
398dcebcd68SChaoyi Chen 1);
399dcebcd68SChaoyi Chen pixel_order =
400dcebcd68SChaoyi Chen drm_of_lvds_get_dual_link_pixel_order(port0, port1);
401dcebcd68SChaoyi Chen
402dcebcd68SChaoyi Chen lvds->pixel_order = pixel_order >= 0 ? pixel_order : 0;
403dcebcd68SChaoyi Chen }
404dcebcd68SChaoyi Chen
405dcebcd68SChaoyi Chen return 0;
406dcebcd68SChaoyi Chen }
407dcebcd68SChaoyi Chen
rk3568_lvds_enable(struct rockchip_lvds * lvds,int pipe)408aeb5dd22SSandy Huang static void rk3568_lvds_enable(struct rockchip_lvds *lvds, int pipe)
409aeb5dd22SSandy Huang {
410dcebcd68SChaoyi Chen if (lvds->id) {
411dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON3,
412dcebcd68SChaoyi Chen RK3568_LVDS1_MODE_EN(1) | RK3568_LVDS1_P2S_EN(1) |
413dcebcd68SChaoyi Chen RK3568_LVDS1_DCLK_INV_SEL(1));
414dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON0,
415dcebcd68SChaoyi Chen RK3568_LVDS1_SELECT(lvds->format) |
416dcebcd68SChaoyi Chen RK3568_LVDS1_MSBSEL(1));
417dcebcd68SChaoyi Chen } else {
418aeb5dd22SSandy Huang regmap_write(lvds->grf, RK3568_GRF_VO_CON2,
419aeb5dd22SSandy Huang RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) |
420aeb5dd22SSandy Huang RK3568_LVDS0_DCLK_INV_SEL(1));
421aeb5dd22SSandy Huang regmap_write(lvds->grf, RK3568_GRF_VO_CON0,
422dcebcd68SChaoyi Chen RK3568_LVDS0_SELECT(lvds->format) |
423dcebcd68SChaoyi Chen RK3568_LVDS0_MSBSEL(1));
424dcebcd68SChaoyi Chen }
425aeb5dd22SSandy Huang }
426aeb5dd22SSandy Huang
rk3568_lvds_disable(struct rockchip_lvds * lvds)427aeb5dd22SSandy Huang static void rk3568_lvds_disable(struct rockchip_lvds *lvds)
428aeb5dd22SSandy Huang {
429dcebcd68SChaoyi Chen if (lvds->id)
430dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON3,
431dcebcd68SChaoyi Chen RK3568_LVDS1_MODE_EN(0));
432dcebcd68SChaoyi Chen else
433dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON2,
434dcebcd68SChaoyi Chen RK3568_LVDS0_MODE_EN(0));
435aeb5dd22SSandy Huang }
436aeb5dd22SSandy Huang
437aeb5dd22SSandy Huang static const struct rockchip_lvds_funcs rk3568_lvds_funcs = {
438dcebcd68SChaoyi Chen .probe = rk3568_lvds_probe,
439aeb5dd22SSandy Huang .enable = rk3568_lvds_enable,
440aeb5dd22SSandy Huang .disable = rk3568_lvds_disable,
441aeb5dd22SSandy Huang };
442aeb5dd22SSandy Huang
443186f8572SMark Yao static const struct udevice_id rockchip_lvds_ids[] = {
444186f8572SMark Yao {
44530d6d433SWyon Bi .compatible = "rockchip,px30-lvds",
4460594ce39SZhang Yubing .data = (ulong)&px30_lvds_funcs,
44730d6d433SWyon Bi },
44830d6d433SWyon Bi {
44930d6d433SWyon Bi .compatible = "rockchip,rk3126-lvds",
4500594ce39SZhang Yubing .data = (ulong)&rk3126_lvds_funcs,
45130d6d433SWyon Bi },
45230d6d433SWyon Bi {
45330d6d433SWyon Bi .compatible = "rockchip,rk3288-lvds",
4540594ce39SZhang Yubing .data = (ulong)&rk3288_lvds_funcs,
45530d6d433SWyon Bi },
45630d6d433SWyon Bi {
457186f8572SMark Yao .compatible = "rockchip,rk3368-lvds",
4580594ce39SZhang Yubing .data = (ulong)&rk3368_lvds_funcs,
45930d6d433SWyon Bi },
460aeb5dd22SSandy Huang {
461cc341c3bSZhang Yubing .compatible = "rockchip,rk3562-lvds",
462cc341c3bSZhang Yubing .data = (ulong)&rk3562_lvds_funcs,
463cc341c3bSZhang Yubing },
464cc341c3bSZhang Yubing {
465aeb5dd22SSandy Huang .compatible = "rockchip,rk3568-lvds",
4660594ce39SZhang Yubing .data = (ulong)&rk3568_lvds_funcs,
467aeb5dd22SSandy Huang },
46830d6d433SWyon Bi {}
469186f8572SMark Yao };
470186f8572SMark Yao
471186f8572SMark Yao U_BOOT_DRIVER(rockchip_lvds) = {
472186f8572SMark Yao .name = "rockchip_lvds",
473186f8572SMark Yao .id = UCLASS_DISPLAY,
474186f8572SMark Yao .of_match = rockchip_lvds_ids,
475b69d3ed4SWyon Bi .probe = rockchip_lvds_probe,
476b69d3ed4SWyon Bi .priv_auto_alloc_size = sizeof(struct rockchip_lvds),
477186f8572SMark Yao };
478