193a7515aSWenping Zhang /* 293a7515aSWenping Zhang * (C) Copyright 2020 Rockchip Electronics Co., Ltd 393a7515aSWenping Zhang * 493a7515aSWenping Zhang * SPDX-License-Identifier: GPL-2.0+ 593a7515aSWenping Zhang * Author: Wenping Zhang <wenping.zhang@rock-chips.com> 693a7515aSWenping Zhang */ 793a7515aSWenping Zhang #include <common.h> 893a7515aSWenping Zhang #include <dm.h> 993a7515aSWenping Zhang #include <stdio.h> 1093a7515aSWenping Zhang #include <errno.h> 1193a7515aSWenping Zhang #include <mapmem.h> 1293a7515aSWenping Zhang #include <stdlib.h> 1393a7515aSWenping Zhang #include <asm/arch/vendor.h> 1493a7515aSWenping Zhang #include <dm/of_access.h> 1593a7515aSWenping Zhang #include <dm/uclass.h> 1693a7515aSWenping Zhang #include <dm/uclass-id.h> 1793a7515aSWenping Zhang #include <boot_rkimg.h> 1893a7515aSWenping Zhang #include <rk_eink.h> 193f41a942SWeixin Zhou #include <backlight.h> 2093a7515aSWenping Zhang #include "rk_ebc.h" 2193a7515aSWenping Zhang #include "epdlut/epd_lut.h" 2293a7515aSWenping Zhang 2393a7515aSWenping Zhang #define PART_WAVEFORM "waveform" 2493a7515aSWenping Zhang #define EINK_LOGO_PART_MAGIC "RKEL" 2593a7515aSWenping Zhang #define EINK_LOGO_IMAGE_MAGIC "GR04" 2693a7515aSWenping Zhang /* 2793a7515aSWenping Zhang * grayscale logo partition format: 2893a7515aSWenping Zhang * block0: 2993a7515aSWenping Zhang * struct logo_part_header part_header; 3093a7515aSWenping Zhang * struct grayscale_header logo1_header; 3193a7515aSWenping Zhang * struct grayscale_header logo2_header; 3293a7515aSWenping Zhang * struct grayscale_header logo3_header; 3393a7515aSWenping Zhang * struct grayscale_header logo4_header; 3493a7515aSWenping Zhang * .... 3593a7515aSWenping Zhang * 3693a7515aSWenping Zhang * block 1: 3793a7515aSWenping Zhang * logo1_image 3893a7515aSWenping Zhang * 3993a7515aSWenping Zhang * ..... 4093a7515aSWenping Zhang * block m: 4193a7515aSWenping Zhang * logo2_image 4293a7515aSWenping Zhang * 4393a7515aSWenping Zhang * ........ 4493a7515aSWenping Zhang * block n: 4593a7515aSWenping Zhang * logo3_image 4693a7515aSWenping Zhang * 4793a7515aSWenping Zhang * ........ 4893a7515aSWenping Zhang * block i: 4993a7515aSWenping Zhang * logoi_image 5093a7515aSWenping Zhang */ 5193a7515aSWenping Zhang 5293a7515aSWenping Zhang //logo partition Header, 64byte 5393a7515aSWenping Zhang struct logo_part_header { 5493a7515aSWenping Zhang char magic[4]; /* must be "RKEL" */ 5593a7515aSWenping Zhang u32 totoal_size; 5693a7515aSWenping Zhang u32 screen_width; 5793a7515aSWenping Zhang u32 screen_height; 5893a7515aSWenping Zhang u32 logo_count; 5993a7515aSWenping Zhang u8 version[4]; 6093a7515aSWenping Zhang u32 rsv[10]; 6193a7515aSWenping Zhang } __packed; 6293a7515aSWenping Zhang 6393a7515aSWenping Zhang // logo image header,32 byte 6493a7515aSWenping Zhang struct grayscale_header { 6593a7515aSWenping Zhang char magic[4]; /* must be "GR04" */ 6693a7515aSWenping Zhang u16 x; 6793a7515aSWenping Zhang u16 y; 6893a7515aSWenping Zhang u16 w; 6993a7515aSWenping Zhang u16 h; 7093a7515aSWenping Zhang u32 logo_type; 7193a7515aSWenping Zhang u32 data_offset; /* image offset in byte */ 7293a7515aSWenping Zhang u32 data_size; /* image size in byte */ 7393a7515aSWenping Zhang u32 rsv[2]; 7493a7515aSWenping Zhang } __packed; 7593a7515aSWenping Zhang 7693a7515aSWenping Zhang /* 7793a7515aSWenping Zhang * The start address of logo image in logo.img must be aligned in 512 bytes, 7893a7515aSWenping Zhang * so the header size must be times of 512 bytes. Here we fix the size to 512 7993a7515aSWenping Zhang * bytes, so the count of logo image can only support up to 14. 8093a7515aSWenping Zhang */ 8193a7515aSWenping Zhang struct logo_info { 8293a7515aSWenping Zhang struct logo_part_header part_hdr; 8393a7515aSWenping Zhang struct grayscale_header img_hdr[14]; 8493a7515aSWenping Zhang } __packed; 8593a7515aSWenping Zhang 8693a7515aSWenping Zhang struct rockchip_eink_display_priv { 8793a7515aSWenping Zhang struct udevice *dev; 8893a7515aSWenping Zhang struct udevice *ebc_tcon_dev; 8993a7515aSWenping Zhang struct udevice *ebc_pwr_dev; 9093a7515aSWenping Zhang int vcom; 913f41a942SWeixin Zhou struct udevice *backlight; 9293a7515aSWenping Zhang }; 9393a7515aSWenping Zhang 9493a7515aSWenping Zhang enum { 9593a7515aSWenping Zhang EBC_PWR_DOWN = 0, 9693a7515aSWenping Zhang EBC_PWR_ON = 1, 9793a7515aSWenping Zhang }; 9893a7515aSWenping Zhang 9993a7515aSWenping Zhang #define EINK_VCOM_ID 17 10093a7515aSWenping Zhang #define EINK_VCOM_MAX 64 10193a7515aSWenping Zhang #define VCOM_DEFAULT_VALUE 1650 10293a7515aSWenping Zhang 10393a7515aSWenping Zhang static struct logo_info eink_logo_info; 10493a7515aSWenping Zhang static struct udevice *eink_dev; 10593a7515aSWenping Zhang static volatile int last_logo_type = -1; 10693a7515aSWenping Zhang static int read_vcom_from_vendor(void) 10793a7515aSWenping Zhang { 10893a7515aSWenping Zhang int ret = 0; 10993a7515aSWenping Zhang char vcom_str[EINK_VCOM_MAX] = {0}; 11093a7515aSWenping Zhang char vcom_args[EINK_VCOM_MAX] = {0}; 11193a7515aSWenping Zhang 11293a7515aSWenping Zhang /* Read vcom value from vendor storage part */ 11393a7515aSWenping Zhang ret = vendor_storage_read(EINK_VCOM_ID, vcom_str, (EINK_VCOM_MAX - 1)); 11493a7515aSWenping Zhang if (ret > 0) { 115cd44409eSZorro Liu snprintf(vcom_args, strlen(vcom_str) + 15, "ebc_pmic.vcom=%s", vcom_str); 11693a7515aSWenping Zhang printf("eink update bootargs: %s\n", vcom_args); 11793a7515aSWenping Zhang env_update("bootargs", vcom_args); 11893a7515aSWenping Zhang } else { 11993a7515aSWenping Zhang return ret; 12093a7515aSWenping Zhang } 12193a7515aSWenping Zhang 12293a7515aSWenping Zhang return atoi(vcom_str); 12393a7515aSWenping Zhang } 12493a7515aSWenping Zhang 12593a7515aSWenping Zhang static int read_waveform(struct udevice *dev) 12693a7515aSWenping Zhang { 12793a7515aSWenping Zhang int cnt, start, ret; 12893a7515aSWenping Zhang disk_partition_t part; 12993a7515aSWenping Zhang struct blk_desc *dev_desc; 13093a7515aSWenping Zhang struct ebc_panel *plat = dev_get_platdata(dev); 13193a7515aSWenping Zhang 13293a7515aSWenping Zhang dev_desc = rockchip_get_bootdev(); 13393a7515aSWenping Zhang if (!dev_desc) { 13493a7515aSWenping Zhang printf("%s: Could not find device\n", __func__); 13593a7515aSWenping Zhang return -EIO; 13693a7515aSWenping Zhang } 13793a7515aSWenping Zhang if (part_get_info_by_name(dev_desc, PART_WAVEFORM, &part) < 0) { 13893a7515aSWenping Zhang printf("Get waveform partition failed\n"); 13993a7515aSWenping Zhang return -ENODEV; 14093a7515aSWenping Zhang } 14193a7515aSWenping Zhang cnt = plat->lut_pbuf_size / RK_BLK_SIZE; 14293a7515aSWenping Zhang start = part.start; 14393a7515aSWenping Zhang ret = blk_dread(dev_desc, start, cnt, (void *)plat->lut_pbuf); 14493a7515aSWenping Zhang if (ret != cnt) 14593a7515aSWenping Zhang printf("Try to read %d blocks failed, only read %d\n", 14693a7515aSWenping Zhang cnt, ret); 14793a7515aSWenping Zhang 14893a7515aSWenping Zhang flush_dcache_range((ulong)plat->lut_pbuf, 14993a7515aSWenping Zhang ALIGN((ulong)plat->lut_pbuf + cnt, 15093a7515aSWenping Zhang CONFIG_SYS_CACHELINE_SIZE)); 15193a7515aSWenping Zhang ret = epd_lut_from_mem_init(plat->lut_pbuf, &plat->lut_ops); 15293a7515aSWenping Zhang if (ret < 0) { 15393a7515aSWenping Zhang printf("lut init failed\n"); 15493a7515aSWenping Zhang return -EINVAL; 15593a7515aSWenping Zhang } 15693a7515aSWenping Zhang 15793a7515aSWenping Zhang return 0; 15893a7515aSWenping Zhang } 15993a7515aSWenping Zhang 16093a7515aSWenping Zhang static u32 aligned_image_size_4k(struct udevice *dev) 16193a7515aSWenping Zhang { 16293a7515aSWenping Zhang struct ebc_panel *plat = dev_get_platdata(dev); 1639876686dSWenping Zhang u32 w = plat->vir_width; 1649876686dSWenping Zhang u32 h = plat->vir_height; 16593a7515aSWenping Zhang 16693a7515aSWenping Zhang return ALIGN((w * h) >> 1, 4096); 16793a7515aSWenping Zhang } 16893a7515aSWenping Zhang 16993a7515aSWenping Zhang /* 17093a7515aSWenping Zhang * This driver load the grayscale image from flash, 17193a7515aSWenping Zhang * and put it in the reserve memory which define in dts: 17293a7515aSWenping Zhang * display_reserved: framebuffer@10000000 { 17393a7515aSWenping Zhang * reg = <0x0 0x10000000 0x0 0x2000000>; 17493a7515aSWenping Zhang * no-map; 17593a7515aSWenping Zhang * }; 17693a7515aSWenping Zhang * Every image logo size must be aligned in 4K, make sure 17793a7515aSWenping Zhang * kernel can use it rightly, the buffer of LOGO image is 17893a7515aSWenping Zhang * put in order of below map: 179e79e2085SWenping Zhang * |---reset logo ---| 18093a7515aSWenping Zhang * |---uboot logo ---| 18193a7515aSWenping Zhang * |---kernel logo ---| 18293a7515aSWenping Zhang * |---charge_0 logo ---| 18393a7515aSWenping Zhang * |---charge_1 logo ---| 18493a7515aSWenping Zhang * |---charge_2 logo ---| 18593a7515aSWenping Zhang * |---charge_3 logo ---| 18693a7515aSWenping Zhang * |---charge_4 logo ---| 18793a7515aSWenping Zhang * |---charge_5 logo ---| 18893a7515aSWenping Zhang * |---battery low logo---| 1894f14f98fSWenping Zhang * |---temp un-mirror buffer--| 19093a7515aSWenping Zhang */ 19193a7515aSWenping Zhang static int get_addr_by_type(struct udevice *dev, u32 logo_type) 19293a7515aSWenping Zhang { 19393a7515aSWenping Zhang u32 offset, indx, img_size; 19493a7515aSWenping Zhang struct ebc_panel *plat = dev_get_platdata(dev); 19593a7515aSWenping Zhang 19693a7515aSWenping Zhang if (plat->disp_pbuf_size == 0 || !plat->disp_pbuf) { 19793a7515aSWenping Zhang printf("invalid display buffer, please check dts\n"); 19893a7515aSWenping Zhang return -EINVAL; 19993a7515aSWenping Zhang } 200e79e2085SWenping Zhang indx = ffs(logo_type); 20193a7515aSWenping Zhang img_size = aligned_image_size_4k(dev); 20293a7515aSWenping Zhang offset = img_size * indx; 20393a7515aSWenping Zhang if (offset + img_size > plat->disp_pbuf_size) { 20493a7515aSWenping Zhang printf("reserve display memory size is not enough\n"); 20593a7515aSWenping Zhang return -EINVAL; 20693a7515aSWenping Zhang } 20793a7515aSWenping Zhang 20893a7515aSWenping Zhang switch (logo_type) { 209e79e2085SWenping Zhang case EINK_LOGO_RESET: 21093a7515aSWenping Zhang case EINK_LOGO_UBOOT: 21193a7515aSWenping Zhang case EINK_LOGO_KERNEL: 21293a7515aSWenping Zhang case EINK_LOGO_CHARGING_0: 21393a7515aSWenping Zhang case EINK_LOGO_CHARGING_1: 21493a7515aSWenping Zhang case EINK_LOGO_CHARGING_2: 21593a7515aSWenping Zhang case EINK_LOGO_CHARGING_3: 21693a7515aSWenping Zhang case EINK_LOGO_CHARGING_4: 21793a7515aSWenping Zhang case EINK_LOGO_CHARGING_5: 21893a7515aSWenping Zhang case EINK_LOGO_CHARGING_LOWPOWER: 219*77bac292SZorro Liu case EINK_LOGO_POWEROFF: 2204f14f98fSWenping Zhang /* 2214f14f98fSWenping Zhang * The MIRROR_TEMP_BUF is used to save the 2224f14f98fSWenping Zhang * non-mirror image data. 2234f14f98fSWenping Zhang */ 2244f14f98fSWenping Zhang case EINK_LOGO_UNMIRROR_TEMP_BUF: 22593a7515aSWenping Zhang return (plat->disp_pbuf + offset); 22693a7515aSWenping Zhang default: 22793a7515aSWenping Zhang printf("invalid logo type[%d]\n", logo_type); 22893a7515aSWenping Zhang } 22993a7515aSWenping Zhang 23093a7515aSWenping Zhang return -EINVAL; 23193a7515aSWenping Zhang } 23293a7515aSWenping Zhang 23393a7515aSWenping Zhang static int read_header(struct blk_desc *dev_desc, 23493a7515aSWenping Zhang disk_partition_t *part, 23593a7515aSWenping Zhang struct logo_info *header) 23693a7515aSWenping Zhang { 23793a7515aSWenping Zhang int i; 23893a7515aSWenping Zhang struct logo_part_header *part_hdr = &header->part_hdr; 23993a7515aSWenping Zhang 24093a7515aSWenping Zhang if (blk_dread(dev_desc, part->start, 1, header) != 1) 24193a7515aSWenping Zhang return -EIO; 24293a7515aSWenping Zhang 24393a7515aSWenping Zhang if (memcmp(part_hdr->magic, EINK_LOGO_PART_MAGIC, 4)) { 24493a7515aSWenping Zhang printf("partition header is invalid\n"); 24593a7515aSWenping Zhang return -EINVAL; 24693a7515aSWenping Zhang } 24793a7515aSWenping Zhang if (part_hdr->logo_count == 0) { 24893a7515aSWenping Zhang printf("the count of logo image is 0\n"); 24993a7515aSWenping Zhang return -EINVAL; 25093a7515aSWenping Zhang } 25193a7515aSWenping Zhang for (i = 0; i < part_hdr->logo_count; i++) { 25293a7515aSWenping Zhang struct grayscale_header *img_hdr = &header->img_hdr[i]; 25393a7515aSWenping Zhang 25493a7515aSWenping Zhang if (memcmp(img_hdr->magic, EINK_LOGO_IMAGE_MAGIC, 4)) { 25593a7515aSWenping Zhang printf("image[%d] header '%s' is invalid\n", i, 25693a7515aSWenping Zhang img_hdr->magic); 25793a7515aSWenping Zhang return -EINVAL; 25893a7515aSWenping Zhang } 25993a7515aSWenping Zhang } 26093a7515aSWenping Zhang 26193a7515aSWenping Zhang return 0; 26293a7515aSWenping Zhang } 26393a7515aSWenping Zhang 26493a7515aSWenping Zhang static int read_grayscale(struct blk_desc *dev_desc, 26593a7515aSWenping Zhang disk_partition_t *part, u32 offset, 26693a7515aSWenping Zhang u32 size, void *buf) 26793a7515aSWenping Zhang { 26893a7515aSWenping Zhang u32 blk_start, blk_offset, blk_count; 26993a7515aSWenping Zhang 27093a7515aSWenping Zhang blk_offset = DIV_ROUND_UP(offset, dev_desc->blksz); 27193a7515aSWenping Zhang blk_start = part->start + blk_offset; 27293a7515aSWenping Zhang blk_count = DIV_ROUND_UP(size, dev_desc->blksz); 27393a7515aSWenping Zhang 27493a7515aSWenping Zhang debug("blk_offset=%d, blk_start=%d,blk_count=%d,out buf=%p\n", 27593a7515aSWenping Zhang blk_offset, blk_start, blk_count, buf); 27693a7515aSWenping Zhang if (blk_dread(dev_desc, blk_start, blk_count, buf) != blk_count) { 27793a7515aSWenping Zhang printf("read grayscale data failed\n"); 27893a7515aSWenping Zhang return -EIO; 27993a7515aSWenping Zhang } 28093a7515aSWenping Zhang 28193a7515aSWenping Zhang return 0; 28293a7515aSWenping Zhang } 28393a7515aSWenping Zhang 2844f14f98fSWenping Zhang static int image_mirror(u8 *in_buf, u8 *out_buf, u16 w, u16 h) 2854f14f98fSWenping Zhang { 2864f14f98fSWenping Zhang int i; 2874f14f98fSWenping Zhang 2884f14f98fSWenping Zhang if (!in_buf || !out_buf) { 2894f14f98fSWenping Zhang printf("mirror in buffer or out buffer is NULL\n"); 2904f14f98fSWenping Zhang return -EINVAL; 2914f14f98fSWenping Zhang } 2924f14f98fSWenping Zhang 2934f14f98fSWenping Zhang for (i = 0; i < h; i++) { 2944f14f98fSWenping Zhang u16 column_len = w / 2; 2954f14f98fSWenping Zhang u8 *column_in = in_buf + i * column_len; 2964f14f98fSWenping Zhang u8 *column_out = out_buf + (h - i - 1) * column_len; 2974f14f98fSWenping Zhang 2984f14f98fSWenping Zhang memcpy(column_out, column_in, column_len); 2994f14f98fSWenping Zhang } 3004f14f98fSWenping Zhang 3014f14f98fSWenping Zhang return 0; 3024f14f98fSWenping Zhang } 3034f14f98fSWenping Zhang 30493a7515aSWenping Zhang /* 30593a7515aSWenping Zhang * The eink kernel driver need last frame to do part refresh, 30693a7515aSWenping Zhang * so we need to transfer two images to kernel, which is kernel 30793a7515aSWenping Zhang * logo and the logo displayed in uboot. 30893a7515aSWenping Zhang * 30993a7515aSWenping Zhang * this function use logo type bitmap to indicate several logo. 31093a7515aSWenping Zhang * u32 needed_logo: we only load needed logo image into ram, such as 31193a7515aSWenping Zhang * uboot logo + kernel logo or charger logo + kernel 31293a7515aSWenping Zhang * logo 313074c7ac4SWenping Zhang * u32 *loaded_logo: because the needed logo may not exist in logo.img, 314074c7ac4SWenping Zhang * store the really loaded logo in para loaded_logo. 31593a7515aSWenping Zhang */ 31693a7515aSWenping Zhang static int read_needed_logo_from_partition(struct udevice *dev, 31793a7515aSWenping Zhang u32 needed_logo, 31893a7515aSWenping Zhang u32 *loaded_logo) 31993a7515aSWenping Zhang { 32093a7515aSWenping Zhang int ret, i; 32193a7515aSWenping Zhang disk_partition_t part; 32293a7515aSWenping Zhang struct blk_desc *dev_desc; 32393a7515aSWenping Zhang struct logo_info *hdr = &eink_logo_info; 32493a7515aSWenping Zhang struct logo_part_header *part_hdr = &hdr->part_hdr; 32593a7515aSWenping Zhang struct ebc_panel *panel = dev_get_platdata(dev); 32639939100SWenping Zhang u32 logo = needed_logo & (~(*loaded_logo)); 32793a7515aSWenping Zhang 32839939100SWenping Zhang if (!logo) { 329074c7ac4SWenping Zhang printf("logo[0x%x] is already loaded, just return!\n", 330074c7ac4SWenping Zhang needed_logo); 331074c7ac4SWenping Zhang return 0; 332074c7ac4SWenping Zhang } 33393a7515aSWenping Zhang dev_desc = rockchip_get_bootdev(); 33493a7515aSWenping Zhang if (!dev_desc) { 33593a7515aSWenping Zhang printf("%s: Could not find device\n", __func__); 33693a7515aSWenping Zhang return -EIO; 33793a7515aSWenping Zhang } 33893a7515aSWenping Zhang 33993a7515aSWenping Zhang if (part_get_info_by_name(dev_desc, PART_LOGO, &part) < 0) 34093a7515aSWenping Zhang return -ENODEV; 34193a7515aSWenping Zhang 34293a7515aSWenping Zhang ret = read_header(dev_desc, &part, hdr); 34393a7515aSWenping Zhang if (ret < 0) { 34493a7515aSWenping Zhang printf("eink logo read header failed,ret = %d\n", ret); 34593a7515aSWenping Zhang return -EINVAL; 34693a7515aSWenping Zhang } 3479876686dSWenping Zhang if (part_hdr->screen_width != panel->vir_width || 3489876686dSWenping Zhang part_hdr->screen_height != panel->vir_height){ 34993a7515aSWenping Zhang printf("logo size(%dx%d) is not same as screen size(%dx%d)\n", 35093a7515aSWenping Zhang part_hdr->screen_width, part_hdr->screen_height, 3519876686dSWenping Zhang panel->vir_width, panel->vir_height); 35293a7515aSWenping Zhang return -EINVAL; 35393a7515aSWenping Zhang } 35493a7515aSWenping Zhang 35593a7515aSWenping Zhang for (i = 0; i < part_hdr->logo_count; i++) { 35693a7515aSWenping Zhang struct grayscale_header *img_hdr = &hdr->img_hdr[i]; 35793a7515aSWenping Zhang int pic_buf; 35893a7515aSWenping Zhang u32 offset = img_hdr->data_offset; 35993a7515aSWenping Zhang u32 size = img_hdr->data_size; 36093a7515aSWenping Zhang u32 logo_type = img_hdr->logo_type; 36193a7515aSWenping Zhang 36293a7515aSWenping Zhang debug("offset=0x%x, size=%d,logo_type=%d,w=%d,h=%d\n", 36393a7515aSWenping Zhang offset, size, logo_type, img_hdr->w, img_hdr->h); 36493a7515aSWenping Zhang 36539939100SWenping Zhang if (logo & logo_type) { 36693a7515aSWenping Zhang pic_buf = get_addr_by_type(dev, logo_type); 36793a7515aSWenping Zhang 36893a7515aSWenping Zhang if (pic_buf <= 0) { 36993a7515aSWenping Zhang printf("Get buffer failed for image %d\n", 37093a7515aSWenping Zhang img_hdr->logo_type); 37193a7515aSWenping Zhang return -EIO; 37293a7515aSWenping Zhang } 37393a7515aSWenping Zhang if (!IS_ALIGNED((ulong)pic_buf, 37493a7515aSWenping Zhang ARCH_DMA_MINALIGN)) { 37593a7515aSWenping Zhang printf("disp buffer is not dma aligned\n"); 37693a7515aSWenping Zhang return -EINVAL; 37793a7515aSWenping Zhang } 3784f14f98fSWenping Zhang /* 3794f14f98fSWenping Zhang * kernel logo is transmitted to kernel to display, and 3804f14f98fSWenping Zhang * kernel will do the mirror operation, so skip kernel 3814f14f98fSWenping Zhang * logo here. 3824f14f98fSWenping Zhang */ 38339939100SWenping Zhang if (panel->mirror && logo_type != EINK_LOGO_KERNEL) { 3844f14f98fSWenping Zhang u32 w = panel->vir_width; 3854f14f98fSWenping Zhang u32 h = panel->vir_height; 3864f14f98fSWenping Zhang u32 mirror_buf = 0; 3874f14f98fSWenping Zhang 3884f14f98fSWenping Zhang mirror_buf = get_addr_by_type(dev, 3894f14f98fSWenping Zhang EINK_LOGO_UNMIRROR_TEMP_BUF); 3904f14f98fSWenping Zhang if (mirror_buf <= 0) { 3914f14f98fSWenping Zhang printf("get mirror buffer failed\n"); 3924f14f98fSWenping Zhang return -EIO; 3934f14f98fSWenping Zhang } 3944f14f98fSWenping Zhang read_grayscale(dev_desc, &part, offset, size, 3954f14f98fSWenping Zhang (void *)((ulong)mirror_buf)); 3964f14f98fSWenping Zhang image_mirror((u8 *)((ulong)mirror_buf), 3974f14f98fSWenping Zhang (u8 *)((ulong)pic_buf), w, h); 3984f14f98fSWenping Zhang } else { 39993a7515aSWenping Zhang read_grayscale(dev_desc, &part, offset, size, 40093a7515aSWenping Zhang (void *)((ulong)pic_buf)); 4014f14f98fSWenping Zhang } 40293a7515aSWenping Zhang flush_dcache_range((ulong)pic_buf, 40393a7515aSWenping Zhang ALIGN((ulong)pic_buf + size, 40493a7515aSWenping Zhang CONFIG_SYS_CACHELINE_SIZE)); 40593a7515aSWenping Zhang *loaded_logo |= logo_type; 40639939100SWenping Zhang 40739939100SWenping Zhang logo &= ~logo_type; 40839939100SWenping Zhang if (!logo) 40939939100SWenping Zhang break; 41093a7515aSWenping Zhang } 41193a7515aSWenping Zhang } 41293a7515aSWenping Zhang 41393a7515aSWenping Zhang return 0; 41493a7515aSWenping Zhang } 41593a7515aSWenping Zhang 41693a7515aSWenping Zhang static int ebc_power_set(struct udevice *dev, int is_on) 41793a7515aSWenping Zhang { 41893a7515aSWenping Zhang int ret; 41993a7515aSWenping Zhang struct rockchip_eink_display_priv *priv = dev_get_priv(dev); 42093a7515aSWenping Zhang struct ebc_panel *panel = dev_get_platdata(dev); 42193a7515aSWenping Zhang struct udevice *ebc_tcon_dev = priv->ebc_tcon_dev; 42293a7515aSWenping Zhang struct rk_ebc_tcon_ops *ebc_tcon_ops = ebc_tcon_get_ops(ebc_tcon_dev); 42393a7515aSWenping Zhang struct udevice *ebc_pwr_dev = priv->ebc_pwr_dev; 42493a7515aSWenping Zhang struct rk_ebc_pwr_ops *pwr_ops = ebc_pwr_get_ops(ebc_pwr_dev); 42593a7515aSWenping Zhang 42693a7515aSWenping Zhang if (is_on) { 42793a7515aSWenping Zhang ret = ebc_tcon_ops->enable(ebc_tcon_dev, panel); 42893a7515aSWenping Zhang if (ret) { 42993a7515aSWenping Zhang printf("%s, ebc tcon enabled failed\n", __func__); 43093a7515aSWenping Zhang return -1; 43193a7515aSWenping Zhang } 43293a7515aSWenping Zhang ret = pwr_ops->power_on(ebc_pwr_dev); 43393a7515aSWenping Zhang if (ret) { 43493a7515aSWenping Zhang printf("%s, power on failed\n", __func__); 43593a7515aSWenping Zhang return -1; 43693a7515aSWenping Zhang } 43793a7515aSWenping Zhang } else { 43893a7515aSWenping Zhang ret = pwr_ops->power_down(ebc_pwr_dev); 43993a7515aSWenping Zhang if (ret) { 44093a7515aSWenping Zhang printf("%s, power_down failed\n", __func__); 44193a7515aSWenping Zhang return -1; 44293a7515aSWenping Zhang } 44393a7515aSWenping Zhang ret = ebc_tcon_ops->disable(ebc_tcon_dev); 44493a7515aSWenping Zhang if (ret) { 44593a7515aSWenping Zhang printf("%s, ebc tcon disable failed\n", __func__); 44693a7515aSWenping Zhang return -1; 44793a7515aSWenping Zhang } 44893a7515aSWenping Zhang } 44993a7515aSWenping Zhang return 0; 45093a7515aSWenping Zhang } 45193a7515aSWenping Zhang 45293a7515aSWenping Zhang static int eink_display(struct udevice *dev, u32 pre_img_buf, 45393a7515aSWenping Zhang u32 cur_img_buf, u32 lut_type, int update_mode) 45493a7515aSWenping Zhang { 45593a7515aSWenping Zhang u32 temperature, frame_num; 45693a7515aSWenping Zhang struct rockchip_eink_display_priv *priv = dev_get_priv(dev); 45793a7515aSWenping Zhang struct ebc_panel *plat = dev_get_platdata(dev); 45893a7515aSWenping Zhang struct epd_lut_ops *lut_ops = &plat->lut_ops; 45993a7515aSWenping Zhang struct udevice *ebc_pwr_dev = priv->ebc_pwr_dev; 46093a7515aSWenping Zhang struct rk_ebc_pwr_ops *pwr_ops = ebc_pwr_get_ops(ebc_pwr_dev); 46193a7515aSWenping Zhang struct udevice *ebc_tcon_dev = priv->ebc_tcon_dev; 46293a7515aSWenping Zhang struct rk_ebc_tcon_ops *ebc_tcon_ops = ebc_tcon_get_ops(ebc_tcon_dev); 46393a7515aSWenping Zhang 46493a7515aSWenping Zhang pwr_ops->temp_get(ebc_pwr_dev, &temperature); 46593a7515aSWenping Zhang if (temperature <= 0 || temperature > 50) { 46693a7515aSWenping Zhang printf("temperature = %d, out of range0~50 ,use 25\n", 46793a7515aSWenping Zhang temperature); 46893a7515aSWenping Zhang temperature = 25; 46993a7515aSWenping Zhang } 47093a7515aSWenping Zhang 47193a7515aSWenping Zhang if (!lut_ops->lut_get) { 47293a7515aSWenping Zhang printf("get lut ops failed\n"); 47393a7515aSWenping Zhang return -EIO; 47493a7515aSWenping Zhang } 47593a7515aSWenping Zhang lut_ops->lut_get(&plat->lut_data, lut_type, temperature); 47693a7515aSWenping Zhang frame_num = plat->lut_data.frame_num; 47793a7515aSWenping Zhang debug("lut_type=%d, frame num=%d, temp=%d\n", lut_type, 47893a7515aSWenping Zhang frame_num, temperature); 47993a7515aSWenping Zhang 48039939100SWenping Zhang ebc_tcon_ops->wait_for_last_frame_complete(ebc_tcon_dev); 48193a7515aSWenping Zhang ebc_tcon_ops->lut_data_set(ebc_tcon_dev, plat->lut_data.data, 48293a7515aSWenping Zhang frame_num, 0); 48393a7515aSWenping Zhang ebc_tcon_ops->dsp_mode_set(ebc_tcon_dev, update_mode, 48493a7515aSWenping Zhang LUT_MODE, !THREE_WIN_MODE, !EINK_MODE); 48593a7515aSWenping Zhang ebc_tcon_ops->image_addr_set(ebc_tcon_dev, pre_img_buf, cur_img_buf); 48693a7515aSWenping Zhang ebc_tcon_ops->frame_start(ebc_tcon_dev, frame_num); 48793a7515aSWenping Zhang return 0; 48893a7515aSWenping Zhang } 48993a7515aSWenping Zhang 49093a7515aSWenping Zhang static int rk_eink_display_init(void) 49193a7515aSWenping Zhang { 49293a7515aSWenping Zhang int ret; 49393a7515aSWenping Zhang struct uclass *uc; 49493a7515aSWenping Zhang struct udevice *dev; 49593a7515aSWenping Zhang 49693a7515aSWenping Zhang if (eink_dev) { 49793a7515aSWenping Zhang printf("ebc-dev is already initialized!\n"); 49893a7515aSWenping Zhang return 0; 49993a7515aSWenping Zhang } 50093a7515aSWenping Zhang 50193a7515aSWenping Zhang ret = uclass_get(UCLASS_EINK_DISPLAY, &uc); 50293a7515aSWenping Zhang if (ret) { 50393a7515aSWenping Zhang printf("can't find uclass eink\n"); 50493a7515aSWenping Zhang return -ENODEV; 50593a7515aSWenping Zhang } 50693a7515aSWenping Zhang for (uclass_first_device(UCLASS_EINK_DISPLAY, &dev); 50793a7515aSWenping Zhang dev; uclass_next_device(&dev)) 50893a7515aSWenping Zhang ; 50993a7515aSWenping Zhang 51093a7515aSWenping Zhang if (eink_dev) { 51193a7515aSWenping Zhang printf("ebc-dev is probed success!\n"); 51293a7515aSWenping Zhang return 0; 51393a7515aSWenping Zhang } 51493a7515aSWenping Zhang printf("Can't find ebc-dev\n"); 51593a7515aSWenping Zhang return -ENODEV; 51693a7515aSWenping Zhang } 51793a7515aSWenping Zhang 51893a7515aSWenping Zhang /* 51993a7515aSWenping Zhang * Eink display need current and previous image buffer, We assume 52093a7515aSWenping Zhang * every type of logo has only one image, so just tell this function 52193a7515aSWenping Zhang * last logo type and current logo type, it will find the right images. 52293a7515aSWenping Zhang * last_logo_type: -1 means it's first displaying. 52393a7515aSWenping Zhang */ 52493a7515aSWenping Zhang static int rockchip_eink_show_logo(int cur_logo_type, int update_mode) 52593a7515aSWenping Zhang { 52693a7515aSWenping Zhang int ret = 0; 52793a7515aSWenping Zhang u32 logo_addr; 52893a7515aSWenping Zhang u32 last_logo_addr; 52993a7515aSWenping Zhang struct ebc_panel *plat; 53093a7515aSWenping Zhang struct udevice *dev; 53139939100SWenping Zhang static u32 loaded_logo = 0; 5323f41a942SWeixin Zhou struct rockchip_eink_display_priv *priv; 53393a7515aSWenping Zhang 53493a7515aSWenping Zhang if (!eink_dev) { 535449de1d3SWenping Zhang static bool first_init = true; 536449de1d3SWenping Zhang 537449de1d3SWenping Zhang if (first_init) { 538449de1d3SWenping Zhang first_init = false; 53993a7515aSWenping Zhang ret = rk_eink_display_init(); 54093a7515aSWenping Zhang if (ret) { 541449de1d3SWenping Zhang printf("Get ebc dev failed, check dts\n"); 542449de1d3SWenping Zhang return -ENODEV; 543449de1d3SWenping Zhang } 544449de1d3SWenping Zhang } else { 54593a7515aSWenping Zhang return -ENODEV; 54693a7515aSWenping Zhang } 54793a7515aSWenping Zhang } 54893a7515aSWenping Zhang dev = eink_dev; 54993a7515aSWenping Zhang 55093a7515aSWenping Zhang /*Don't need to update display*/ 55193a7515aSWenping Zhang if (last_logo_type == cur_logo_type) { 55293a7515aSWenping Zhang debug("Same as last picture, Don't need to display\n"); 55393a7515aSWenping Zhang return 0; 55493a7515aSWenping Zhang } 55593a7515aSWenping Zhang 55693a7515aSWenping Zhang plat = dev_get_platdata(dev); 5573f41a942SWeixin Zhou priv = dev_get_priv(dev); 55893a7515aSWenping Zhang 55939939100SWenping Zhang /* 56039939100SWenping Zhang * The last_logo_type is -1 means it's first displaying 56139939100SWenping Zhang */ 56239939100SWenping Zhang if (last_logo_type == -1) { 56393a7515aSWenping Zhang ret = ebc_power_set(dev, EBC_PWR_ON); 56493a7515aSWenping Zhang if (ret) { 56593a7515aSWenping Zhang printf("Eink power on failed\n"); 56693a7515aSWenping Zhang return -1; 56793a7515aSWenping Zhang } 56839939100SWenping Zhang 5699876686dSWenping Zhang int size = (plat->vir_width * plat->vir_height) >> 1; 57093a7515aSWenping Zhang 571e79e2085SWenping Zhang logo_addr = get_addr_by_type(dev, EINK_LOGO_RESET); 572e79e2085SWenping Zhang memset((u32 *)(u64)logo_addr, 0xff, size); 57323f3ce8dSWenping Zhang flush_dcache_range((ulong)logo_addr, 57423f3ce8dSWenping Zhang ALIGN((ulong)logo_addr + size, 57523f3ce8dSWenping Zhang CONFIG_SYS_CACHELINE_SIZE)); 576e79e2085SWenping Zhang eink_display(dev, logo_addr, logo_addr, 57739939100SWenping Zhang WF_TYPE_RESET, EINK_LOGO_RESET); 57893a7515aSWenping Zhang last_logo_type = 0; 579e79e2085SWenping Zhang last_logo_addr = logo_addr; 58093a7515aSWenping Zhang } else { 58193a7515aSWenping Zhang last_logo_addr = get_addr_by_type(dev, last_logo_type); 58293a7515aSWenping Zhang if (last_logo_addr < 0) { 58393a7515aSWenping Zhang printf("Invalid last logo addr, exit!\n"); 58493a7515aSWenping Zhang goto out; 58593a7515aSWenping Zhang } 586*77bac292SZorro Liu } 587*77bac292SZorro Liu ret = read_needed_logo_from_partition(dev, cur_logo_type, 588*77bac292SZorro Liu &loaded_logo); 589*77bac292SZorro Liu if (ret || !(loaded_logo & cur_logo_type)) { 590*77bac292SZorro Liu printf("read logo[0x%x] failed, loaded_logo=0x%x\n", 591*77bac292SZorro Liu cur_logo_type, loaded_logo); 592*77bac292SZorro Liu ret = -EIO; 593*77bac292SZorro Liu goto out; 594*77bac292SZorro Liu } 595*77bac292SZorro Liu logo_addr = get_addr_by_type(dev, cur_logo_type); 596*77bac292SZorro Liu debug("logo_addr=%x, logo_type=%d\n", logo_addr, cur_logo_type); 597*77bac292SZorro Liu if (logo_addr <= 0) { 598*77bac292SZorro Liu printf("get logo buffer failed\n"); 599*77bac292SZorro Liu ret = -EIO; 600*77bac292SZorro Liu goto out; 601*77bac292SZorro Liu } 60239939100SWenping Zhang 603*77bac292SZorro Liu eink_display(dev, last_logo_addr, logo_addr, WF_TYPE_GC16, update_mode); 604*77bac292SZorro Liu 605*77bac292SZorro Liu if (priv->backlight) 606*77bac292SZorro Liu backlight_enable(priv->backlight); 607*77bac292SZorro Liu 608*77bac292SZorro Liu last_logo_type = cur_logo_type; 609*77bac292SZorro Liu 610*77bac292SZorro Liu if (cur_logo_type == EINK_LOGO_POWEROFF) { 61139939100SWenping Zhang struct udevice *ebc_tcon_dev = priv->ebc_tcon_dev; 61239939100SWenping Zhang struct rk_ebc_tcon_ops *ebc_tcon_ops; 61339939100SWenping Zhang 61493a7515aSWenping Zhang last_logo_type = -1; 61539939100SWenping Zhang /* 61639939100SWenping Zhang * For normal logo display, waiting for the last frame 61739939100SWenping Zhang * completion before start a new frame, except one 61839939100SWenping Zhang * situation which charging logo display finished, 61939939100SWenping Zhang * because device will rebooting or shutdown after 62039939100SWenping Zhang * charging logo is competed. 62139939100SWenping Zhang * 62239939100SWenping Zhang * We should take care of the power sequence, 62339939100SWenping Zhang * because ebc can't power off if last frame 62439939100SWenping Zhang * data is still sending, so keep the ebc power 62539939100SWenping Zhang * during u-boot phase and shutdown the 62639939100SWenping Zhang * power only if uboot charging is finished. 62739939100SWenping Zhang */ 62839939100SWenping Zhang ebc_tcon_ops = ebc_tcon_get_ops(ebc_tcon_dev); 62939939100SWenping Zhang ebc_tcon_ops->wait_for_last_frame_complete(ebc_tcon_dev); 63039939100SWenping Zhang debug("charging logo displaying is complete\n"); 63139939100SWenping Zhang /* 63239939100SWenping Zhang *shutdown ebc after charging logo display is complete 63339939100SWenping Zhang */ 63439939100SWenping Zhang ret = ebc_power_set(dev, EBC_PWR_DOWN); 63539939100SWenping Zhang if (ret) 63639939100SWenping Zhang printf("Eink power down failed\n"); 63793a7515aSWenping Zhang goto out; 63893a7515aSWenping Zhang } 63993a7515aSWenping Zhang 64093a7515aSWenping Zhang /* 64193a7515aSWenping Zhang * System will boot up to kernel only when the 64293a7515aSWenping Zhang * logo is uboot logo 64393a7515aSWenping Zhang */ 64493a7515aSWenping Zhang if (cur_logo_type == EINK_LOGO_UBOOT) { 64593a7515aSWenping Zhang char logo_args[64] = {0}; 6464f14f98fSWenping Zhang u32 uboot_logo_buf; 64793a7515aSWenping Zhang 6484f14f98fSWenping Zhang if (plat->mirror) 6494f14f98fSWenping Zhang uboot_logo_buf = get_addr_by_type(dev, 6504f14f98fSWenping Zhang EINK_LOGO_UNMIRROR_TEMP_BUF); 6514f14f98fSWenping Zhang else 6524f14f98fSWenping Zhang uboot_logo_buf = logo_addr; 6534f14f98fSWenping Zhang printf("Transmit uboot logo addr(0x%x) to kernel\n", 6544f14f98fSWenping Zhang uboot_logo_buf); 6554f14f98fSWenping Zhang sprintf(logo_args, "ulogo_addr=0x%x", uboot_logo_buf); 65693a7515aSWenping Zhang env_update("bootargs", logo_args); 65793a7515aSWenping Zhang ret = read_needed_logo_from_partition(dev, EINK_LOGO_KERNEL, 658074c7ac4SWenping Zhang &loaded_logo); 659074c7ac4SWenping Zhang if (ret || !(loaded_logo & EINK_LOGO_KERNEL)) { 66093a7515aSWenping Zhang printf("No invalid kernel logo in logo.img\n"); 66193a7515aSWenping Zhang } else { 66293a7515aSWenping Zhang int klogo_addr = get_addr_by_type(dev, 66393a7515aSWenping Zhang EINK_LOGO_KERNEL); 66493a7515aSWenping Zhang 66593a7515aSWenping Zhang if (klogo_addr <= 0) { 66693a7515aSWenping Zhang printf("get kernel logo buffer failed\n"); 66793a7515aSWenping Zhang ret = -EIO; 66893a7515aSWenping Zhang goto out; 66993a7515aSWenping Zhang } 67093a7515aSWenping Zhang printf("Transmit kernel logo addr(0x%x) to kernel\n", 67193a7515aSWenping Zhang klogo_addr); 67293a7515aSWenping Zhang sprintf(logo_args, "klogo_addr=0x%x", klogo_addr); 67393a7515aSWenping Zhang env_update("bootargs", logo_args); 67493a7515aSWenping Zhang } 67593a7515aSWenping Zhang } 67693a7515aSWenping Zhang 67793a7515aSWenping Zhang out: 67893a7515aSWenping Zhang return ret; 67993a7515aSWenping Zhang } 68093a7515aSWenping Zhang 68193a7515aSWenping Zhang int rockchip_eink_show_uboot_logo(void) 68293a7515aSWenping Zhang { 68393a7515aSWenping Zhang return rockchip_eink_show_logo(EINK_LOGO_UBOOT, EINK_UPDATE_DIFF); 68493a7515aSWenping Zhang } 68593a7515aSWenping Zhang 68693a7515aSWenping Zhang int rockchip_eink_show_charge_logo(int logo_type) 68793a7515aSWenping Zhang { 68893a7515aSWenping Zhang return rockchip_eink_show_logo(logo_type, EINK_UPDATE_DIFF); 68993a7515aSWenping Zhang } 69093a7515aSWenping Zhang 69193a7515aSWenping Zhang static int rockchip_eink_display_probe(struct udevice *dev) 69293a7515aSWenping Zhang { 69393a7515aSWenping Zhang int ret, vcom; 69493a7515aSWenping Zhang struct rockchip_eink_display_priv *priv = dev_get_priv(dev); 69593a7515aSWenping Zhang 69693a7515aSWenping Zhang /* Before relocation we don't need to do anything */ 69793a7515aSWenping Zhang if (!(gd->flags & GD_FLG_RELOC)) 69893a7515aSWenping Zhang return 0; 69993a7515aSWenping Zhang 70093a7515aSWenping Zhang ret = uclass_get_device_by_phandle(UCLASS_EBC, dev, 70193a7515aSWenping Zhang "ebc_tcon", 70293a7515aSWenping Zhang &priv->ebc_tcon_dev); 703449de1d3SWenping Zhang if (ret) { 70493a7515aSWenping Zhang dev_err(dev, "Cannot get ebc_tcon: %d\n", ret); 70593a7515aSWenping Zhang return ret; 70693a7515aSWenping Zhang } 70793a7515aSWenping Zhang 70893a7515aSWenping Zhang ret = uclass_get_device_by_phandle(UCLASS_I2C_GENERIC, dev, 70993a7515aSWenping Zhang "pmic", 71093a7515aSWenping Zhang &priv->ebc_pwr_dev); 711449de1d3SWenping Zhang if (ret) { 71293a7515aSWenping Zhang dev_err(dev, "Cannot get pmic: %d\n", ret); 71393a7515aSWenping Zhang return ret; 71493a7515aSWenping Zhang } 71593a7515aSWenping Zhang 7163f41a942SWeixin Zhou ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, 7173f41a942SWeixin Zhou "backlight", &priv->backlight); 7183f41a942SWeixin Zhou if (ret && ret != -ENOENT) { 7193f41a942SWeixin Zhou printf("%s: Cannot get backlight: %d\n", __func__, ret); 7203f41a942SWeixin Zhou } 7213f41a942SWeixin Zhou 72293a7515aSWenping Zhang vcom = read_vcom_from_vendor(); 72393a7515aSWenping Zhang if (vcom <= 0) { 72493a7515aSWenping Zhang printf("read vcom from vendor failed, use default vcom\n"); 72593a7515aSWenping Zhang priv->vcom = VCOM_DEFAULT_VALUE; 72693a7515aSWenping Zhang } else { 72793a7515aSWenping Zhang priv->vcom = vcom; 72893a7515aSWenping Zhang } 72993a7515aSWenping Zhang 73093a7515aSWenping Zhang if (priv->ebc_pwr_dev) { 73193a7515aSWenping Zhang struct rk_ebc_pwr_ops *pwr_ops; 73293a7515aSWenping Zhang 73393a7515aSWenping Zhang pwr_ops = ebc_pwr_get_ops(priv->ebc_pwr_dev); 73493a7515aSWenping Zhang ret = pwr_ops->vcom_set(priv->ebc_pwr_dev, priv->vcom); 73593a7515aSWenping Zhang if (ret) { 73693a7515aSWenping Zhang printf("%s, vcom_set failed\n", __func__); 73793a7515aSWenping Zhang return -EIO; 73893a7515aSWenping Zhang } 73993a7515aSWenping Zhang } 74093a7515aSWenping Zhang 74193a7515aSWenping Zhang // read lut to ram, and get lut ops 74293a7515aSWenping Zhang ret = read_waveform(dev); 74393a7515aSWenping Zhang if (ret < 0) { 74493a7515aSWenping Zhang printf("read wavform failed\n"); 74593a7515aSWenping Zhang return -EIO; 74693a7515aSWenping Zhang } 74793a7515aSWenping Zhang 74893a7515aSWenping Zhang eink_dev = dev; 7493f41a942SWeixin Zhou 75093a7515aSWenping Zhang return 0; 75193a7515aSWenping Zhang } 75293a7515aSWenping Zhang 75393a7515aSWenping Zhang static int rockchip_eink_display_ofdata_to_platdata(struct udevice *dev) 75493a7515aSWenping Zhang { 75593a7515aSWenping Zhang fdt_size_t size; 75693a7515aSWenping Zhang fdt_addr_t tmp_addr; 75793a7515aSWenping Zhang struct device_node *disp_mem; 75893a7515aSWenping Zhang struct device_node *waveform_mem; 75993a7515aSWenping Zhang struct ebc_panel *plat = dev_get_platdata(dev); 76093a7515aSWenping Zhang 76193a7515aSWenping Zhang plat->width = dev_read_u32_default(dev, "panel,width", 0); 76293a7515aSWenping Zhang plat->height = dev_read_u32_default(dev, "panel,height", 0); 7639876686dSWenping Zhang plat->vir_width = dev_read_u32_default(dev, "panel,vir_width", plat->width); 7649876686dSWenping Zhang plat->vir_height = dev_read_u32_default(dev, "panel,vir_height", plat->height); 76593a7515aSWenping Zhang plat->sdck = dev_read_u32_default(dev, "panel,sdck", 0); 76693a7515aSWenping Zhang plat->lsl = dev_read_u32_default(dev, "panel,lsl", 0); 76793a7515aSWenping Zhang plat->lbl = dev_read_u32_default(dev, "panel,lbl", 0); 76893a7515aSWenping Zhang plat->ldl = dev_read_u32_default(dev, "panel,ldl", 0); 76993a7515aSWenping Zhang plat->lel = dev_read_u32_default(dev, "panel,lel", 0); 77093a7515aSWenping Zhang plat->gdck_sta = dev_read_u32_default(dev, "panel,gdck-sta", 0); 77193a7515aSWenping Zhang plat->lgonl = dev_read_u32_default(dev, "panel,lgonl", 0); 77293a7515aSWenping Zhang plat->fsl = dev_read_u32_default(dev, "panel,fsl", 0); 77393a7515aSWenping Zhang plat->fbl = dev_read_u32_default(dev, "panel,fbl", 0); 77493a7515aSWenping Zhang plat->fdl = dev_read_u32_default(dev, "panel,fdl", 0); 77593a7515aSWenping Zhang plat->fel = dev_read_u32_default(dev, "panel,fel", 0); 77693a7515aSWenping Zhang plat->panel_16bit = dev_read_u32_default(dev, "panel,panel_16bit", 0); 77793a7515aSWenping Zhang plat->panel_color = dev_read_u32_default(dev, "panel,panel_color", 0); 77893a7515aSWenping Zhang plat->mirror = dev_read_u32_default(dev, "panel,mirror", 0); 77993a7515aSWenping Zhang plat->width_mm = dev_read_u32_default(dev, "panel,width-mm", 0); 78093a7515aSWenping Zhang plat->height_mm = dev_read_u32_default(dev, "panel,height-mm", 0); 78193a7515aSWenping Zhang 78293a7515aSWenping Zhang disp_mem = of_parse_phandle(ofnode_to_np(dev_ofnode(dev)), 78393a7515aSWenping Zhang "memory-region", 0); 78493a7515aSWenping Zhang if (!disp_mem) { 78593a7515aSWenping Zhang dev_err(dev, "Cannot get memory-region from dts\n"); 78693a7515aSWenping Zhang return -ENODEV; 78793a7515aSWenping Zhang } 78893a7515aSWenping Zhang tmp_addr = ofnode_get_addr_size(np_to_ofnode(disp_mem), "reg", &size); 78993a7515aSWenping Zhang if (tmp_addr == FDT_ADDR_T_NONE) { 79093a7515aSWenping Zhang printf("get display memory address failed\n"); 79193a7515aSWenping Zhang return -ENODEV; 79293a7515aSWenping Zhang } 79393a7515aSWenping Zhang 79493a7515aSWenping Zhang plat->disp_pbuf = (u64)map_sysmem(tmp_addr, 0); 79593a7515aSWenping Zhang plat->disp_pbuf_size = size; 79693a7515aSWenping Zhang debug("display mem=0x%x, size=%x\n", plat->disp_pbuf, 79793a7515aSWenping Zhang plat->disp_pbuf_size); 79893a7515aSWenping Zhang waveform_mem = of_parse_phandle(ofnode_to_np(dev_ofnode(dev)), 79993a7515aSWenping Zhang "waveform-region", 0); 80093a7515aSWenping Zhang if (!waveform_mem) { 80193a7515aSWenping Zhang printf("Cannot get waveform-region from dts\n"); 80293a7515aSWenping Zhang return -ENODEV; 80393a7515aSWenping Zhang } 80493a7515aSWenping Zhang tmp_addr = ofnode_get_addr_size(np_to_ofnode(waveform_mem), 80593a7515aSWenping Zhang "reg", &size); 80693a7515aSWenping Zhang if (tmp_addr == FDT_ADDR_T_NONE) { 80793a7515aSWenping Zhang printf("get waveform memory address failed\n"); 80893a7515aSWenping Zhang return -ENODEV; 80993a7515aSWenping Zhang } 81093a7515aSWenping Zhang 81193a7515aSWenping Zhang plat->lut_pbuf = map_sysmem(tmp_addr, 0); 81293a7515aSWenping Zhang plat->lut_pbuf_size = size; 81393a7515aSWenping Zhang debug("lut mem=0x%p, size=%x\n", plat->lut_pbuf, plat->lut_pbuf_size); 81493a7515aSWenping Zhang return 0; 81593a7515aSWenping Zhang } 81693a7515aSWenping Zhang 81793a7515aSWenping Zhang static const struct udevice_id rockchip_eink_display_ids[] = { 81893a7515aSWenping Zhang { .compatible = "rockchip,ebc-dev", }, 81993a7515aSWenping Zhang {} 82093a7515aSWenping Zhang }; 82193a7515aSWenping Zhang 82293a7515aSWenping Zhang U_BOOT_DRIVER(rk_eink_display) = { 82393a7515aSWenping Zhang .name = "rockchip_eink_display", 82493a7515aSWenping Zhang .id = UCLASS_EINK_DISPLAY, 82593a7515aSWenping Zhang .of_match = rockchip_eink_display_ids, 82693a7515aSWenping Zhang .ofdata_to_platdata = rockchip_eink_display_ofdata_to_platdata, 82793a7515aSWenping Zhang .probe = rockchip_eink_display_probe, 82893a7515aSWenping Zhang .priv_auto_alloc_size = sizeof(struct rockchip_eink_display_priv), 82993a7515aSWenping Zhang .platdata_auto_alloc_size = sizeof(struct ebc_panel), 83093a7515aSWenping Zhang }; 83193a7515aSWenping Zhang 83293a7515aSWenping Zhang UCLASS_DRIVER(rk_eink) = { 83393a7515aSWenping Zhang .id = UCLASS_EINK_DISPLAY, 83493a7515aSWenping Zhang .name = "rk_eink", 83593a7515aSWenping Zhang }; 83693a7515aSWenping Zhang 837