]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
f680a91d | 2 | /* |
3 | * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd | |
4 | * Author: Eric Gao <eric.gao@rock-chips.com> | |
f680a91d | 5 | */ |
6 | ||
7 | #include <common.h> | |
8 | #include <clk.h> | |
9 | #include <display.h> | |
10 | #include <dm.h> | |
11 | #include <fdtdec.h> | |
12 | #include <panel.h> | |
13 | #include <regmap.h> | |
14 | #include "rk_mipi.h" | |
15 | #include <syscon.h> | |
16 | #include <asm/gpio.h> | |
17 | #include <asm/hardware.h> | |
18 | #include <asm/io.h> | |
19 | #include <dm/uclass-internal.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <asm/arch/clock.h> | |
22 | #include <asm/arch/cru_rk3288.h> | |
23 | #include <asm/arch/grf_rk3288.h> | |
24 | #include <asm/arch/rockchip_mipi_dsi.h> | |
25 | ||
f680a91d | 26 | #define MHz 1000000 |
27 | ||
28 | /* Select mipi dsi source, big or little vop */ | |
29 | static int rk_mipi_dsi_source_select(struct udevice *dev) | |
30 | { | |
31 | struct rk_mipi_priv *priv = dev_get_priv(dev); | |
32 | struct rk3288_grf *grf = priv->grf; | |
33 | struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev); | |
34 | ||
35 | /* Select the video source */ | |
36 | switch (disp_uc_plat->source_id) { | |
37 | case VOP_B: | |
38 | rk_clrsetreg(&grf->soc_con6, RK3288_DSI0_LCDC_SEL_MASK, | |
39 | RK3288_DSI0_LCDC_SEL_BIG | |
40 | << RK3288_DSI0_LCDC_SEL_SHIFT); | |
41 | break; | |
42 | case VOP_L: | |
43 | rk_clrsetreg(&grf->soc_con6, RK3288_DSI0_LCDC_SEL_MASK, | |
44 | RK3288_DSI0_LCDC_SEL_LIT | |
45 | << RK3288_DSI0_LCDC_SEL_SHIFT); | |
46 | break; | |
47 | default: | |
48 | debug("%s: Invalid VOP id\n", __func__); | |
49 | return -EINVAL; | |
50 | } | |
51 | ||
52 | return 0; | |
53 | } | |
54 | ||
55 | /* Setup mipi dphy working mode */ | |
56 | static void rk_mipi_dphy_mode_set(struct udevice *dev) | |
57 | { | |
58 | struct rk_mipi_priv *priv = dev_get_priv(dev); | |
59 | struct rk3288_grf *grf = priv->grf; | |
60 | int val; | |
61 | ||
62 | /* Set Controller as TX mode */ | |
63 | val = RK3288_DPHY_TX0_RXMODE_DIS << RK3288_DPHY_TX0_RXMODE_SHIFT; | |
64 | rk_clrsetreg(&grf->soc_con8, RK3288_DPHY_TX0_RXMODE_MASK, val); | |
65 | ||
66 | /* Exit tx stop mode */ | |
67 | val |= RK3288_DPHY_TX0_TXSTOPMODE_EN | |
68 | << RK3288_DPHY_TX0_TXSTOPMODE_SHIFT; | |
69 | rk_clrsetreg(&grf->soc_con8, | |
70 | RK3288_DPHY_TX0_TXSTOPMODE_MASK, val); | |
71 | ||
72 | /* Disable turnequest */ | |
73 | val |= RK3288_DPHY_TX0_TURNREQUEST_EN | |
74 | << RK3288_DPHY_TX0_TURNREQUEST_SHIFT; | |
75 | rk_clrsetreg(&grf->soc_con8, | |
76 | RK3288_DPHY_TX0_TURNREQUEST_MASK, val); | |
77 | } | |
78 | ||
79 | /* | |
80 | * This function is called by rk_display_init() using rk_mipi_dsi_enable() and | |
81 | * rk_mipi_phy_enable() to initialize mipi controller and dphy. If success, | |
82 | * enable backlight. | |
83 | */ | |
84 | static int rk_mipi_enable(struct udevice *dev, int panel_bpp, | |
85 | const struct display_timing *timing) | |
86 | { | |
87 | int ret; | |
88 | struct rk_mipi_priv *priv = dev_get_priv(dev); | |
89 | ||
90 | /* Fill the mipi controller parameter */ | |
91 | priv->ref_clk = 24 * MHz; | |
92 | priv->sys_clk = priv->ref_clk; | |
93 | priv->pix_clk = timing->pixelclock.typ; | |
94 | priv->phy_clk = priv->pix_clk * 6; | |
95 | priv->txbyte_clk = priv->phy_clk / 8; | |
96 | priv->txesc_clk = 20 * MHz; | |
97 | ||
98 | /* Select vop port, big or little */ | |
99 | rk_mipi_dsi_source_select(dev); | |
100 | ||
101 | /* Set mipi dphy work mode */ | |
102 | rk_mipi_dphy_mode_set(dev); | |
103 | ||
104 | /* Config and enable mipi dsi according to timing */ | |
105 | ret = rk_mipi_dsi_enable(dev, timing); | |
106 | if (ret) { | |
107 | debug("%s: rk_mipi_dsi_enable() failed (err=%d)\n", | |
108 | __func__, ret); | |
109 | return ret; | |
110 | } | |
111 | ||
112 | /* Config and enable mipi phy */ | |
113 | ret = rk_mipi_phy_enable(dev); | |
114 | if (ret) { | |
115 | debug("%s: rk_mipi_phy_enable() failed (err=%d)\n", | |
116 | __func__, ret); | |
117 | return ret; | |
118 | } | |
119 | ||
120 | /* Enable backlight */ | |
121 | ret = panel_enable_backlight(priv->panel); | |
122 | if (ret) { | |
123 | debug("%s: panel_enable_backlight() failed (err=%d)\n", | |
124 | __func__, ret); | |
125 | return ret; | |
126 | } | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | static int rk_mipi_ofdata_to_platdata(struct udevice *dev) | |
132 | { | |
133 | struct rk_mipi_priv *priv = dev_get_priv(dev); | |
134 | ||
135 | priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); | |
6e607791 | 136 | if (IS_ERR_OR_NULL(priv->grf)) { |
f680a91d | 137 | debug("%s: Get syscon grf failed (ret=%p)\n", |
138 | __func__, priv->grf); | |
139 | return -ENXIO; | |
140 | } | |
141 | priv->regs = dev_read_addr(dev); | |
142 | if (priv->regs == FDT_ADDR_T_NONE) { | |
143 | debug("%s: Get MIPI dsi address failed (ret=%lu)\n", __func__, | |
144 | priv->regs); | |
145 | return -ENXIO; | |
146 | } | |
147 | ||
148 | return 0; | |
149 | } | |
150 | ||
151 | /* | |
152 | * Probe function: check panel existence and readingit's timing. Then config | |
153 | * mipi dsi controller and enable it according to the timing parameter. | |
154 | */ | |
155 | static int rk_mipi_probe(struct udevice *dev) | |
156 | { | |
157 | int ret; | |
158 | struct rk_mipi_priv *priv = dev_get_priv(dev); | |
159 | ||
160 | ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel", | |
161 | &priv->panel); | |
162 | if (ret) { | |
163 | debug("%s: Can not find panel (err=%d)\n", __func__, ret); | |
164 | return ret; | |
165 | } | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | static const struct dm_display_ops rk_mipi_dsi_ops = { | |
171 | .read_timing = rk_mipi_read_timing, | |
172 | .enable = rk_mipi_enable, | |
173 | }; | |
174 | ||
175 | static const struct udevice_id rk_mipi_dsi_ids[] = { | |
176 | { .compatible = "rockchip,rk3288_mipi_dsi" }, | |
177 | { } | |
178 | }; | |
179 | ||
180 | U_BOOT_DRIVER(rk_mipi_dsi) = { | |
181 | .name = "rk_mipi_dsi", | |
182 | .id = UCLASS_DISPLAY, | |
183 | .of_match = rk_mipi_dsi_ids, | |
184 | .ofdata_to_platdata = rk_mipi_ofdata_to_platdata, | |
185 | .probe = rk_mipi_probe, | |
186 | .ops = &rk_mipi_dsi_ops, | |
187 | .priv_auto_alloc_size = sizeof(struct rk_mipi_priv), | |
188 | }; |