blob: 9cf3e3ca76885ca38b231a5c15fb6ba19efc4e72 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jacob Chen35ac89d2016-03-14 11:20:16 +08002/*
3 * Copyright 2016 Rockchip Inc.
Jacob Chen35ac89d2016-03-14 11:20:16 +08004 */
5
6#include <common.h>
Jacob Chen35ac89d2016-03-14 11:20:16 +08007#include <display.h>
8#include <dm.h>
9#include <edid.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Jacob Chen35ac89d2016-03-14 11:20:16 +080011#include <panel.h>
12#include <regmap.h>
13#include <syscon.h>
Simon Glass401d1c42020-10-30 21:38:53 -060014#include <asm/global_data.h>
Jacob Chen35ac89d2016-03-14 11:20:16 +080015#include <asm/gpio.h>
16#include <asm/io.h>
Kever Yang15f09a12019-03-28 11:01:23 +080017#include <asm/arch-rockchip/clock.h>
Kever Yang15f09a12019-03-28 11:01:23 +080018#include <asm/arch-rockchip/grf_rk3288.h>
Peter Robinson973e31f2020-04-20 19:18:25 +010019#include <asm/arch-rockchip/hardware.h>
20#include <asm/arch-rockchip/lvds_rk3288.h>
Jacob Chen35ac89d2016-03-14 11:20:16 +080021#include <dt-bindings/clock/rk3288-cru.h>
22#include <dt-bindings/video/rk3288.h>
23
24DECLARE_GLOBAL_DATA_PTR;
25
26/**
27 * struct rk_lvds_priv - private rockchip lvds display driver info
28 *
29 * @reg: LVDS register address
30 * @grf: GRF register
31 * @panel: Panel device that is used in driver
32 *
33 * @output: Output mode, decided single or double channel,
34 * LVDS or LVTLL
35 * @format: Data format that RGB data will packing as
36 */
37struct rk_lvds_priv {
38 void __iomem *regs;
39 struct rk3288_grf *grf;
40 struct udevice *panel;
41
42 int output;
43 int format;
44};
45
46static inline void lvds_writel(struct rk_lvds_priv *lvds, u32 offset, u32 val)
47{
48 writel(val, lvds->regs + offset);
49
50 writel(val, lvds->regs + offset + 0x100);
51}
52
53int rk_lvds_enable(struct udevice *dev, int panel_bpp,
54 const struct display_timing *edid)
55{
56 struct rk_lvds_priv *priv = dev_get_priv(dev);
Simon Glasscaa4daa2020-12-03 16:55:18 -070057 struct display_plat *uc_plat = dev_get_uclass_plat(dev);
Jacob Chen35ac89d2016-03-14 11:20:16 +080058 int ret = 0;
59 unsigned int val = 0;
60
61 ret = panel_enable_backlight(priv->panel);
62 if (ret) {
63 debug("%s: backlight error: %d\n", __func__, ret);
64 return ret;
65 }
66
67 /* Select the video source */
68 if (uc_plat->source_id)
69 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
70 (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
71 else
72 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
73 rk_setreg(&priv->grf->soc_con6, val);
74
75 /* Select data transfer format */
76 val = priv->format;
77 if (priv->output == LVDS_OUTPUT_DUAL)
78 val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
79 else if (priv->output == LVDS_OUTPUT_SINGLE)
80 val |= LVDS_CH0_EN;
81 else if (priv->output == LVDS_OUTPUT_RGB)
82 val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
83 val |= (0xffff << 16);
84 rk_setreg(&priv->grf->soc_con7, val);
85
86 /* Enable LVDS PHY */
87 if (priv->output == LVDS_OUTPUT_RGB) {
88 lvds_writel(priv, RK3288_LVDS_CH0_REG0,
89 RK3288_LVDS_CH0_REG0_TTL_EN |
90 RK3288_LVDS_CH0_REG0_LANECK_EN |
91 RK3288_LVDS_CH0_REG0_LANE4_EN |
92 RK3288_LVDS_CH0_REG0_LANE3_EN |
93 RK3288_LVDS_CH0_REG0_LANE2_EN |
94 RK3288_LVDS_CH0_REG0_LANE1_EN |
95 RK3288_LVDS_CH0_REG0_LANE0_EN);
96 lvds_writel(priv, RK3288_LVDS_CH0_REG2,
97 RK3288_LVDS_PLL_FBDIV_REG2(0x46));
98
99 lvds_writel(priv, RK3288_LVDS_CH0_REG3,
100 RK3288_LVDS_PLL_FBDIV_REG3(0x46));
101 lvds_writel(priv, RK3288_LVDS_CH0_REG4,
102 RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
103 RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
104 RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
105 RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
106 RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
107 RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
108 lvds_writel(priv, RK3288_LVDS_CH0_REG5,
109 RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
110 RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
111 RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
112 RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
113 RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
114 RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
115 lvds_writel(priv, RK3288_LVDS_CH0_REGD,
116 RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
117 lvds_writel(priv, RK3288_LVDS_CH0_REG20,
118 RK3288_LVDS_CH0_REG20_LSB);
119 } else {
120 lvds_writel(priv, RK3288_LVDS_CH0_REG0,
121 RK3288_LVDS_CH0_REG0_LVDS_EN |
122 RK3288_LVDS_CH0_REG0_LANECK_EN |
123 RK3288_LVDS_CH0_REG0_LANE4_EN |
124 RK3288_LVDS_CH0_REG0_LANE3_EN |
125 RK3288_LVDS_CH0_REG0_LANE2_EN |
126 RK3288_LVDS_CH0_REG0_LANE1_EN |
127 RK3288_LVDS_CH0_REG0_LANE0_EN);
128 lvds_writel(priv, RK3288_LVDS_CH0_REG1,
129 RK3288_LVDS_CH0_REG1_LANECK_BIAS |
130 RK3288_LVDS_CH0_REG1_LANE4_BIAS |
131 RK3288_LVDS_CH0_REG1_LANE3_BIAS |
132 RK3288_LVDS_CH0_REG1_LANE2_BIAS |
133 RK3288_LVDS_CH0_REG1_LANE1_BIAS |
134 RK3288_LVDS_CH0_REG1_LANE0_BIAS);
135 lvds_writel(priv, RK3288_LVDS_CH0_REG2,
136 RK3288_LVDS_CH0_REG2_RESERVE_ON |
137 RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
138 RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
139 RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
140 RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
141 RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
142 RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
143 RK3288_LVDS_PLL_FBDIV_REG2(0x46));
144 lvds_writel(priv, RK3288_LVDS_CH0_REG3,
145 RK3288_LVDS_PLL_FBDIV_REG3(0x46));
146 lvds_writel(priv, RK3288_LVDS_CH0_REG4, 0x00);
147 lvds_writel(priv, RK3288_LVDS_CH0_REG5, 0x00);
148 lvds_writel(priv, RK3288_LVDS_CH0_REGD,
149 RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
150 lvds_writel(priv, RK3288_LVDS_CH0_REG20,
151 RK3288_LVDS_CH0_REG20_LSB);
152 }
153
154 /* Power on */
155 writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE,
156 priv->regs + RK3288_LVDS_CFG_REGC);
157
158 writel(RK3288_LVDS_CFG_REG21_TX_ENABLE,
159 priv->regs + RK3288_LVDS_CFG_REG21);
160
161 return 0;
162}
163
164int rk_lvds_read_timing(struct udevice *dev, struct display_timing *timing)
165{
Kever Yangc3d31af2020-02-19 09:45:37 +0800166 if (ofnode_decode_display_timing(dev_ofnode(dev), 0, timing)) {
Jacob Chen35ac89d2016-03-14 11:20:16 +0800167 debug("%s: Failed to decode display timing\n", __func__);
168 return -EINVAL;
169 }
170
171 return 0;
172}
173
Simon Glassd1998a92020-12-03 16:55:21 -0700174static int rk_lvds_of_to_plat(struct udevice *dev)
Jacob Chen35ac89d2016-03-14 11:20:16 +0800175{
176 struct rk_lvds_priv *priv = dev_get_priv(dev);
Jacob Chen35ac89d2016-03-14 11:20:16 +0800177 int ret;
Kever Yang653ac182020-02-19 09:45:38 +0800178 priv->regs = dev_read_addr_ptr(dev);
Jacob Chen35ac89d2016-03-14 11:20:16 +0800179 priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
180
Kever Yang653ac182020-02-19 09:45:38 +0800181 ret = dev_read_s32_default(dev, "rockchip,output", -1);
Jacob Chen35ac89d2016-03-14 11:20:16 +0800182 if (ret != -1) {
183 priv->output = ret;
184 debug("LVDS output : %d\n", ret);
185 } else {
186 /* default set it as output rgb */
187 priv->output = LVDS_OUTPUT_RGB;
188 }
189
Kever Yang653ac182020-02-19 09:45:38 +0800190 ret = dev_read_s32_default(dev, "rockchip,data-mapping", -1);
Jacob Chen35ac89d2016-03-14 11:20:16 +0800191 if (ret != -1) {
192 priv->format = ret;
193 debug("LVDS data-mapping : %d\n", ret);
194 } else {
195 /* default set it as format jeida */
196 priv->format = LVDS_FORMAT_JEIDA;
197 }
198
Kever Yang653ac182020-02-19 09:45:38 +0800199 ret = dev_read_s32_default(dev, "rockchip,data-width", -1);
Jacob Chen35ac89d2016-03-14 11:20:16 +0800200 if (ret != -1) {
201 debug("LVDS data-width : %d\n", ret);
202 if (ret == 24) {
203 priv->format |= LVDS_24BIT;
204 } else if (ret == 18) {
205 priv->format |= LVDS_18BIT;
206 } else {
207 debug("rockchip-lvds unsupport data-width[%d]\n", ret);
208 ret = -EINVAL;
209 return ret;
210 }
211 } else {
212 priv->format |= LVDS_24BIT;
213 }
214
215 return 0;
216}
217
218int rk_lvds_probe(struct udevice *dev)
219{
220 struct rk_lvds_priv *priv = dev_get_priv(dev);
221 int ret;
222
223 ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
224 &priv->panel);
225 if (ret) {
226 debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__,
227 dev->name, ret);
228 return ret;
229 }
230
231 return 0;
232}
233
234static const struct dm_display_ops lvds_rockchip_ops = {
235 .read_timing = rk_lvds_read_timing,
236 .enable = rk_lvds_enable,
237};
238
239static const struct udevice_id rockchip_lvds_ids[] = {
240 {.compatible = "rockchip,rk3288-lvds"},
241 {}
242};
243
244U_BOOT_DRIVER(lvds_rockchip) = {
245 .name = "lvds_rockchip",
246 .id = UCLASS_DISPLAY,
247 .of_match = rockchip_lvds_ids,
248 .ops = &lvds_rockchip_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700249 .of_to_plat = rk_lvds_of_to_plat,
Jacob Chen35ac89d2016-03-14 11:20:16 +0800250 .probe = rk_lvds_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700251 .priv_auto = sizeof(struct rk_lvds_priv),
Jacob Chen35ac89d2016-03-14 11:20:16 +0800252};