xref: /OK3568_Linux_fs/u-boot/drivers/video/rk_eink/rk_eink_display.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2020 Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:     GPL-2.0+
5*4882a593Smuzhiyun  * Author: Wenping Zhang <wenping.zhang@rock-chips.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <errno.h>
11*4882a593Smuzhiyun #include <mapmem.h>
12*4882a593Smuzhiyun #include <stdlib.h>
13*4882a593Smuzhiyun #include <asm/arch/vendor.h>
14*4882a593Smuzhiyun #include <dm/of_access.h>
15*4882a593Smuzhiyun #include <dm/uclass.h>
16*4882a593Smuzhiyun #include <dm/uclass-id.h>
17*4882a593Smuzhiyun #include <boot_rkimg.h>
18*4882a593Smuzhiyun #include <rk_eink.h>
19*4882a593Smuzhiyun #include <backlight.h>
20*4882a593Smuzhiyun #include "rk_ebc.h"
21*4882a593Smuzhiyun #include "epdlut/epd_lut.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define PART_WAVEFORM		"waveform"
24*4882a593Smuzhiyun #define EINK_LOGO_PART_MAGIC	"RKEL"
25*4882a593Smuzhiyun #define EINK_LOGO_IMAGE_MAGIC	"GR04"
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun  * grayscale logo partition format:
28*4882a593Smuzhiyun  * block0:
29*4882a593Smuzhiyun  * struct logo_part_header part_header;
30*4882a593Smuzhiyun  * struct grayscale_header logo1_header;
31*4882a593Smuzhiyun  * struct grayscale_header logo2_header;
32*4882a593Smuzhiyun  * struct grayscale_header logo3_header;
33*4882a593Smuzhiyun  * struct grayscale_header logo4_header;
34*4882a593Smuzhiyun  * ....
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * block 1:
37*4882a593Smuzhiyun  * logo1_image
38*4882a593Smuzhiyun  *
39*4882a593Smuzhiyun  * .....
40*4882a593Smuzhiyun  * block m:
41*4882a593Smuzhiyun  * logo2_image
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  * ........
44*4882a593Smuzhiyun  * block n:
45*4882a593Smuzhiyun  * logo3_image
46*4882a593Smuzhiyun  *
47*4882a593Smuzhiyun  * ........
48*4882a593Smuzhiyun  * block i:
49*4882a593Smuzhiyun  * logoi_image
50*4882a593Smuzhiyun  */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun //logo partition Header, 64byte
53*4882a593Smuzhiyun struct logo_part_header {
54*4882a593Smuzhiyun 	char magic[4]; /* must be "RKEL" */
55*4882a593Smuzhiyun 	u32  totoal_size;
56*4882a593Smuzhiyun 	u32  screen_width;
57*4882a593Smuzhiyun 	u32  screen_height;
58*4882a593Smuzhiyun 	u32  logo_count;
59*4882a593Smuzhiyun 	u8   version[4];
60*4882a593Smuzhiyun 	u32  rsv[10];
61*4882a593Smuzhiyun } __packed;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun // logo image header,32 byte
64*4882a593Smuzhiyun struct grayscale_header {
65*4882a593Smuzhiyun 	char magic[4]; /* must be "GR04" */
66*4882a593Smuzhiyun 	u16 x;
67*4882a593Smuzhiyun 	u16 y;
68*4882a593Smuzhiyun 	u16 w;
69*4882a593Smuzhiyun 	u16 h;
70*4882a593Smuzhiyun 	u32 logo_type;
71*4882a593Smuzhiyun 	u32 data_offset; /* image offset in byte */
72*4882a593Smuzhiyun 	u32 data_size; /* image size in byte */
73*4882a593Smuzhiyun 	u32 rsv[2];
74*4882a593Smuzhiyun } __packed;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /*
77*4882a593Smuzhiyun  * The start address of logo image in logo.img must be aligned in 512 bytes,
78*4882a593Smuzhiyun  * so the header size must be times of 512 bytes. Here we fix the size to 512
79*4882a593Smuzhiyun  * bytes, so the count of logo image can only support up to 14.
80*4882a593Smuzhiyun  */
81*4882a593Smuzhiyun struct logo_info {
82*4882a593Smuzhiyun 	struct logo_part_header part_hdr;
83*4882a593Smuzhiyun 	struct grayscale_header img_hdr[14];
84*4882a593Smuzhiyun } __packed;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun struct rockchip_eink_display_priv {
87*4882a593Smuzhiyun 	struct udevice *dev;
88*4882a593Smuzhiyun 	struct udevice *ebc_tcon_dev;
89*4882a593Smuzhiyun 	struct udevice *ebc_pwr_dev;
90*4882a593Smuzhiyun 	int vcom;
91*4882a593Smuzhiyun 	struct udevice *backlight;
92*4882a593Smuzhiyun };
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun enum {
95*4882a593Smuzhiyun 	EBC_PWR_DOWN = 0,
96*4882a593Smuzhiyun 	EBC_PWR_ON = 1,
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun #define EINK_VCOM_ID		17
100*4882a593Smuzhiyun #define EINK_VCOM_MAX		64
101*4882a593Smuzhiyun #define VCOM_DEFAULT_VALUE	1650
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun static struct logo_info eink_logo_info;
104*4882a593Smuzhiyun static struct udevice *eink_dev;
105*4882a593Smuzhiyun static volatile int last_logo_type = -1;
read_vcom_from_vendor(void)106*4882a593Smuzhiyun static int read_vcom_from_vendor(void)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	int ret = 0;
109*4882a593Smuzhiyun 	char vcom_str[EINK_VCOM_MAX] = {0};
110*4882a593Smuzhiyun 	char vcom_args[EINK_VCOM_MAX] = {0};
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	/* Read vcom value from vendor storage part */
113*4882a593Smuzhiyun 	ret = vendor_storage_read(EINK_VCOM_ID, vcom_str, (EINK_VCOM_MAX - 1));
114*4882a593Smuzhiyun 	if (ret > 0) {
115*4882a593Smuzhiyun 		snprintf(vcom_args, strlen(vcom_str) + 15, "ebc_pmic.vcom=%s", vcom_str);
116*4882a593Smuzhiyun 		printf("eink update bootargs: %s\n", vcom_args);
117*4882a593Smuzhiyun 		env_update("bootargs", vcom_args);
118*4882a593Smuzhiyun 	} else {
119*4882a593Smuzhiyun 		return ret;
120*4882a593Smuzhiyun 	}
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return atoi(vcom_str);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
read_waveform(struct udevice * dev)125*4882a593Smuzhiyun static int read_waveform(struct udevice *dev)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	int cnt, start, ret;
128*4882a593Smuzhiyun 	disk_partition_t part;
129*4882a593Smuzhiyun 	struct blk_desc *dev_desc;
130*4882a593Smuzhiyun 	struct ebc_panel *plat = dev_get_platdata(dev);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	dev_desc = rockchip_get_bootdev();
133*4882a593Smuzhiyun 	if (!dev_desc) {
134*4882a593Smuzhiyun 		printf("%s: Could not find device\n", __func__);
135*4882a593Smuzhiyun 		return -EIO;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 	if (part_get_info_by_name(dev_desc, PART_WAVEFORM, &part) < 0) {
138*4882a593Smuzhiyun 		printf("Get waveform partition failed\n");
139*4882a593Smuzhiyun 		return -ENODEV;
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 	cnt = plat->lut_pbuf_size / RK_BLK_SIZE;
142*4882a593Smuzhiyun 	start = part.start;
143*4882a593Smuzhiyun 	ret = blk_dread(dev_desc, start, cnt, (void *)plat->lut_pbuf);
144*4882a593Smuzhiyun 	if (ret != cnt)
145*4882a593Smuzhiyun 		printf("Try to read %d blocks failed, only read %d\n",
146*4882a593Smuzhiyun 		       cnt, ret);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	flush_dcache_range((ulong)plat->lut_pbuf,
149*4882a593Smuzhiyun 			   ALIGN((ulong)plat->lut_pbuf + cnt,
150*4882a593Smuzhiyun 				 CONFIG_SYS_CACHELINE_SIZE));
151*4882a593Smuzhiyun 	ret = epd_lut_from_mem_init(plat->lut_pbuf, &plat->lut_ops);
152*4882a593Smuzhiyun 	if (ret < 0) {
153*4882a593Smuzhiyun 		printf("lut init failed\n");
154*4882a593Smuzhiyun 		return -EINVAL;
155*4882a593Smuzhiyun 	}
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
aligned_image_size_4k(struct udevice * dev)160*4882a593Smuzhiyun static u32 aligned_image_size_4k(struct udevice *dev)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	struct ebc_panel *plat = dev_get_platdata(dev);
163*4882a593Smuzhiyun 	u32 w = plat->vir_width;
164*4882a593Smuzhiyun 	u32 h = plat->vir_height;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return ALIGN((w * h) >> 1, 4096);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /*
170*4882a593Smuzhiyun  * This driver load the grayscale image from flash,
171*4882a593Smuzhiyun  * and put it in the reserve memory which define in dts:
172*4882a593Smuzhiyun  * display_reserved: framebuffer@10000000 {
173*4882a593Smuzhiyun  *	reg = <0x0 0x10000000 0x0 0x2000000>;
174*4882a593Smuzhiyun  *	no-map;
175*4882a593Smuzhiyun  * };
176*4882a593Smuzhiyun  * Every image logo size must be aligned in 4K, make sure
177*4882a593Smuzhiyun  * kernel can use it rightly, the buffer of LOGO image is
178*4882a593Smuzhiyun  * put in order of below map:
179*4882a593Smuzhiyun  *  |---reset logo        ---|
180*4882a593Smuzhiyun  *  |---uboot logo        ---|
181*4882a593Smuzhiyun  *  |---kernel logo       ---|
182*4882a593Smuzhiyun  *  |---charge_0 logo   ---|
183*4882a593Smuzhiyun  *  |---charge_1 logo   ---|
184*4882a593Smuzhiyun  *  |---charge_2 logo   ---|
185*4882a593Smuzhiyun  *  |---charge_3 logo   ---|
186*4882a593Smuzhiyun  *  |---charge_4 logo   ---|
187*4882a593Smuzhiyun  *  |---charge_5 logo   ---|
188*4882a593Smuzhiyun  *  |---battery low logo---|
189*4882a593Smuzhiyun  *  |---temp un-mirror buffer--|
190*4882a593Smuzhiyun  */
get_addr_by_type(struct udevice * dev,u32 logo_type)191*4882a593Smuzhiyun static int get_addr_by_type(struct udevice *dev, u32 logo_type)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	u32 offset, indx, img_size;
194*4882a593Smuzhiyun 	struct ebc_panel *plat = dev_get_platdata(dev);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (plat->disp_pbuf_size == 0 || !plat->disp_pbuf) {
197*4882a593Smuzhiyun 		printf("invalid display buffer, please check dts\n");
198*4882a593Smuzhiyun 		return -EINVAL;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 	indx = ffs(logo_type);
201*4882a593Smuzhiyun 	img_size = aligned_image_size_4k(dev);
202*4882a593Smuzhiyun 	offset = img_size * indx;
203*4882a593Smuzhiyun 	if (offset + img_size > plat->disp_pbuf_size) {
204*4882a593Smuzhiyun 		printf("reserve display memory size is not enough\n");
205*4882a593Smuzhiyun 		return -EINVAL;
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	switch (logo_type) {
209*4882a593Smuzhiyun 	case EINK_LOGO_RESET:
210*4882a593Smuzhiyun 	case EINK_LOGO_UBOOT:
211*4882a593Smuzhiyun 	case EINK_LOGO_KERNEL:
212*4882a593Smuzhiyun 	case EINK_LOGO_CHARGING_0:
213*4882a593Smuzhiyun 	case EINK_LOGO_CHARGING_1:
214*4882a593Smuzhiyun 	case EINK_LOGO_CHARGING_2:
215*4882a593Smuzhiyun 	case EINK_LOGO_CHARGING_3:
216*4882a593Smuzhiyun 	case EINK_LOGO_CHARGING_4:
217*4882a593Smuzhiyun 	case EINK_LOGO_CHARGING_5:
218*4882a593Smuzhiyun 	case EINK_LOGO_CHARGING_LOWPOWER:
219*4882a593Smuzhiyun 	case EINK_LOGO_POWEROFF:
220*4882a593Smuzhiyun 	/*
221*4882a593Smuzhiyun 	 * The MIRROR_TEMP_BUF is used to save the
222*4882a593Smuzhiyun 	 * non-mirror image data.
223*4882a593Smuzhiyun 	 */
224*4882a593Smuzhiyun 	case EINK_LOGO_UNMIRROR_TEMP_BUF:
225*4882a593Smuzhiyun 		return (plat->disp_pbuf + offset);
226*4882a593Smuzhiyun 	default:
227*4882a593Smuzhiyun 		printf("invalid logo type[%d]\n", logo_type);
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	return -EINVAL;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
read_header(struct blk_desc * dev_desc,disk_partition_t * part,struct logo_info * header)233*4882a593Smuzhiyun static int read_header(struct blk_desc *dev_desc,
234*4882a593Smuzhiyun 		       disk_partition_t *part,
235*4882a593Smuzhiyun 		       struct logo_info *header)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	int i;
238*4882a593Smuzhiyun 	struct logo_part_header *part_hdr = &header->part_hdr;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (blk_dread(dev_desc, part->start, 1, header) != 1)
241*4882a593Smuzhiyun 		return -EIO;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (memcmp(part_hdr->magic, EINK_LOGO_PART_MAGIC, 4)) {
244*4882a593Smuzhiyun 		printf("partition header is invalid\n");
245*4882a593Smuzhiyun 		return -EINVAL;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	if (part_hdr->logo_count == 0) {
248*4882a593Smuzhiyun 		printf("the count of logo image is 0\n");
249*4882a593Smuzhiyun 		return -EINVAL;
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 	for (i = 0; i < part_hdr->logo_count; i++) {
252*4882a593Smuzhiyun 		struct grayscale_header *img_hdr = &header->img_hdr[i];
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 		if (memcmp(img_hdr->magic, EINK_LOGO_IMAGE_MAGIC, 4)) {
255*4882a593Smuzhiyun 			printf("image[%d] header '%s' is invalid\n", i,
256*4882a593Smuzhiyun 			       img_hdr->magic);
257*4882a593Smuzhiyun 			return -EINVAL;
258*4882a593Smuzhiyun 		}
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
read_grayscale(struct blk_desc * dev_desc,disk_partition_t * part,u32 offset,u32 size,void * buf)264*4882a593Smuzhiyun static int read_grayscale(struct blk_desc *dev_desc,
265*4882a593Smuzhiyun 			  disk_partition_t *part, u32 offset,
266*4882a593Smuzhiyun 			  u32 size, void *buf)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	u32 blk_start, blk_offset, blk_count;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	blk_offset = DIV_ROUND_UP(offset, dev_desc->blksz);
271*4882a593Smuzhiyun 	blk_start = part->start + blk_offset;
272*4882a593Smuzhiyun 	blk_count = DIV_ROUND_UP(size, dev_desc->blksz);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	debug("blk_offset=%d, blk_start=%d,blk_count=%d,out buf=%p\n",
275*4882a593Smuzhiyun 	      blk_offset, blk_start, blk_count, buf);
276*4882a593Smuzhiyun 	if (blk_dread(dev_desc, blk_start, blk_count, buf) != blk_count) {
277*4882a593Smuzhiyun 		printf("read grayscale data failed\n");
278*4882a593Smuzhiyun 		return -EIO;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun 
image_rearrange(u8 * in_buf,u8 * out_buf,u16 w,u16 h)284*4882a593Smuzhiyun static int image_rearrange(u8 *in_buf, u8 *out_buf, u16 w, u16 h)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	int i, j;
287*4882a593Smuzhiyun 	u8 in_data;
288*4882a593Smuzhiyun 	u8 *out_buf_tmp;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (!in_buf || !out_buf) {
291*4882a593Smuzhiyun 		printf("rearrange in buffer or out buffer is NULL\n");
292*4882a593Smuzhiyun 		return -EINVAL;
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	for (i = 0; i < h; i += 2) {
296*4882a593Smuzhiyun 		out_buf_tmp = out_buf + (i * w / 2);
297*4882a593Smuzhiyun 		for (j = 0; j < w / 2; j++) {
298*4882a593Smuzhiyun 			in_data = *in_buf++;
299*4882a593Smuzhiyun 			*(out_buf_tmp + j * 2) = in_data & 0x0f;
300*4882a593Smuzhiyun 			*(out_buf_tmp + j * 2 + 1) = (in_data >> 4) & 0x0f;
301*4882a593Smuzhiyun 		}
302*4882a593Smuzhiyun 		for (j = 0; j < w / 2; j++) {
303*4882a593Smuzhiyun 			in_data = *in_buf++;
304*4882a593Smuzhiyun 			*(out_buf_tmp + j * 2) |= (in_data << 4) & 0xf0;
305*4882a593Smuzhiyun 			*(out_buf_tmp + j * 2 + 1) |= in_data & 0xf0;
306*4882a593Smuzhiyun 		}
307*4882a593Smuzhiyun 	}
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	return 0;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
image_mirror(u8 * in_buf,u8 * out_buf,u16 w,u16 h)312*4882a593Smuzhiyun static int image_mirror(u8 *in_buf, u8 *out_buf, u16 w, u16 h)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	int i;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	if (!in_buf || !out_buf) {
317*4882a593Smuzhiyun 		printf("mirror in buffer or out buffer is NULL\n");
318*4882a593Smuzhiyun 		return -EINVAL;
319*4882a593Smuzhiyun 	}
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	for (i = 0; i < h; i++) {
322*4882a593Smuzhiyun 		u16 column_len = w / 2;
323*4882a593Smuzhiyun 		u8 *column_in = in_buf + i * column_len;
324*4882a593Smuzhiyun 		u8 *column_out = out_buf + (h - i - 1) * column_len;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 		memcpy(column_out, column_in, column_len);
327*4882a593Smuzhiyun 	}
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	return 0;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun /*
333*4882a593Smuzhiyun  * The eink kernel driver need last frame to do part refresh,
334*4882a593Smuzhiyun  * so we need to transfer two images to kernel, which is kernel
335*4882a593Smuzhiyun  * logo and the logo displayed in uboot.
336*4882a593Smuzhiyun  *
337*4882a593Smuzhiyun  * this function use logo type bitmap to indicate several logo.
338*4882a593Smuzhiyun  * u32 needed_logo: we only load needed logo image into ram, such as
339*4882a593Smuzhiyun  *                   uboot logo + kernel logo or charger logo + kernel
340*4882a593Smuzhiyun  *                   logo
341*4882a593Smuzhiyun  * u32 *loaded_logo: because the needed logo may not exist in logo.img,
342*4882a593Smuzhiyun  *                  store the really loaded logo in para loaded_logo.
343*4882a593Smuzhiyun  */
read_needed_logo_from_partition(struct udevice * dev,u32 needed_logo,u32 * loaded_logo)344*4882a593Smuzhiyun static int read_needed_logo_from_partition(struct udevice *dev,
345*4882a593Smuzhiyun 					   u32 needed_logo,
346*4882a593Smuzhiyun 					   u32 *loaded_logo)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	int ret, i;
349*4882a593Smuzhiyun 	disk_partition_t part;
350*4882a593Smuzhiyun 	struct blk_desc *dev_desc;
351*4882a593Smuzhiyun 	struct logo_info *hdr = &eink_logo_info;
352*4882a593Smuzhiyun 	struct logo_part_header *part_hdr = &hdr->part_hdr;
353*4882a593Smuzhiyun 	struct ebc_panel *panel = dev_get_platdata(dev);
354*4882a593Smuzhiyun 	u32 logo = needed_logo & (~(*loaded_logo));
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (!logo) {
357*4882a593Smuzhiyun 		printf("logo[0x%x] is already loaded, just return!\n",
358*4882a593Smuzhiyun 		       needed_logo);
359*4882a593Smuzhiyun 		return 0;
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 	dev_desc = rockchip_get_bootdev();
362*4882a593Smuzhiyun 	if (!dev_desc) {
363*4882a593Smuzhiyun 		printf("%s: Could not find device\n", __func__);
364*4882a593Smuzhiyun 		return -EIO;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	if (part_get_info_by_name(dev_desc, PART_LOGO, &part) < 0)
368*4882a593Smuzhiyun 		return -ENODEV;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	ret = read_header(dev_desc, &part, hdr);
371*4882a593Smuzhiyun 	if (ret < 0) {
372*4882a593Smuzhiyun 		printf("eink logo read header failed,ret = %d\n", ret);
373*4882a593Smuzhiyun 		return -EINVAL;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun 	if (part_hdr->screen_width != panel->vir_width ||
376*4882a593Smuzhiyun 	    part_hdr->screen_height != panel->vir_height){
377*4882a593Smuzhiyun 		printf("logo size(%dx%d) is not same as screen size(%dx%d)\n",
378*4882a593Smuzhiyun 		       part_hdr->screen_width, part_hdr->screen_height,
379*4882a593Smuzhiyun 			panel->vir_width, panel->vir_height);
380*4882a593Smuzhiyun 		return -EINVAL;
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	for (i = 0; i < part_hdr->logo_count; i++) {
384*4882a593Smuzhiyun 		struct grayscale_header *img_hdr = &hdr->img_hdr[i];
385*4882a593Smuzhiyun 		int pic_buf;
386*4882a593Smuzhiyun 		u32 offset = img_hdr->data_offset;
387*4882a593Smuzhiyun 		u32 size = img_hdr->data_size;
388*4882a593Smuzhiyun 		u32 logo_type = img_hdr->logo_type;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 		debug("offset=0x%x, size=%d,logo_type=%d,w=%d,h=%d\n",
391*4882a593Smuzhiyun 		      offset, size, logo_type, img_hdr->w, img_hdr->h);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 		if (logo & logo_type) {
394*4882a593Smuzhiyun 			pic_buf = get_addr_by_type(dev, logo_type);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 			if (pic_buf <= 0) {
397*4882a593Smuzhiyun 				printf("Get buffer failed for image %d\n",
398*4882a593Smuzhiyun 				       img_hdr->logo_type);
399*4882a593Smuzhiyun 				return -EIO;
400*4882a593Smuzhiyun 			}
401*4882a593Smuzhiyun 			if (!IS_ALIGNED((ulong)pic_buf,
402*4882a593Smuzhiyun 					ARCH_DMA_MINALIGN)) {
403*4882a593Smuzhiyun 				printf("disp buffer is not dma aligned\n");
404*4882a593Smuzhiyun 				return -EINVAL;
405*4882a593Smuzhiyun 			}
406*4882a593Smuzhiyun 			/*
407*4882a593Smuzhiyun 			 * kernel logo is transmitted to kernel to display, and
408*4882a593Smuzhiyun 			 * kernel will do the mirror operation, so skip kernel
409*4882a593Smuzhiyun 			 * logo here.
410*4882a593Smuzhiyun 			 */
411*4882a593Smuzhiyun 			if (panel->mirror && logo_type != EINK_LOGO_KERNEL) {
412*4882a593Smuzhiyun 				u32 w = panel->vir_width;
413*4882a593Smuzhiyun 				u32 h = panel->vir_height;
414*4882a593Smuzhiyun 				u32 mirror_buf = 0;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 				mirror_buf = get_addr_by_type(dev,
417*4882a593Smuzhiyun 							      EINK_LOGO_UNMIRROR_TEMP_BUF);
418*4882a593Smuzhiyun 				if (mirror_buf <= 0) {
419*4882a593Smuzhiyun 					printf("get mirror buffer failed\n");
420*4882a593Smuzhiyun 					return -EIO;
421*4882a593Smuzhiyun 				}
422*4882a593Smuzhiyun 				read_grayscale(dev_desc, &part, offset, size,
423*4882a593Smuzhiyun 					       (void *)((ulong)mirror_buf));
424*4882a593Smuzhiyun 				image_mirror((u8 *)((ulong)mirror_buf),
425*4882a593Smuzhiyun 					     (u8 *)((ulong)pic_buf), w, h);
426*4882a593Smuzhiyun 			} else if (panel->rearrange && logo_type != EINK_LOGO_KERNEL) {
427*4882a593Smuzhiyun 				u32 w = panel->vir_width;
428*4882a593Smuzhiyun 				u32 h = panel->vir_height;
429*4882a593Smuzhiyun 				u32 rearrange_buf = 0;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 				rearrange_buf = get_addr_by_type(dev,
432*4882a593Smuzhiyun 							      EINK_LOGO_UNMIRROR_TEMP_BUF);
433*4882a593Smuzhiyun 				if (rearrange_buf <= 0) {
434*4882a593Smuzhiyun 					printf("get mirror buffer failed\n");
435*4882a593Smuzhiyun 					return -EIO;
436*4882a593Smuzhiyun 				}
437*4882a593Smuzhiyun 				read_grayscale(dev_desc, &part, offset, size,
438*4882a593Smuzhiyun 					       (void *)((ulong)rearrange_buf));
439*4882a593Smuzhiyun 				image_rearrange((u8 *)((ulong)rearrange_buf),
440*4882a593Smuzhiyun 					     (u8 *)((ulong)pic_buf), w, h);
441*4882a593Smuzhiyun 			} else {
442*4882a593Smuzhiyun 				read_grayscale(dev_desc, &part, offset, size,
443*4882a593Smuzhiyun 					       (void *)((ulong)pic_buf));
444*4882a593Smuzhiyun 			}
445*4882a593Smuzhiyun 			flush_dcache_range((ulong)pic_buf,
446*4882a593Smuzhiyun 					   ALIGN((ulong)pic_buf + size,
447*4882a593Smuzhiyun 						 CONFIG_SYS_CACHELINE_SIZE));
448*4882a593Smuzhiyun 			*loaded_logo |= logo_type;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 			logo &= ~logo_type;
451*4882a593Smuzhiyun 			if (!logo)
452*4882a593Smuzhiyun 				break;
453*4882a593Smuzhiyun 		}
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	return 0;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
ebc_power_set(struct udevice * dev,int is_on)459*4882a593Smuzhiyun static int ebc_power_set(struct udevice *dev, int is_on)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	int ret;
462*4882a593Smuzhiyun 	struct rockchip_eink_display_priv *priv = dev_get_priv(dev);
463*4882a593Smuzhiyun 	struct ebc_panel *panel = dev_get_platdata(dev);
464*4882a593Smuzhiyun 	struct udevice *ebc_tcon_dev = priv->ebc_tcon_dev;
465*4882a593Smuzhiyun 	struct rk_ebc_tcon_ops *ebc_tcon_ops = ebc_tcon_get_ops(ebc_tcon_dev);
466*4882a593Smuzhiyun 	struct udevice *ebc_pwr_dev = priv->ebc_pwr_dev;
467*4882a593Smuzhiyun 	struct rk_ebc_pwr_ops *pwr_ops = ebc_pwr_get_ops(ebc_pwr_dev);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	if (is_on) {
470*4882a593Smuzhiyun 		ret = pwr_ops->power_on(ebc_pwr_dev);
471*4882a593Smuzhiyun 		if (ret) {
472*4882a593Smuzhiyun 			printf("%s, power on failed\n", __func__);
473*4882a593Smuzhiyun 			return -1;
474*4882a593Smuzhiyun 		}
475*4882a593Smuzhiyun 		ret = ebc_tcon_ops->enable(ebc_tcon_dev, panel);
476*4882a593Smuzhiyun 		if (ret) {
477*4882a593Smuzhiyun 			printf("%s, ebc tcon enabled failed\n", __func__);
478*4882a593Smuzhiyun 			return -1;
479*4882a593Smuzhiyun 		}
480*4882a593Smuzhiyun 	} else {
481*4882a593Smuzhiyun 		ret = ebc_tcon_ops->disable(ebc_tcon_dev);
482*4882a593Smuzhiyun 		if (ret) {
483*4882a593Smuzhiyun 			printf("%s, ebc tcon disable failed\n", __func__);
484*4882a593Smuzhiyun 			return -1;
485*4882a593Smuzhiyun 		}
486*4882a593Smuzhiyun 		ret = pwr_ops->power_down(ebc_pwr_dev);
487*4882a593Smuzhiyun 		if (ret) {
488*4882a593Smuzhiyun 			printf("%s, power_down failed\n", __func__);
489*4882a593Smuzhiyun 			return -1;
490*4882a593Smuzhiyun 		}
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 	return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
eink_display(struct udevice * dev,u32 pre_img_buf,u32 cur_img_buf,u32 lut_type,int update_mode)495*4882a593Smuzhiyun static int eink_display(struct udevice *dev, u32 pre_img_buf,
496*4882a593Smuzhiyun 			u32 cur_img_buf, u32 lut_type, int update_mode)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	u32 temperature, frame_num;
499*4882a593Smuzhiyun 	struct rockchip_eink_display_priv *priv = dev_get_priv(dev);
500*4882a593Smuzhiyun 	struct ebc_panel *plat = dev_get_platdata(dev);
501*4882a593Smuzhiyun 	struct epd_lut_ops *lut_ops = &plat->lut_ops;
502*4882a593Smuzhiyun 	struct udevice *ebc_pwr_dev = priv->ebc_pwr_dev;
503*4882a593Smuzhiyun 	struct rk_ebc_pwr_ops *pwr_ops = ebc_pwr_get_ops(ebc_pwr_dev);
504*4882a593Smuzhiyun 	struct udevice *ebc_tcon_dev = priv->ebc_tcon_dev;
505*4882a593Smuzhiyun 	struct rk_ebc_tcon_ops *ebc_tcon_ops = ebc_tcon_get_ops(ebc_tcon_dev);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	pwr_ops->temp_get(ebc_pwr_dev, &temperature);
508*4882a593Smuzhiyun 	if (temperature <= 0 || temperature > 50) {
509*4882a593Smuzhiyun 		printf("temperature = %d, out of range0~50 ,use 25\n",
510*4882a593Smuzhiyun 		       temperature);
511*4882a593Smuzhiyun 		temperature = 25;
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (!lut_ops->lut_get) {
515*4882a593Smuzhiyun 		printf("get lut ops failed\n");
516*4882a593Smuzhiyun 		return -EIO;
517*4882a593Smuzhiyun 	}
518*4882a593Smuzhiyun 	lut_ops->lut_get(&plat->lut_data, lut_type, temperature);
519*4882a593Smuzhiyun 	frame_num = plat->lut_data.frame_num;
520*4882a593Smuzhiyun 	debug("lut_type=%d, frame num=%d, temp=%d\n", lut_type,
521*4882a593Smuzhiyun 	      frame_num, temperature);
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	ebc_tcon_ops->wait_for_last_frame_complete(ebc_tcon_dev);
524*4882a593Smuzhiyun 	ebc_tcon_ops->lut_data_set(ebc_tcon_dev, plat->lut_data.data,
525*4882a593Smuzhiyun 				   frame_num, 0);
526*4882a593Smuzhiyun 	ebc_tcon_ops->dsp_mode_set(ebc_tcon_dev, update_mode,
527*4882a593Smuzhiyun 				   LUT_MODE, !THREE_WIN_MODE, !EINK_MODE);
528*4882a593Smuzhiyun 	ebc_tcon_ops->image_addr_set(ebc_tcon_dev, pre_img_buf, cur_img_buf);
529*4882a593Smuzhiyun 	ebc_tcon_ops->frame_start(ebc_tcon_dev, frame_num);
530*4882a593Smuzhiyun 	return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
rk_eink_display_init(void)533*4882a593Smuzhiyun static int rk_eink_display_init(void)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	int ret;
536*4882a593Smuzhiyun 	struct uclass *uc;
537*4882a593Smuzhiyun 	struct udevice *dev;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	if (eink_dev) {
540*4882a593Smuzhiyun 		printf("ebc-dev is already initialized!\n");
541*4882a593Smuzhiyun 		return 0;
542*4882a593Smuzhiyun 	}
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_EINK_DISPLAY, &uc);
545*4882a593Smuzhiyun 	if (ret) {
546*4882a593Smuzhiyun 		printf("can't find uclass eink\n");
547*4882a593Smuzhiyun 		return -ENODEV;
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun 	for (uclass_first_device(UCLASS_EINK_DISPLAY, &dev);
550*4882a593Smuzhiyun 	     dev; uclass_next_device(&dev))
551*4882a593Smuzhiyun 		;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	if (eink_dev) {
554*4882a593Smuzhiyun 		printf("ebc-dev is probed success!\n");
555*4882a593Smuzhiyun 		return 0;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 	printf("Can't find ebc-dev\n");
558*4882a593Smuzhiyun 	return -ENODEV;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun /*
562*4882a593Smuzhiyun  * Eink display need current and previous image buffer, We assume
563*4882a593Smuzhiyun  * every type of logo has only one image, so just tell this function
564*4882a593Smuzhiyun  * last logo type and current logo type, it will find the right images.
565*4882a593Smuzhiyun  * last_logo_type: -1 means it's first displaying.
566*4882a593Smuzhiyun  */
rockchip_eink_show_logo(int cur_logo_type,int update_mode)567*4882a593Smuzhiyun static int rockchip_eink_show_logo(int cur_logo_type, int update_mode)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	int ret = 0;
570*4882a593Smuzhiyun 	u32 logo_addr;
571*4882a593Smuzhiyun 	u32 last_logo_addr;
572*4882a593Smuzhiyun 	struct ebc_panel *plat;
573*4882a593Smuzhiyun 	struct udevice *dev;
574*4882a593Smuzhiyun 	static u32 loaded_logo = 0;
575*4882a593Smuzhiyun 	struct rockchip_eink_display_priv *priv;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	if (!eink_dev) {
578*4882a593Smuzhiyun 		static bool first_init = true;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 		if (first_init) {
581*4882a593Smuzhiyun 			first_init = false;
582*4882a593Smuzhiyun 			ret = rk_eink_display_init();
583*4882a593Smuzhiyun 			if (ret) {
584*4882a593Smuzhiyun 				printf("Get ebc dev failed, check dts\n");
585*4882a593Smuzhiyun 				return -ENODEV;
586*4882a593Smuzhiyun 			}
587*4882a593Smuzhiyun 		} else {
588*4882a593Smuzhiyun 			return -ENODEV;
589*4882a593Smuzhiyun 		}
590*4882a593Smuzhiyun 	}
591*4882a593Smuzhiyun 	dev = eink_dev;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	/*Don't need to update display*/
594*4882a593Smuzhiyun 	if (last_logo_type == cur_logo_type) {
595*4882a593Smuzhiyun 		debug("Same as last picture, Don't need to display\n");
596*4882a593Smuzhiyun 		return 0;
597*4882a593Smuzhiyun 	}
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	plat = dev_get_platdata(dev);
600*4882a593Smuzhiyun 	priv = dev_get_priv(dev);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	/*
603*4882a593Smuzhiyun 	 * The last_logo_type is -1 means it's first displaying
604*4882a593Smuzhiyun 	 */
605*4882a593Smuzhiyun 	if (last_logo_type == -1) {
606*4882a593Smuzhiyun 		ret = ebc_power_set(dev, EBC_PWR_ON);
607*4882a593Smuzhiyun 		if (ret) {
608*4882a593Smuzhiyun 			printf("Eink power on failed\n");
609*4882a593Smuzhiyun 			return -1;
610*4882a593Smuzhiyun 		}
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 		int size = (plat->vir_width * plat->vir_height) >> 1;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 		logo_addr = get_addr_by_type(dev, EINK_LOGO_RESET);
615*4882a593Smuzhiyun 		memset((u32 *)(u64)logo_addr, 0xff, size);
616*4882a593Smuzhiyun 		flush_dcache_range((ulong)logo_addr,
617*4882a593Smuzhiyun 				   ALIGN((ulong)logo_addr + size,
618*4882a593Smuzhiyun 					 CONFIG_SYS_CACHELINE_SIZE));
619*4882a593Smuzhiyun 		eink_display(dev, logo_addr, logo_addr,
620*4882a593Smuzhiyun 			     WF_TYPE_RESET, EINK_LOGO_RESET);
621*4882a593Smuzhiyun 		last_logo_type = 0;
622*4882a593Smuzhiyun 		last_logo_addr = logo_addr;
623*4882a593Smuzhiyun 	} else {
624*4882a593Smuzhiyun 		last_logo_addr = get_addr_by_type(dev, last_logo_type);
625*4882a593Smuzhiyun 		if (last_logo_addr < 0) {
626*4882a593Smuzhiyun 			printf("Invalid last logo addr, exit!\n");
627*4882a593Smuzhiyun 			goto out;
628*4882a593Smuzhiyun 		}
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 	ret = read_needed_logo_from_partition(dev, cur_logo_type,
631*4882a593Smuzhiyun 					      &loaded_logo);
632*4882a593Smuzhiyun 	if (ret || !(loaded_logo & cur_logo_type)) {
633*4882a593Smuzhiyun 		printf("read logo[0x%x] failed, loaded_logo=0x%x\n",
634*4882a593Smuzhiyun 		       cur_logo_type, loaded_logo);
635*4882a593Smuzhiyun 		ret = -EIO;
636*4882a593Smuzhiyun 		goto out;
637*4882a593Smuzhiyun 	}
638*4882a593Smuzhiyun 	logo_addr = get_addr_by_type(dev, cur_logo_type);
639*4882a593Smuzhiyun 	debug("logo_addr=%x, logo_type=%d\n", logo_addr, cur_logo_type);
640*4882a593Smuzhiyun 	if (logo_addr <= 0) {
641*4882a593Smuzhiyun 		printf("get logo buffer failed\n");
642*4882a593Smuzhiyun 		ret = -EIO;
643*4882a593Smuzhiyun 		goto out;
644*4882a593Smuzhiyun 	}
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	eink_display(dev, last_logo_addr, logo_addr, WF_TYPE_GC16, update_mode);
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	if (priv->backlight)
649*4882a593Smuzhiyun 		backlight_enable(priv->backlight);
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	last_logo_type = cur_logo_type;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	if (cur_logo_type == EINK_LOGO_POWEROFF) {
654*4882a593Smuzhiyun 		struct udevice *ebc_tcon_dev = priv->ebc_tcon_dev;
655*4882a593Smuzhiyun 		struct rk_ebc_tcon_ops *ebc_tcon_ops;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 		last_logo_type = -1;
658*4882a593Smuzhiyun 		/*
659*4882a593Smuzhiyun 		 * For normal logo display, waiting for the last frame
660*4882a593Smuzhiyun 		 * completion before start a new frame, except one
661*4882a593Smuzhiyun 		 * situation which charging logo display finished,
662*4882a593Smuzhiyun 		 * because device will rebooting or shutdown after
663*4882a593Smuzhiyun 		 * charging logo is competed.
664*4882a593Smuzhiyun 		 *
665*4882a593Smuzhiyun 		 * We should take care of the power sequence,
666*4882a593Smuzhiyun 		 * because ebc can't power off if last frame
667*4882a593Smuzhiyun 		 * data is still sending, so keep the ebc power
668*4882a593Smuzhiyun 		 * during u-boot phase and shutdown the
669*4882a593Smuzhiyun 		 * power only if uboot charging is finished.
670*4882a593Smuzhiyun 		 */
671*4882a593Smuzhiyun 		ebc_tcon_ops = ebc_tcon_get_ops(ebc_tcon_dev);
672*4882a593Smuzhiyun 		ebc_tcon_ops->wait_for_last_frame_complete(ebc_tcon_dev);
673*4882a593Smuzhiyun 		debug("charging logo displaying is complete\n");
674*4882a593Smuzhiyun 		/*
675*4882a593Smuzhiyun 		 *shutdown ebc after charging logo display is complete
676*4882a593Smuzhiyun 		 */
677*4882a593Smuzhiyun 		ret = ebc_power_set(dev, EBC_PWR_DOWN);
678*4882a593Smuzhiyun 		if (ret)
679*4882a593Smuzhiyun 			printf("Eink power down failed\n");
680*4882a593Smuzhiyun 		goto out;
681*4882a593Smuzhiyun 	}
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	/*
684*4882a593Smuzhiyun 	 * System will boot up to kernel only when the
685*4882a593Smuzhiyun 	 * logo is uboot logo
686*4882a593Smuzhiyun 	 */
687*4882a593Smuzhiyun 	if (cur_logo_type == EINK_LOGO_UBOOT) {
688*4882a593Smuzhiyun 		char logo_args[64] = {0};
689*4882a593Smuzhiyun 		u32 uboot_logo_buf;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 		if (plat->mirror || plat->rearrange)
692*4882a593Smuzhiyun 			uboot_logo_buf = get_addr_by_type(dev,
693*4882a593Smuzhiyun 							  EINK_LOGO_UNMIRROR_TEMP_BUF);
694*4882a593Smuzhiyun 		else
695*4882a593Smuzhiyun 			uboot_logo_buf = logo_addr;
696*4882a593Smuzhiyun 		printf("Transmit uboot logo addr(0x%x) to kernel\n",
697*4882a593Smuzhiyun 		       uboot_logo_buf);
698*4882a593Smuzhiyun 		sprintf(logo_args, "ulogo_addr=0x%x", uboot_logo_buf);
699*4882a593Smuzhiyun 		env_update("bootargs", logo_args);
700*4882a593Smuzhiyun 		ret = read_needed_logo_from_partition(dev, EINK_LOGO_KERNEL,
701*4882a593Smuzhiyun 						      &loaded_logo);
702*4882a593Smuzhiyun 		if (ret || !(loaded_logo & EINK_LOGO_KERNEL)) {
703*4882a593Smuzhiyun 			printf("No invalid kernel logo in logo.img\n");
704*4882a593Smuzhiyun 		} else {
705*4882a593Smuzhiyun 			int klogo_addr = get_addr_by_type(dev,
706*4882a593Smuzhiyun 							  EINK_LOGO_KERNEL);
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 			if (klogo_addr <= 0) {
709*4882a593Smuzhiyun 				printf("get kernel logo buffer failed\n");
710*4882a593Smuzhiyun 				ret = -EIO;
711*4882a593Smuzhiyun 				goto out;
712*4882a593Smuzhiyun 			}
713*4882a593Smuzhiyun 			printf("Transmit kernel logo addr(0x%x) to kernel\n",
714*4882a593Smuzhiyun 			       klogo_addr);
715*4882a593Smuzhiyun 			sprintf(logo_args, "klogo_addr=0x%x", klogo_addr);
716*4882a593Smuzhiyun 			env_update("bootargs", logo_args);
717*4882a593Smuzhiyun 		}
718*4882a593Smuzhiyun 	}
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun out:
721*4882a593Smuzhiyun 	return ret;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun 
rockchip_eink_show_uboot_logo(void)724*4882a593Smuzhiyun int rockchip_eink_show_uboot_logo(void)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun 	return rockchip_eink_show_logo(EINK_LOGO_UBOOT, EINK_UPDATE_DIFF);
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun 
rockchip_eink_show_charge_logo(int logo_type)729*4882a593Smuzhiyun int rockchip_eink_show_charge_logo(int logo_type)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun 	return rockchip_eink_show_logo(logo_type, EINK_UPDATE_DIFF);
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
rockchip_eink_display_probe(struct udevice * dev)734*4882a593Smuzhiyun static int rockchip_eink_display_probe(struct udevice *dev)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun 	int ret, vcom, size, i;
737*4882a593Smuzhiyun 	const fdt32_t *list;
738*4882a593Smuzhiyun 	uint32_t phandle;
739*4882a593Smuzhiyun 	struct rockchip_eink_display_priv *priv = dev_get_priv(dev);
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	/* Before relocation we don't need to do anything */
742*4882a593Smuzhiyun 	if (!(gd->flags & GD_FLG_RELOC))
743*4882a593Smuzhiyun 		return 0;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	ret = uclass_get_device_by_phandle(UCLASS_EBC, dev,
746*4882a593Smuzhiyun 					   "ebc_tcon",
747*4882a593Smuzhiyun 					   &priv->ebc_tcon_dev);
748*4882a593Smuzhiyun 	if (ret) {
749*4882a593Smuzhiyun 		dev_err(dev, "Cannot get ebc_tcon: %d\n", ret);
750*4882a593Smuzhiyun 		return ret;
751*4882a593Smuzhiyun 	}
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	list = dev_read_prop(dev, "pmic", &size);
754*4882a593Smuzhiyun 	if (!list) {
755*4882a593Smuzhiyun 		dev_err(dev, "Cannot get pmic prop\n");
756*4882a593Smuzhiyun 		return -EINVAL;
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	size /= sizeof(*list);
760*4882a593Smuzhiyun 	for (i = 0; i < size; i++) {
761*4882a593Smuzhiyun 		phandle = fdt32_to_cpu(*list++);
762*4882a593Smuzhiyun 		ret = uclass_get_device_by_phandle_id(UCLASS_I2C_GENERIC,
763*4882a593Smuzhiyun 						      phandle,
764*4882a593Smuzhiyun 						      &priv->ebc_pwr_dev);
765*4882a593Smuzhiyun 		if (!ret) {
766*4882a593Smuzhiyun 			printf("Eink: use pmic %s\n", priv->ebc_pwr_dev->name);
767*4882a593Smuzhiyun 			break;
768*4882a593Smuzhiyun 		}
769*4882a593Smuzhiyun 	}
770*4882a593Smuzhiyun 	if (ret) {
771*4882a593Smuzhiyun 		dev_err(dev, "Cannot get pmic: %d\n", ret);
772*4882a593Smuzhiyun 		return ret;
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
776*4882a593Smuzhiyun 					   "backlight", &priv->backlight);
777*4882a593Smuzhiyun 	if (ret && ret != -ENOENT) {
778*4882a593Smuzhiyun 		printf("%s: Cannot get backlight: %d\n", __func__, ret);
779*4882a593Smuzhiyun 	}
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	vcom = read_vcom_from_vendor();
782*4882a593Smuzhiyun 	if (vcom <= 0) {
783*4882a593Smuzhiyun 		printf("read vcom from vendor failed, use default vcom\n");
784*4882a593Smuzhiyun 		priv->vcom = VCOM_DEFAULT_VALUE;
785*4882a593Smuzhiyun 	} else {
786*4882a593Smuzhiyun 		priv->vcom = vcom;
787*4882a593Smuzhiyun 	}
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	if (priv->ebc_pwr_dev) {
790*4882a593Smuzhiyun 		struct rk_ebc_pwr_ops *pwr_ops;
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 		pwr_ops = ebc_pwr_get_ops(priv->ebc_pwr_dev);
793*4882a593Smuzhiyun 		ret = pwr_ops->vcom_set(priv->ebc_pwr_dev, priv->vcom);
794*4882a593Smuzhiyun 		if (ret) {
795*4882a593Smuzhiyun 			printf("%s, vcom_set failed\n", __func__);
796*4882a593Smuzhiyun 			return -EIO;
797*4882a593Smuzhiyun 		}
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	// read lut to ram, and get lut ops
801*4882a593Smuzhiyun 	ret = read_waveform(dev);
802*4882a593Smuzhiyun 	if (ret < 0) {
803*4882a593Smuzhiyun 		printf("read wavform failed\n");
804*4882a593Smuzhiyun 		return -EIO;
805*4882a593Smuzhiyun 	}
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	eink_dev = dev;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	return 0;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun 
rockchip_eink_display_ofdata_to_platdata(struct udevice * dev)812*4882a593Smuzhiyun static int rockchip_eink_display_ofdata_to_platdata(struct udevice *dev)
813*4882a593Smuzhiyun {
814*4882a593Smuzhiyun 	fdt_size_t size;
815*4882a593Smuzhiyun 	fdt_addr_t tmp_addr;
816*4882a593Smuzhiyun 	struct device_node *disp_mem;
817*4882a593Smuzhiyun 	struct device_node *waveform_mem;
818*4882a593Smuzhiyun 	struct ebc_panel *plat = dev_get_platdata(dev);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	plat->width = dev_read_u32_default(dev, "panel,width", 0);
821*4882a593Smuzhiyun 	plat->height = dev_read_u32_default(dev, "panel,height", 0);
822*4882a593Smuzhiyun 	plat->vir_width = dev_read_u32_default(dev, "panel,vir_width", plat->width);
823*4882a593Smuzhiyun 	plat->vir_height = dev_read_u32_default(dev, "panel,vir_height", plat->height);
824*4882a593Smuzhiyun 	plat->sdck = dev_read_u32_default(dev, "panel,sdck", 0);
825*4882a593Smuzhiyun 	plat->lsl = dev_read_u32_default(dev, "panel,lsl", 0);
826*4882a593Smuzhiyun 	plat->lbl = dev_read_u32_default(dev, "panel,lbl", 0);
827*4882a593Smuzhiyun 	plat->ldl = dev_read_u32_default(dev, "panel,ldl", 0);
828*4882a593Smuzhiyun 	plat->lel = dev_read_u32_default(dev, "panel,lel", 0);
829*4882a593Smuzhiyun 	plat->gdck_sta = dev_read_u32_default(dev, "panel,gdck-sta", 0);
830*4882a593Smuzhiyun 	plat->lgonl = dev_read_u32_default(dev, "panel,lgonl", 0);
831*4882a593Smuzhiyun 	plat->fsl = dev_read_u32_default(dev, "panel,fsl", 0);
832*4882a593Smuzhiyun 	plat->fbl = dev_read_u32_default(dev, "panel,fbl", 0);
833*4882a593Smuzhiyun 	plat->fdl = dev_read_u32_default(dev, "panel,fdl", 0);
834*4882a593Smuzhiyun 	plat->fel = dev_read_u32_default(dev, "panel,fel", 0);
835*4882a593Smuzhiyun 	plat->panel_16bit = dev_read_u32_default(dev, "panel,panel_16bit", 0);
836*4882a593Smuzhiyun 	plat->panel_color = dev_read_u32_default(dev, "panel,panel_color", 0);
837*4882a593Smuzhiyun 	plat->mirror = dev_read_u32_default(dev, "panel,mirror", 0);
838*4882a593Smuzhiyun 	plat->rearrange = dev_read_u32_default(dev, "panel,rearrange", 0);
839*4882a593Smuzhiyun 	plat->width_mm = dev_read_u32_default(dev, "panel,width-mm", 0);
840*4882a593Smuzhiyun 	plat->height_mm = dev_read_u32_default(dev, "panel,height-mm", 0);
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	disp_mem = of_parse_phandle(ofnode_to_np(dev_ofnode(dev)),
843*4882a593Smuzhiyun 				    "memory-region", 0);
844*4882a593Smuzhiyun 	if (!disp_mem) {
845*4882a593Smuzhiyun 		dev_err(dev, "Cannot get memory-region from dts\n");
846*4882a593Smuzhiyun 		return -ENODEV;
847*4882a593Smuzhiyun 	}
848*4882a593Smuzhiyun 	tmp_addr = ofnode_get_addr_size(np_to_ofnode(disp_mem), "reg", &size);
849*4882a593Smuzhiyun 	if (tmp_addr == FDT_ADDR_T_NONE) {
850*4882a593Smuzhiyun 		printf("get display memory address failed\n");
851*4882a593Smuzhiyun 		return -ENODEV;
852*4882a593Smuzhiyun 	}
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	plat->disp_pbuf = (u64)map_sysmem(tmp_addr, 0);
855*4882a593Smuzhiyun 	plat->disp_pbuf_size = size;
856*4882a593Smuzhiyun 	debug("display mem=0x%x, size=%x\n", plat->disp_pbuf,
857*4882a593Smuzhiyun 	      plat->disp_pbuf_size);
858*4882a593Smuzhiyun 	waveform_mem = of_parse_phandle(ofnode_to_np(dev_ofnode(dev)),
859*4882a593Smuzhiyun 					"waveform-region", 0);
860*4882a593Smuzhiyun 	if (!waveform_mem) {
861*4882a593Smuzhiyun 		printf("Cannot get waveform-region from dts\n");
862*4882a593Smuzhiyun 		return -ENODEV;
863*4882a593Smuzhiyun 	}
864*4882a593Smuzhiyun 	tmp_addr = ofnode_get_addr_size(np_to_ofnode(waveform_mem),
865*4882a593Smuzhiyun 					"reg", &size);
866*4882a593Smuzhiyun 	if (tmp_addr == FDT_ADDR_T_NONE) {
867*4882a593Smuzhiyun 		printf("get waveform memory address failed\n");
868*4882a593Smuzhiyun 		return -ENODEV;
869*4882a593Smuzhiyun 	}
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	plat->lut_pbuf = map_sysmem(tmp_addr, 0);
872*4882a593Smuzhiyun 	plat->lut_pbuf_size = size;
873*4882a593Smuzhiyun 	debug("lut mem=0x%p, size=%x\n", plat->lut_pbuf, plat->lut_pbuf_size);
874*4882a593Smuzhiyun 	return 0;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun static const struct udevice_id rockchip_eink_display_ids[] = {
878*4882a593Smuzhiyun 	{ .compatible = "rockchip,ebc-dev", },
879*4882a593Smuzhiyun 	{}
880*4882a593Smuzhiyun };
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun U_BOOT_DRIVER(rk_eink_display) = {
883*4882a593Smuzhiyun 	.name = "rockchip_eink_display",
884*4882a593Smuzhiyun 	.id = UCLASS_EINK_DISPLAY,
885*4882a593Smuzhiyun 	.of_match = rockchip_eink_display_ids,
886*4882a593Smuzhiyun 	.ofdata_to_platdata = rockchip_eink_display_ofdata_to_platdata,
887*4882a593Smuzhiyun 	.probe = rockchip_eink_display_probe,
888*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct rockchip_eink_display_priv),
889*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct ebc_panel),
890*4882a593Smuzhiyun };
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun UCLASS_DRIVER(rk_eink) = {
893*4882a593Smuzhiyun 	.id	= UCLASS_EINK_DISPLAY,
894*4882a593Smuzhiyun 	.name	= "rk_eink",
895*4882a593Smuzhiyun };
896*4882a593Smuzhiyun 
897