1*ab3bc873SGuochun Huang // SPDX-License-Identifier: GPL-2.0
2*ab3bc873SGuochun Huang /*
3*ab3bc873SGuochun Huang * Copyright (C) 2020 Rockchip Electronics Co. Ltd.
4*ab3bc873SGuochun Huang *
5*ab3bc873SGuochun Huang * Author: Guochun Huang <hero.huang@rock-chips.com>
6*ab3bc873SGuochun Huang */
7*ab3bc873SGuochun Huang
8*ab3bc873SGuochun Huang #include <drm/drm_mipi_dsi.h>
9*ab3bc873SGuochun Huang
10*ab3bc873SGuochun Huang #include <config.h>
11*ab3bc873SGuochun Huang #include <common.h>
12*ab3bc873SGuochun Huang #include <errno.h>
13*ab3bc873SGuochun Huang #include <malloc.h>
14*ab3bc873SGuochun Huang #include <video.h>
15*ab3bc873SGuochun Huang #include <backlight.h>
16*ab3bc873SGuochun Huang #include <spi.h>
17*ab3bc873SGuochun Huang #include <asm/gpio.h>
18*ab3bc873SGuochun Huang #include <dm/device.h>
19*ab3bc873SGuochun Huang #include <dm/read.h>
20*ab3bc873SGuochun Huang #include <dm/uclass.h>
21*ab3bc873SGuochun Huang #include <dm/uclass-id.h>
22*ab3bc873SGuochun Huang #include <linux/media-bus-format.h>
23*ab3bc873SGuochun Huang #include <power/regulator.h>
24*ab3bc873SGuochun Huang
25*ab3bc873SGuochun Huang #include "rk628.h"
26*ab3bc873SGuochun Huang #include "panel.h"
27*ab3bc873SGuochun Huang
kmemdup(const void * src,size_t len,gfp_t gfp)28*ab3bc873SGuochun Huang void *kmemdup(const void *src, size_t len, gfp_t gfp)
29*ab3bc873SGuochun Huang {
30*ab3bc873SGuochun Huang void *p;
31*ab3bc873SGuochun Huang
32*ab3bc873SGuochun Huang p = kmalloc(len, gfp);
33*ab3bc873SGuochun Huang if (p)
34*ab3bc873SGuochun Huang memcpy(p, src, len);
35*ab3bc873SGuochun Huang return p;
36*ab3bc873SGuochun Huang }
37*ab3bc873SGuochun Huang
38*ab3bc873SGuochun Huang static int
dsi_panel_parse_cmds(const u8 * data,int blen,struct panel_cmds * pcmds)39*ab3bc873SGuochun Huang dsi_panel_parse_cmds(const u8 *data, int blen, struct panel_cmds *pcmds)
40*ab3bc873SGuochun Huang {
41*ab3bc873SGuochun Huang unsigned int len;
42*ab3bc873SGuochun Huang u8 *buf, *bp;
43*ab3bc873SGuochun Huang struct cmd_ctrl_hdr *dchdr;
44*ab3bc873SGuochun Huang int i, cnt;
45*ab3bc873SGuochun Huang
46*ab3bc873SGuochun Huang if (!pcmds)
47*ab3bc873SGuochun Huang return -EINVAL;
48*ab3bc873SGuochun Huang
49*ab3bc873SGuochun Huang buf = kmemdup(data, blen, GFP_KERNEL);
50*ab3bc873SGuochun Huang if (!buf)
51*ab3bc873SGuochun Huang return -ENOMEM;
52*ab3bc873SGuochun Huang
53*ab3bc873SGuochun Huang /* scan init commands */
54*ab3bc873SGuochun Huang bp = buf;
55*ab3bc873SGuochun Huang len = blen;
56*ab3bc873SGuochun Huang cnt = 0;
57*ab3bc873SGuochun Huang while (len > sizeof(*dchdr)) {
58*ab3bc873SGuochun Huang dchdr = (struct cmd_ctrl_hdr *)bp;
59*ab3bc873SGuochun Huang
60*ab3bc873SGuochun Huang if (dchdr->dlen > len) {
61*ab3bc873SGuochun Huang pr_err("%s: error, len=%d", __func__, dchdr->dlen);
62*ab3bc873SGuochun Huang return -EINVAL;
63*ab3bc873SGuochun Huang }
64*ab3bc873SGuochun Huang
65*ab3bc873SGuochun Huang bp += sizeof(*dchdr);
66*ab3bc873SGuochun Huang len -= sizeof(*dchdr);
67*ab3bc873SGuochun Huang bp += dchdr->dlen;
68*ab3bc873SGuochun Huang len -= dchdr->dlen;
69*ab3bc873SGuochun Huang cnt++;
70*ab3bc873SGuochun Huang }
71*ab3bc873SGuochun Huang
72*ab3bc873SGuochun Huang if (len != 0) {
73*ab3bc873SGuochun Huang pr_err("%s: dcs_cmd=%x len=%d error!", __func__, buf[0], blen);
74*ab3bc873SGuochun Huang kfree(buf);
75*ab3bc873SGuochun Huang return -EINVAL;
76*ab3bc873SGuochun Huang }
77*ab3bc873SGuochun Huang
78*ab3bc873SGuochun Huang pcmds->cmds = kcalloc(cnt, sizeof(struct cmd_desc), GFP_KERNEL);
79*ab3bc873SGuochun Huang if (!pcmds->cmds) {
80*ab3bc873SGuochun Huang kfree(buf);
81*ab3bc873SGuochun Huang return -ENOMEM;
82*ab3bc873SGuochun Huang }
83*ab3bc873SGuochun Huang
84*ab3bc873SGuochun Huang pcmds->cmd_cnt = cnt;
85*ab3bc873SGuochun Huang pcmds->buf = buf;
86*ab3bc873SGuochun Huang pcmds->blen = blen;
87*ab3bc873SGuochun Huang
88*ab3bc873SGuochun Huang bp = buf;
89*ab3bc873SGuochun Huang len = blen;
90*ab3bc873SGuochun Huang for (i = 0; i < cnt; i++) {
91*ab3bc873SGuochun Huang dchdr = (struct cmd_ctrl_hdr *)bp;
92*ab3bc873SGuochun Huang len -= sizeof(*dchdr);
93*ab3bc873SGuochun Huang bp += sizeof(*dchdr);
94*ab3bc873SGuochun Huang pcmds->cmds[i].dchdr = *dchdr;
95*ab3bc873SGuochun Huang pcmds->cmds[i].payload = bp;
96*ab3bc873SGuochun Huang bp += dchdr->dlen;
97*ab3bc873SGuochun Huang len -= dchdr->dlen;
98*ab3bc873SGuochun Huang }
99*ab3bc873SGuochun Huang
100*ab3bc873SGuochun Huang return 0;
101*ab3bc873SGuochun Huang }
102*ab3bc873SGuochun Huang
dsi_panel_get_cmds(struct rk628 * rk628,ofnode dsi_np)103*ab3bc873SGuochun Huang static int dsi_panel_get_cmds(struct rk628 *rk628, ofnode dsi_np)
104*ab3bc873SGuochun Huang {
105*ab3bc873SGuochun Huang ofnode np;
106*ab3bc873SGuochun Huang const void *data;
107*ab3bc873SGuochun Huang int len;
108*ab3bc873SGuochun Huang int ret, err;
109*ab3bc873SGuochun Huang
110*ab3bc873SGuochun Huang np = ofnode_find_subnode(dsi_np, "rk628-panel");
111*ab3bc873SGuochun Huang if (!ofnode_valid(np))
112*ab3bc873SGuochun Huang return -EINVAL;
113*ab3bc873SGuochun Huang
114*ab3bc873SGuochun Huang data = ofnode_get_property(np, "panel-init-sequence", &len);
115*ab3bc873SGuochun Huang if (data) {
116*ab3bc873SGuochun Huang rk628->panel->on_cmds = kcalloc(1, sizeof(struct panel_cmds), GFP_KERNEL);
117*ab3bc873SGuochun Huang if (!rk628->panel->on_cmds)
118*ab3bc873SGuochun Huang return -ENOMEM;
119*ab3bc873SGuochun Huang
120*ab3bc873SGuochun Huang err = dsi_panel_parse_cmds(data, len, rk628->panel->on_cmds);
121*ab3bc873SGuochun Huang if (err) {
122*ab3bc873SGuochun Huang printf("rk628 failed to parse dsi panel init sequence\n");
123*ab3bc873SGuochun Huang ret = err;
124*ab3bc873SGuochun Huang goto init_err;
125*ab3bc873SGuochun Huang }
126*ab3bc873SGuochun Huang }
127*ab3bc873SGuochun Huang
128*ab3bc873SGuochun Huang data = ofnode_get_property(np, "panel-exit-sequence", &len);
129*ab3bc873SGuochun Huang if (data) {
130*ab3bc873SGuochun Huang rk628->panel->off_cmds = kcalloc(1, sizeof(struct panel_cmds), GFP_KERNEL);
131*ab3bc873SGuochun Huang if (!rk628->panel->off_cmds) {
132*ab3bc873SGuochun Huang ret = -ENOMEM;
133*ab3bc873SGuochun Huang goto on_err;
134*ab3bc873SGuochun Huang }
135*ab3bc873SGuochun Huang
136*ab3bc873SGuochun Huang err = dsi_panel_parse_cmds(data, len, rk628->panel->off_cmds);
137*ab3bc873SGuochun Huang if (err) {
138*ab3bc873SGuochun Huang printf("rk628 failed to parse dsi panel exit sequence\n");
139*ab3bc873SGuochun Huang ret = err;
140*ab3bc873SGuochun Huang goto exit_err;
141*ab3bc873SGuochun Huang }
142*ab3bc873SGuochun Huang }
143*ab3bc873SGuochun Huang
144*ab3bc873SGuochun Huang return 0;
145*ab3bc873SGuochun Huang
146*ab3bc873SGuochun Huang exit_err:
147*ab3bc873SGuochun Huang kfree(rk628->panel->off_cmds);
148*ab3bc873SGuochun Huang on_err:
149*ab3bc873SGuochun Huang kfree(rk628->panel->on_cmds->cmds);
150*ab3bc873SGuochun Huang kfree(rk628->panel->on_cmds->buf);
151*ab3bc873SGuochun Huang init_err:
152*ab3bc873SGuochun Huang kfree(rk628->panel->on_cmds);
153*ab3bc873SGuochun Huang
154*ab3bc873SGuochun Huang return ret;
155*ab3bc873SGuochun Huang }
156*ab3bc873SGuochun Huang
rk628_panel_info_get(struct rk628 * rk628,ofnode np)157*ab3bc873SGuochun Huang int rk628_panel_info_get(struct rk628 *rk628, ofnode np)
158*ab3bc873SGuochun Huang {
159*ab3bc873SGuochun Huang struct rk628_panel_simple *panel;
160*ab3bc873SGuochun Huang struct udevice *dev = rk628->dev;
161*ab3bc873SGuochun Huang int ret;
162*ab3bc873SGuochun Huang
163*ab3bc873SGuochun Huang panel = devm_kzalloc(dev, sizeof(struct rk628_panel_simple), GFP_KERNEL);
164*ab3bc873SGuochun Huang if (!panel)
165*ab3bc873SGuochun Huang return -ENOMEM;
166*ab3bc873SGuochun Huang
167*ab3bc873SGuochun Huang ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, "panel-power-supply", &panel->supply);
168*ab3bc873SGuochun Huang if (ret && ret != -ENOENT) {
169*ab3bc873SGuochun Huang printf("rk628 failed to get power supply: %d\n", ret);
170*ab3bc873SGuochun Huang return ret;
171*ab3bc873SGuochun Huang }
172*ab3bc873SGuochun Huang
173*ab3bc873SGuochun Huang ret = gpio_request_by_name(dev, "panel-enable-gpios", 0,
174*ab3bc873SGuochun Huang &panel->enable_gpio, GPIOD_IS_OUT);
175*ab3bc873SGuochun Huang if (ret && ret != -ENOENT) {
176*ab3bc873SGuochun Huang printf("%s: Cannot get enable GPIO: %d\n", __func__, ret);
177*ab3bc873SGuochun Huang return ret;
178*ab3bc873SGuochun Huang }
179*ab3bc873SGuochun Huang
180*ab3bc873SGuochun Huang ret = gpio_request_by_name(dev, "panel-reset-gpios", 0,
181*ab3bc873SGuochun Huang &panel->reset_gpio, GPIOD_IS_OUT);
182*ab3bc873SGuochun Huang if (ret && ret != -ENOENT) {
183*ab3bc873SGuochun Huang printf("%s: Cannot get reset GPIO: %d\n", __func__, ret);
184*ab3bc873SGuochun Huang return ret;
185*ab3bc873SGuochun Huang }
186*ab3bc873SGuochun Huang
187*ab3bc873SGuochun Huang ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
188*ab3bc873SGuochun Huang "panel-backlight", &panel->backlight);
189*ab3bc873SGuochun Huang if (ret && ret != -ENOENT) {
190*ab3bc873SGuochun Huang printf("%s: Cannot get backlight: %d\n", __func__, ret);
191*ab3bc873SGuochun Huang return ret;
192*ab3bc873SGuochun Huang }
193*ab3bc873SGuochun Huang
194*ab3bc873SGuochun Huang panel->delay.prepare = dev_read_u32_default(dev, "panel-prepare-delay-ms", 0);
195*ab3bc873SGuochun Huang panel->delay.enable = dev_read_u32_default(dev, "panel-enable-delay-ms", 0);
196*ab3bc873SGuochun Huang panel->delay.disable = dev_read_u32_default(dev, "panel-disable-delay-ms", 0);
197*ab3bc873SGuochun Huang panel->delay.unprepare = dev_read_u32_default(dev, "panel-unprepare-delay-ms", 0);
198*ab3bc873SGuochun Huang panel->delay.reset = dev_read_u32_default(dev, "panel-reset-delay-ms", 0);
199*ab3bc873SGuochun Huang panel->delay.init = dev_read_u32_default(dev, "panel-init-delay-ms", 0);
200*ab3bc873SGuochun Huang
201*ab3bc873SGuochun Huang rk628->panel = panel;
202*ab3bc873SGuochun Huang
203*ab3bc873SGuochun Huang if (rk628_output_is_dsi(rk628)) {
204*ab3bc873SGuochun Huang ret = dsi_panel_get_cmds(rk628, np);
205*ab3bc873SGuochun Huang if (ret) {
206*ab3bc873SGuochun Huang dev_err(dev, "failed to get cmds\n");
207*ab3bc873SGuochun Huang return ret;
208*ab3bc873SGuochun Huang }
209*ab3bc873SGuochun Huang }
210*ab3bc873SGuochun Huang
211*ab3bc873SGuochun Huang return 0;
212*ab3bc873SGuochun Huang }
213*ab3bc873SGuochun Huang
rk628_panel_prepare(struct rk628 * rk628)214*ab3bc873SGuochun Huang void rk628_panel_prepare(struct rk628 *rk628)
215*ab3bc873SGuochun Huang {
216*ab3bc873SGuochun Huang struct rk628_panel_simple *p = rk628->panel;
217*ab3bc873SGuochun Huang
218*ab3bc873SGuochun Huang if (!p)
219*ab3bc873SGuochun Huang return;
220*ab3bc873SGuochun Huang
221*ab3bc873SGuochun Huang if (p->supply)
222*ab3bc873SGuochun Huang regulator_set_enable(p->supply, 1);
223*ab3bc873SGuochun Huang
224*ab3bc873SGuochun Huang if (dm_gpio_is_valid(&p->enable_gpio))
225*ab3bc873SGuochun Huang dm_gpio_set_value(&p->enable_gpio, 1);
226*ab3bc873SGuochun Huang
227*ab3bc873SGuochun Huang if (p->delay.prepare)
228*ab3bc873SGuochun Huang mdelay(p->delay.prepare);
229*ab3bc873SGuochun Huang
230*ab3bc873SGuochun Huang if (dm_gpio_is_valid(&p->reset_gpio))
231*ab3bc873SGuochun Huang dm_gpio_set_value(&p->reset_gpio, 1);
232*ab3bc873SGuochun Huang
233*ab3bc873SGuochun Huang if (p->delay.reset)
234*ab3bc873SGuochun Huang mdelay(p->delay.reset);
235*ab3bc873SGuochun Huang
236*ab3bc873SGuochun Huang if (dm_gpio_is_valid(&p->reset_gpio))
237*ab3bc873SGuochun Huang dm_gpio_set_value(&p->reset_gpio, 0);
238*ab3bc873SGuochun Huang
239*ab3bc873SGuochun Huang if (p->delay.init)
240*ab3bc873SGuochun Huang mdelay(p->delay.init);
241*ab3bc873SGuochun Huang }
242*ab3bc873SGuochun Huang
rk628_panel_enable(struct rk628 * rk628)243*ab3bc873SGuochun Huang void rk628_panel_enable(struct rk628 *rk628)
244*ab3bc873SGuochun Huang {
245*ab3bc873SGuochun Huang struct rk628_panel_simple *p = rk628->panel;
246*ab3bc873SGuochun Huang
247*ab3bc873SGuochun Huang if (!p)
248*ab3bc873SGuochun Huang return;
249*ab3bc873SGuochun Huang
250*ab3bc873SGuochun Huang if (p->delay.enable)
251*ab3bc873SGuochun Huang mdelay(p->delay.enable);
252*ab3bc873SGuochun Huang
253*ab3bc873SGuochun Huang
254*ab3bc873SGuochun Huang if (p->backlight)
255*ab3bc873SGuochun Huang backlight_enable(p->backlight);
256*ab3bc873SGuochun Huang }
257*ab3bc873SGuochun Huang
rk628_panel_unprepare(struct rk628 * rk628)258*ab3bc873SGuochun Huang void rk628_panel_unprepare(struct rk628 *rk628)
259*ab3bc873SGuochun Huang {
260*ab3bc873SGuochun Huang struct rk628_panel_simple *p = rk628->panel;
261*ab3bc873SGuochun Huang
262*ab3bc873SGuochun Huang if (!p)
263*ab3bc873SGuochun Huang return;
264*ab3bc873SGuochun Huang
265*ab3bc873SGuochun Huang if (dm_gpio_is_valid(&p->reset_gpio))
266*ab3bc873SGuochun Huang dm_gpio_set_value(&p->reset_gpio, 1);
267*ab3bc873SGuochun Huang
268*ab3bc873SGuochun Huang if (dm_gpio_is_valid(&p->enable_gpio))
269*ab3bc873SGuochun Huang dm_gpio_set_value(&p->enable_gpio, 0);
270*ab3bc873SGuochun Huang
271*ab3bc873SGuochun Huang if (rk628->panel->supply)
272*ab3bc873SGuochun Huang regulator_set_enable(p->supply, 0);
273*ab3bc873SGuochun Huang
274*ab3bc873SGuochun Huang if (p->delay.unprepare)
275*ab3bc873SGuochun Huang mdelay(p->delay.unprepare);
276*ab3bc873SGuochun Huang }
277*ab3bc873SGuochun Huang
rk628_panel_disable(struct rk628 * rk628)278*ab3bc873SGuochun Huang void rk628_panel_disable(struct rk628 *rk628)
279*ab3bc873SGuochun Huang {
280*ab3bc873SGuochun Huang struct rk628_panel_simple *p = rk628->panel;
281*ab3bc873SGuochun Huang
282*ab3bc873SGuochun Huang if (!p)
283*ab3bc873SGuochun Huang return;
284*ab3bc873SGuochun Huang
285*ab3bc873SGuochun Huang if (p->backlight)
286*ab3bc873SGuochun Huang backlight_disable(p->backlight);
287*ab3bc873SGuochun Huang
288*ab3bc873SGuochun Huang if (p->delay.disable)
289*ab3bc873SGuochun Huang mdelay(p->delay.disable);
290*ab3bc873SGuochun Huang }
291