xref: /rk3399_rockchip-uboot/drivers/video/rk_eink/rk_ebc_tcon.c (revision 514e00a960f8a815e0c86931b498063c6fc4ef76)
193a7515aSWenping Zhang // SPDX-License-Identifier: GPL-2.0
293a7515aSWenping Zhang /*
393a7515aSWenping Zhang  * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
493a7515aSWenping Zhang  *
593a7515aSWenping Zhang  * Author: Wenping Zhang <wenping.zhang@rock-chips.com>
693a7515aSWenping Zhang  */
793a7515aSWenping Zhang #include <common.h>
893a7515aSWenping Zhang #include <clk.h>
993a7515aSWenping Zhang #include <dm.h>
1093a7515aSWenping Zhang #include <dm/pinctrl.h>
1193a7515aSWenping Zhang #include <pwm.h>
1293a7515aSWenping Zhang #include <regmap.h>
1393a7515aSWenping Zhang #include <syscon.h>
1493a7515aSWenping Zhang #include <asm/arch/clock.h>
1593a7515aSWenping Zhang #include <asm/io.h>
1693a7515aSWenping Zhang #include <syscon.h>
1793a7515aSWenping Zhang #include <linux/io.h>
1893a7515aSWenping Zhang #include "rk_ebc.h"
1993a7515aSWenping Zhang #ifdef CONFIG_IRQ
2093a7515aSWenping Zhang #include <irq-generic.h>
2193a7515aSWenping Zhang #endif
2293a7515aSWenping Zhang 
2393a7515aSWenping Zhang struct ebc_tcon_priv {
2493a7515aSWenping Zhang 	struct udevice *dev;
2593a7515aSWenping Zhang 	void __iomem *reg;
2693a7515aSWenping Zhang 	u32 *regcache;
2793a7515aSWenping Zhang 	u32 reg_len;
2893a7515aSWenping Zhang 	void *grf;
2993a7515aSWenping Zhang 	void *pmugrf;
30f968f3bcSZorro Liu 	struct clk dclk;
3193a7515aSWenping Zhang };
3293a7515aSWenping Zhang 
3393a7515aSWenping Zhang #define msleep(a)		udelay((a) * 1000)
3493a7515aSWenping Zhang #define HIWORD_UPDATE(x, l, h)	(((x) << (l)) | (GENMASK(h, l) << 16))
3593a7515aSWenping Zhang #define UPDATE(x, h, l)		(((x) << (l)) & GENMASK((h), (l)))
3693a7515aSWenping Zhang 
3793a7515aSWenping Zhang #define REG_LOAD_GLOBAL_EN	0x1
3893a7515aSWenping Zhang 
3993a7515aSWenping Zhang /* ebc register define */
4093a7515aSWenping Zhang #define EBC_DSP_START		0x0000 //Frame statrt register
4193a7515aSWenping Zhang #define EBC_EPD_CTRL		0x0004 //EPD control register
4293a7515aSWenping Zhang #define EBC_DSP_CTRL		0x0008 //Display control register
4393a7515aSWenping Zhang #define EBC_DSP_HTIMING0	0x000c //H-Timing setting register0
4493a7515aSWenping Zhang #define EBC_DSP_HTIMING1	0x0010 //H-Timing setting register1
4593a7515aSWenping Zhang #define EBC_DSP_VTIMING0	0x0014 //V-Timing setting register0
4693a7515aSWenping Zhang #define EBC_DSP_VTIMING1	0x0018 //V-Timing setting register1
4793a7515aSWenping Zhang #define EBC_DSP_ACT_INFO	0x001c //ACTIVE width/height
4893a7515aSWenping Zhang #define EBC_WIN_CTRL		0x0020 //Window ctrl
4993a7515aSWenping Zhang #define EBC_WIN_MST0		0x0024 //Current win memory start
5093a7515aSWenping Zhang #define EBC_WIN_MST1		0x0028 //Next win memory start
5193a7515aSWenping Zhang #define EBC_WIN_VIR		0x002c //Window vir width/height
5293a7515aSWenping Zhang #define EBC_WIN_ACT		0x0030 //Window act width/height
5393a7515aSWenping Zhang #define EBC_WIN_DSP		0x0034 //Window dsp width/height
5493a7515aSWenping Zhang #define EBC_WIN_DSP_ST		0x0038 //Window display start point
5593a7515aSWenping Zhang #define EBC_INT_STATUS		0x003c //Interrupt register
5693a7515aSWenping Zhang #define EBC_VCOM0		0x0040 //VCOM setting register0
5793a7515aSWenping Zhang #define EBC_VCOM1		0x0044 //VCOM setting register1
5893a7515aSWenping Zhang #define EBC_VCOM2		0x0048 //VCOM setting register2
5993a7515aSWenping Zhang #define EBC_VCOM3		0x004c //VCOM setting register3
6093a7515aSWenping Zhang #define EBC_CONFIG_DONE		0x0050 //Config done register
6193a7515aSWenping Zhang #define EBC_VNUM		0x0054 //Line flag num
6293a7515aSWenping Zhang #define EBC_WIN_MST2		0x0058 //Framecount memory start
6393a7515aSWenping Zhang #define EBC_LUT_DATA_ADDR	0x1000 //lut data address
6493a7515aSWenping Zhang 
6593a7515aSWenping Zhang #define DSP_HTOTAL(x)		UPDATE(x, 27, 16)
6693a7515aSWenping Zhang #define DSP_HS_END(x)		UPDATE(x, 7, 0)
6793a7515aSWenping Zhang #define DSP_HACT_END(x)		UPDATE(x, 26, 16)
6893a7515aSWenping Zhang #define DSP_HACT_ST(x)		UPDATE(x, 7, 0)
6993a7515aSWenping Zhang #define DSP_VTOTAL(x)		UPDATE(x, 26, 16)
7093a7515aSWenping Zhang #define DSP_VS_END(x)		UPDATE(x, 7, 0)
7193a7515aSWenping Zhang #define DSP_VACT_END(x)		UPDATE(x, 26, 16)
7293a7515aSWenping Zhang #define DSP_VACT_ST(x)		UPDATE(x, 7, 0)
7393a7515aSWenping Zhang #define DSP_HEIGHT(x)		UPDATE(x, 26, 16)
7493a7515aSWenping Zhang #define DSP_WIDTH(x)		UPDATE(x, 11, 0)
7593a7515aSWenping Zhang 
7693a7515aSWenping Zhang #define WIN2_FIFO_ALMOST_FULL_LEVEL(x)	UPDATE(x, 27, 19)
7793a7515aSWenping Zhang #define WIN_EN(x)			UPDATE(x, 18, 18)
7893a7515aSWenping Zhang #define BURST_REG(x)			UPDATE(x, 12, 10)
7993a7515aSWenping Zhang #define WIN_FIFO_ALMOST_FULL_LEVEL(x)	UPDATE(x, 9, 2)
8093a7515aSWenping Zhang #define WIN_FMT(x)			UPDATE(x, 1, 0)
8193a7515aSWenping Zhang 
8293a7515aSWenping Zhang #define WIN_VIR_HEIGHT(x)		UPDATE(x, 31, 16)
8393a7515aSWenping Zhang #define WIN_VIR_WIDTH(x)		UPDATE(x, 15, 0)
8493a7515aSWenping Zhang #define WIN_ACT_HEIGHT(x)		UPDATE(x, 26, 16)
8593a7515aSWenping Zhang #define WIN_ACT_WIDTH(x)		UPDATE(x, 11, 0)
8693a7515aSWenping Zhang #define WIN_DSP_HEIGHT(x)		UPDATE(x, 26, 16)
8793a7515aSWenping Zhang #define WIN_DSP_WIDTH(x)		UPDATE(x, 11, 0)
8893a7515aSWenping Zhang #define WIN_DSP_YST(x)			UPDATE(x, 26, 16)
8993a7515aSWenping Zhang #define WIN_DSP_XST(x)			UPDATE(x, 11, 0)
9093a7515aSWenping Zhang 
9193a7515aSWenping Zhang #define DSP_OUT_LOW			BIT(31)
9293a7515aSWenping Zhang #define DSP_EINK_MODE(x)		UPDATE(x, 13, 13)
9393a7515aSWenping Zhang #define DSP_EINK_MODE_MASK		BIT(13)
9493a7515aSWenping Zhang #define DSP_SDCE_WIDTH(x)		UPDATE(x, 25, 16)
9593a7515aSWenping Zhang #define DSP_FRM_TOTAL(x)		UPDATE(x, 9, 2)
9693a7515aSWenping Zhang #define DSP_FRM_TOTAL_MASK		GENMASK(9, 2)
9793a7515aSWenping Zhang #define DSP_FRM_START			BIT(0)
9893a7515aSWenping Zhang #define DSP_FRM_START_MASK		BIT(0)
9993a7515aSWenping Zhang #define SW_BURST_CTRL			BIT(12)
10093a7515aSWenping Zhang 
10193a7515aSWenping Zhang #define EINK_MODE_SWAP(x)		UPDATE(x, 31, 31)
10293a7515aSWenping Zhang #define EINK_MODE_FRM_SEL(x)		UPDATE(x, 30, 30)
10393a7515aSWenping Zhang #define DSP_GD_END(x)			UPDATE(x, 26, 16)
10493a7515aSWenping Zhang #define DSP_GD_ST(x)			UPDATE(x, 15, 8)
10593a7515aSWenping Zhang #define DSP_THREE_WIN_MODE(x)		UPDATE(x, 7, 7)
10693a7515aSWenping Zhang #define THREE_WIN_MODE_MASK		BIT(7)
10793a7515aSWenping Zhang #define DSP_SDDW_MODE(x)		UPDATE(x, 6, 6)
10893a7515aSWenping Zhang #define EPD_AUO(x)			UPDATE(x, 5, 5)
10993a7515aSWenping Zhang #define EPD_PWR(x)			UPDATE(x, 4, 2)
11093a7515aSWenping Zhang #define EPD_GDRL(x)			UPDATE(x, 1, 1)
11193a7515aSWenping Zhang #define EPD_SDSHR(x)			UPDATE(x, 0, 0)
11293a7515aSWenping Zhang 
11393a7515aSWenping Zhang #define DSP_SWAP_MODE(x)		UPDATE(x, 31, 30)
11493a7515aSWenping Zhang #define DSP_SWAP_MODE_MASK		GENMASK(31, 30)
11593a7515aSWenping Zhang #define DSP_SDCLK_DIV(x)		UPDATE(x, 19, 16)
11693a7515aSWenping Zhang #define DSP_SDCLK_DIV_MASK		GENMASK(19, 16)
11793a7515aSWenping Zhang #define DSP_VCOM_MODE(x)		UPDATE(x, 27, 27)
11893a7515aSWenping Zhang #define DSP_VCOM_MODE_MASK		BIT(27)
11993a7515aSWenping Zhang 
12093a7515aSWenping Zhang #define DSP_UPDATE_MODE(x)	UPDATE(x, 29, 29)
12193a7515aSWenping Zhang #define DSP_DISPLAY_MODE(x)	UPDATE(x, 28, 28)
12293a7515aSWenping Zhang #define UPDATE_MODE_MASK	BIT(29)
12393a7515aSWenping Zhang #define DISPLAY_MODE_MASK	BIT(28)
12493a7515aSWenping Zhang 
12593a7515aSWenping Zhang #define DSP_FRM_INT_NUM(x)	UPDATE(x, 19, 12)
12693a7515aSWenping Zhang #define FRM_END_INT		BIT(0)
12793a7515aSWenping Zhang #define DSP_END_INT		BIT(1)
12893a7515aSWenping Zhang #define DSP_FRM_INT		BIT(2)
12993a7515aSWenping Zhang #define LINE_FLAG_INT		BIT(3)
13093a7515aSWenping Zhang #define FRM_END_INT_MASK	BIT(4)
13193a7515aSWenping Zhang #define DSP_END_INT_MASK	BIT(5)
13293a7515aSWenping Zhang #define DSP_FRM_INT_MASK	BIT(6)
13393a7515aSWenping Zhang #define LINE_FLAG_INT_MASK	BIT(7)
13493a7515aSWenping Zhang #define FRM_END_INT_CLR		BIT(8)
13593a7515aSWenping Zhang #define DSP_END_INT_CLR		BIT(9)
13693a7515aSWenping Zhang #define DSP_FRM_INT_CLR		BIT(10)
13793a7515aSWenping Zhang #define LINE_FLAG_INT_CLR	BIT(11)
13893a7515aSWenping Zhang 
13993a7515aSWenping Zhang #define PMU_BASE_ADDR		0xfdd90000
14093a7515aSWenping Zhang #define PMU_PWR_GATE_SFTCON	0xA0
14193a7515aSWenping Zhang #define PMU_PWR_DWN_ST		0x98
14293a7515aSWenping Zhang #define RGA_PD_OFF		BIT(5)
14393a7515aSWenping Zhang #define RGA_PD_STAT		BIT(5)
14493a7515aSWenping Zhang enum ebc_win_data_fmt {
14593a7515aSWenping Zhang 	Y_DATA_4BPP = 0,
14693a7515aSWenping Zhang 	Y_DATA_8BPP = 1,
14793a7515aSWenping Zhang 	RGB888 = 2,
14893a7515aSWenping Zhang 	RGB565 = 3,
14993a7515aSWenping Zhang };
15093a7515aSWenping Zhang 
15193a7515aSWenping Zhang #ifdef CONFIG_IRQ
15293a7515aSWenping Zhang #define IRQ_EBC			49
15393a7515aSWenping Zhang #endif
15439939100SWenping Zhang static volatile int last_frame_done = -1;
15593a7515aSWenping Zhang static inline void regs_dump(struct ebc_tcon_priv *tcon)
15693a7515aSWenping Zhang {
15793a7515aSWenping Zhang 	int i;
15893a7515aSWenping Zhang 
15993a7515aSWenping Zhang 	printf("dump registers:\n");
16093a7515aSWenping Zhang 	for (i = 0; i <= EBC_WIN_MST2; i = i + 4) {
16193a7515aSWenping Zhang 		if (!(i % 16))
16293a7515aSWenping Zhang 			printf("\n 0x%p:\t", tcon->reg + i);
16393a7515aSWenping Zhang 		printf("0x%x\t", readl(tcon->reg + i));
16493a7515aSWenping Zhang 	}
16593a7515aSWenping Zhang 	printf("\nlut data:\n");
16693a7515aSWenping Zhang 	for (i = 0x1000; i <= 0x1100; i = i + 4) {
16793a7515aSWenping Zhang 		if (!(i % 16))
16893a7515aSWenping Zhang 			printf("\n 0x%p:\t", tcon->reg + i);
16993a7515aSWenping Zhang 		printf("0x%x\t", readl(tcon->reg + i));
17093a7515aSWenping Zhang 	}
17193a7515aSWenping Zhang 	printf("\n");
17293a7515aSWenping Zhang }
17393a7515aSWenping Zhang 
17493a7515aSWenping Zhang static int ebc_power_domain(int on)
17593a7515aSWenping Zhang {
17693a7515aSWenping Zhang 	u32 pd_reg;
17793a7515aSWenping Zhang 	u32 pd_stat;
17893a7515aSWenping Zhang 	int delay = 0;
17993a7515aSWenping Zhang 
18093a7515aSWenping Zhang 	if (on) {
18193a7515aSWenping Zhang 		pd_reg = RGA_PD_OFF << 16;
18293a7515aSWenping Zhang 		pd_stat = RGA_PD_STAT;
18393a7515aSWenping Zhang 	} else {
18493a7515aSWenping Zhang 		pd_reg = RGA_PD_OFF | (RGA_PD_OFF << 16);
18593a7515aSWenping Zhang 		pd_stat = ~((u32)RGA_PD_STAT);
18693a7515aSWenping Zhang 	}
18793a7515aSWenping Zhang 
18893a7515aSWenping Zhang 	/* enable rga pd for ebc tcon*/
18993a7515aSWenping Zhang 	writel(pd_reg, PMU_BASE_ADDR + PMU_PWR_GATE_SFTCON);
19093a7515aSWenping Zhang 	delay = 1000;
19193a7515aSWenping Zhang 	do {
19293a7515aSWenping Zhang 		udelay(1);
19393a7515aSWenping Zhang 		delay--;
19493a7515aSWenping Zhang 		if (delay == 0) {
19593a7515aSWenping Zhang 			printf("Enable rga pd for ebc failed !\n");
19693a7515aSWenping Zhang 			return -1;
19793a7515aSWenping Zhang 		}
19893a7515aSWenping Zhang 	} while (readl(PMU_BASE_ADDR + PMU_PWR_DWN_ST) & pd_stat);
19993a7515aSWenping Zhang 
20093a7515aSWenping Zhang 	return 0;
20193a7515aSWenping Zhang }
20293a7515aSWenping Zhang 
20393a7515aSWenping Zhang static inline void tcon_write(struct ebc_tcon_priv *tcon, unsigned int reg,
20493a7515aSWenping Zhang 			      unsigned int value)
20593a7515aSWenping Zhang {
20693a7515aSWenping Zhang 	unsigned int *cache = tcon->regcache + (reg >> 2);
20793a7515aSWenping Zhang 
20893a7515aSWenping Zhang 	writel(value, tcon->reg + reg);
20993a7515aSWenping Zhang 	*cache = value;
21093a7515aSWenping Zhang }
21193a7515aSWenping Zhang 
21293a7515aSWenping Zhang static inline unsigned int tcon_read(struct ebc_tcon_priv *tcon,
21393a7515aSWenping Zhang 				     unsigned int reg)
21493a7515aSWenping Zhang {
21593a7515aSWenping Zhang 	return readl(tcon->reg + reg);
21693a7515aSWenping Zhang }
21793a7515aSWenping Zhang 
21893a7515aSWenping Zhang static inline void tcon_update_bits(struct ebc_tcon_priv *tcon,
21993a7515aSWenping Zhang 				    unsigned int reg, unsigned int mask,
22093a7515aSWenping Zhang 				    unsigned int val)
22193a7515aSWenping Zhang {
22293a7515aSWenping Zhang 	unsigned int tmp;
22393a7515aSWenping Zhang 	unsigned int *cache = tcon->regcache + (reg >> 2);
22493a7515aSWenping Zhang 
22593a7515aSWenping Zhang 	tmp = *cache & ~mask;
22693a7515aSWenping Zhang 	tmp |= val & mask;
22793a7515aSWenping Zhang 
22893a7515aSWenping Zhang 	writel(tmp, tcon->reg + reg);
22993a7515aSWenping Zhang 	*cache = tmp;
23093a7515aSWenping Zhang }
23193a7515aSWenping Zhang 
23293a7515aSWenping Zhang #ifdef CONFIG_IRQ
23393a7515aSWenping Zhang static void ebc_irq_handler(int irq, void *data)
23493a7515aSWenping Zhang {
23593a7515aSWenping Zhang 	u32 intr_status;
23693a7515aSWenping Zhang 	struct udevice *dev = data;
23793a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
23893a7515aSWenping Zhang 
23993a7515aSWenping Zhang 	intr_status = readl(tcon->reg + EBC_INT_STATUS);
24093a7515aSWenping Zhang 
24193a7515aSWenping Zhang 	if (intr_status & DSP_END_INT) {
24293a7515aSWenping Zhang 		tcon_update_bits(tcon, EBC_INT_STATUS,
24393a7515aSWenping Zhang 				 DSP_END_INT_CLR, DSP_END_INT_CLR);
24439939100SWenping Zhang 		last_frame_done = 1;
24593a7515aSWenping Zhang 	}
24693a7515aSWenping Zhang }
24793a7515aSWenping Zhang #endif
24893a7515aSWenping Zhang 
24993a7515aSWenping Zhang static inline void tcon_cfg_done(struct ebc_tcon_priv *tcon)
25093a7515aSWenping Zhang {
25193a7515aSWenping Zhang 	writel(REG_LOAD_GLOBAL_EN, tcon->reg + EBC_CONFIG_DONE);
25293a7515aSWenping Zhang }
25393a7515aSWenping Zhang 
25493a7515aSWenping Zhang static int ebc_tcon_enable(struct udevice *dev, struct ebc_panel *panel)
25593a7515aSWenping Zhang {
256f968f3bcSZorro Liu 	int ret;
25793a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
25893a7515aSWenping Zhang 
25993a7515aSWenping Zhang 	/* panel timing and win info config */
26093a7515aSWenping Zhang 	tcon_write(tcon, EBC_DSP_HTIMING0,
26193a7515aSWenping Zhang 		   DSP_HTOTAL(panel->lsl + panel->lbl + panel->ldl +
262*514e00a9SZorro Liu 			      panel->lel) | DSP_HS_END(panel->lsl));
26393a7515aSWenping Zhang 	tcon_write(tcon, EBC_DSP_HTIMING1,
26493a7515aSWenping Zhang 		   DSP_HACT_END(panel->lsl + panel->lbl + panel->ldl) |
26593a7515aSWenping Zhang 		   DSP_HACT_ST(panel->lsl + panel->lbl - 1));
26693a7515aSWenping Zhang 	tcon_write(tcon, EBC_DSP_VTIMING0,
26793a7515aSWenping Zhang 		   DSP_VTOTAL(panel->fsl + panel->fbl + panel->fdl +
26893a7515aSWenping Zhang 			      panel->fel) | DSP_VS_END(panel->fsl));
26993a7515aSWenping Zhang 	tcon_write(tcon, EBC_DSP_VTIMING1,
27093a7515aSWenping Zhang 		   DSP_VACT_END(panel->fsl + panel->fbl + panel->fdl) |
27193a7515aSWenping Zhang 		   DSP_VACT_ST(panel->fsl + panel->fbl));
27293a7515aSWenping Zhang 	tcon_write(tcon, EBC_DSP_ACT_INFO,
27393a7515aSWenping Zhang 		   DSP_HEIGHT(panel->height) |
27493a7515aSWenping Zhang 		   DSP_WIDTH(panel->width));
27593a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_VIR,
2769876686dSWenping Zhang 		   WIN_VIR_HEIGHT(panel->vir_height) |
2779876686dSWenping Zhang 		   WIN_VIR_WIDTH(panel->vir_width));
27893a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_ACT,
27993a7515aSWenping Zhang 		   WIN_ACT_HEIGHT(panel->height) |
28093a7515aSWenping Zhang 		   WIN_ACT_WIDTH(panel->width));
28193a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_DSP,
28293a7515aSWenping Zhang 		   WIN_DSP_HEIGHT(panel->height) |
28393a7515aSWenping Zhang 		   WIN_DSP_WIDTH(panel->width));
28493a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_DSP_ST,
28593a7515aSWenping Zhang 		   WIN_DSP_YST(panel->fsl + panel->fbl) |
28693a7515aSWenping Zhang 		   WIN_DSP_XST(panel->lsl + panel->lbl));
28793a7515aSWenping Zhang 
28893a7515aSWenping Zhang 	/* win2 fifo is 512x128, win fifo is 256x128,
28993a7515aSWenping Zhang 	 * we set fifo almost value (fifo_size - 16)
29093a7515aSWenping Zhang 	 * burst_reg = 7 mean ahb burst is incr16
29193a7515aSWenping Zhang 	 */
29293a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_CTRL,
29393a7515aSWenping Zhang 		   WIN2_FIFO_ALMOST_FULL_LEVEL(496) | WIN_EN(1) |
29493a7515aSWenping Zhang 		   BURST_REG(7) | WIN_FIFO_ALMOST_FULL_LEVEL(240) |
29593a7515aSWenping Zhang 		   WIN_FMT(Y_DATA_4BPP));
29693a7515aSWenping Zhang 
29793a7515aSWenping Zhang 	/*
29893a7515aSWenping Zhang 	 * EBC_EPD_CTRL info:
29993a7515aSWenping Zhang 	 * DSP_GD_ST: GCLK rising edge point(SCLK), which count from
30093a7515aSWenping Zhang 	 *            the rasing edge of hsync(spec is wrong, count
30193a7515aSWenping Zhang 	 *            from rasing edge of hsync, not falling edge of hsync)
30293a7515aSWenping Zhang 	 * DSP_GD_END : GCLK falling edge point(SCLK), which count from
30393a7515aSWenping Zhang 	 *              the rasing edge of hsync
30493a7515aSWenping Zhang 	 * DSP_THREE_WIN_MODE: 0: lut mode or direct mode; 1: three win mode
30593a7515aSWenping Zhang 	 * DSP_SDDW_MODE: 0: 8 bit data output; 1: 16 bit data output
30693a7515aSWenping Zhang 	 * EPD_AUO: 0: EINK; 1:AUO
30793a7515aSWenping Zhang 	 * EPD_GDRL: gate scanning direction: 1:button to top 0:top to button
30893a7515aSWenping Zhang 	 * EPD_SDSHR: source scanning direction 1:right to left 0:left to right
30993a7515aSWenping Zhang 	 */
31093a7515aSWenping Zhang 	tcon_write(tcon, EBC_EPD_CTRL,
31193a7515aSWenping Zhang 		   EINK_MODE_SWAP(1) |
31293a7515aSWenping Zhang 		   DSP_GD_ST(panel->lsl + panel->gdck_sta) |
31393a7515aSWenping Zhang 		   DSP_GD_END(panel->lsl + panel->gdck_sta + panel->lgonl) |
31493a7515aSWenping Zhang 		   DSP_THREE_WIN_MODE(0) |
31593a7515aSWenping Zhang 		   DSP_SDDW_MODE(!!panel->panel_16bit) |
31693a7515aSWenping Zhang 		   EPD_AUO(0) |
31793a7515aSWenping Zhang 		   EPD_GDRL(1) |
31893a7515aSWenping Zhang 		   EPD_SDSHR(1));
31993a7515aSWenping Zhang 	tcon_write(tcon, EBC_DSP_START,
32093a7515aSWenping Zhang 		   DSP_SDCE_WIDTH(panel->ldl) | SW_BURST_CTRL);
32193a7515aSWenping Zhang 
32293a7515aSWenping Zhang 	tcon_write(tcon, EBC_DSP_CTRL,
32393a7515aSWenping Zhang 		   DSP_SWAP_MODE(panel->panel_16bit ? 2 : 3) |
32493a7515aSWenping Zhang 		   DSP_VCOM_MODE(1) |
32593a7515aSWenping Zhang 		   DSP_SDCLK_DIV(panel->panel_16bit ? 7 : 3));
32693a7515aSWenping Zhang 
32793a7515aSWenping Zhang 	tcon_cfg_done(tcon);
32893a7515aSWenping Zhang 
329f968f3bcSZorro Liu 	ret = clk_set_rate(&tcon->dclk, panel->sdck * ((panel->panel_16bit ? 7 : 3) + 1));
330f968f3bcSZorro Liu 	if (ret < 0) {
331f968f3bcSZorro Liu 		printf("%s: set clock rate failed, %d\n", __func__, ret);
332f968f3bcSZorro Liu 		return ret;
333f968f3bcSZorro Liu 	}
334f968f3bcSZorro Liu 
33593a7515aSWenping Zhang 	return 0;
33693a7515aSWenping Zhang }
33793a7515aSWenping Zhang 
33893a7515aSWenping Zhang static int ebc_tcon_disable(struct udevice *dev)
33993a7515aSWenping Zhang {
34093a7515aSWenping Zhang 	return 0;
34193a7515aSWenping Zhang }
34293a7515aSWenping Zhang 
34393a7515aSWenping Zhang static int ebc_tcon_dsp_mode_set(struct udevice *dev, int update_mode,
34493a7515aSWenping Zhang 				 int display_mode, int three_win_mode,
34593a7515aSWenping Zhang 				 int eink_mode)
34693a7515aSWenping Zhang {
34793a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
34893a7515aSWenping Zhang 
34993a7515aSWenping Zhang 	tcon_update_bits(tcon, EBC_DSP_CTRL,
35093a7515aSWenping Zhang 			 UPDATE_MODE_MASK | DISPLAY_MODE_MASK,
35193a7515aSWenping Zhang 			 DSP_UPDATE_MODE(!!update_mode) |
35293a7515aSWenping Zhang 			 DSP_DISPLAY_MODE(!!display_mode));
35393a7515aSWenping Zhang 
35493a7515aSWenping Zhang 	tcon_update_bits(tcon, EBC_EPD_CTRL, THREE_WIN_MODE_MASK,
35593a7515aSWenping Zhang 			 DSP_THREE_WIN_MODE(!!three_win_mode));
35693a7515aSWenping Zhang 	/* always set frm start bit 0 before real frame start */
35793a7515aSWenping Zhang 	tcon_update_bits(tcon, EBC_DSP_START,
35893a7515aSWenping Zhang 			 DSP_EINK_MODE_MASK | DSP_FRM_START_MASK,
35993a7515aSWenping Zhang 			 DSP_EINK_MODE(!!eink_mode));
36093a7515aSWenping Zhang 	tcon_cfg_done(tcon);
36193a7515aSWenping Zhang 
36293a7515aSWenping Zhang 	return 0;
36393a7515aSWenping Zhang }
36493a7515aSWenping Zhang 
36593a7515aSWenping Zhang static int ebc_tcon_image_addr_set(struct udevice *dev, u32 pre_image_addr,
36693a7515aSWenping Zhang 				   u32 cur_image_addr)
36793a7515aSWenping Zhang {
36893a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
36993a7515aSWenping Zhang 
37093a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_MST0, pre_image_addr);
37193a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_MST1, cur_image_addr);
37293a7515aSWenping Zhang 	tcon_cfg_done(tcon);
37393a7515aSWenping Zhang 
37493a7515aSWenping Zhang 	return 0;
37593a7515aSWenping Zhang }
37693a7515aSWenping Zhang 
37793a7515aSWenping Zhang static int ebc_tcon_frame_addr_set(struct udevice *dev, u32 frame_addr)
37893a7515aSWenping Zhang {
37993a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
38093a7515aSWenping Zhang 
38193a7515aSWenping Zhang 	tcon_write(tcon, EBC_WIN_MST2, frame_addr);
38293a7515aSWenping Zhang 	tcon_cfg_done(tcon);
38393a7515aSWenping Zhang 
38493a7515aSWenping Zhang 	return 0;
38593a7515aSWenping Zhang }
38693a7515aSWenping Zhang 
38793a7515aSWenping Zhang static int ebc_tcon_lut_data_set(struct udevice *dev, unsigned int *lut_data,
38893a7515aSWenping Zhang 				 int frame_count, int lut_32)
38993a7515aSWenping Zhang {
39093a7515aSWenping Zhang 	int i, lut_size;
39193a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
39293a7515aSWenping Zhang 
39393a7515aSWenping Zhang 	if ((!lut_32 && frame_count > 256) || (lut_32 && frame_count > 64)) {
39493a7515aSWenping Zhang 		dev_err(tcon->dev, "frame count over flow\n");
39593a7515aSWenping Zhang 		return -1;
39693a7515aSWenping Zhang 	}
39793a7515aSWenping Zhang 
39893a7515aSWenping Zhang 	if (lut_32)
39993a7515aSWenping Zhang 		lut_size = frame_count * 64;
40093a7515aSWenping Zhang 	else
40193a7515aSWenping Zhang 		lut_size = frame_count * 16;
40293a7515aSWenping Zhang 
40393a7515aSWenping Zhang 	for (i = 0; i < lut_size; i++)
40493a7515aSWenping Zhang 		tcon_write(tcon, EBC_LUT_DATA_ADDR + (i * 4), lut_data[i]);
40593a7515aSWenping Zhang 
40693a7515aSWenping Zhang 	tcon_cfg_done(tcon);
40793a7515aSWenping Zhang 
40893a7515aSWenping Zhang 	return 0;
40993a7515aSWenping Zhang }
41093a7515aSWenping Zhang 
41193a7515aSWenping Zhang static int wait_for_last_frame_complete(struct udevice *dev)
41293a7515aSWenping Zhang {
41393a7515aSWenping Zhang #ifndef CONFIG_IRQ
41493a7515aSWenping Zhang 	u32 intr_status;
41593a7515aSWenping Zhang #endif
41693a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
41793a7515aSWenping Zhang 
41893a7515aSWenping Zhang #ifdef CONFIG_IRQ
41939939100SWenping Zhang 	while (1) {
42039939100SWenping Zhang 		if ((last_frame_done == -1) || (last_frame_done == 1))
42139939100SWenping Zhang 			break;
42293a7515aSWenping Zhang 		msleep(1);
42339939100SWenping Zhang 	}
42493a7515aSWenping Zhang #else
42593a7515aSWenping Zhang 	/* wait for frame display end*/
42639939100SWenping Zhang 	while (1) {
42739939100SWenping Zhang 		/* first frame don't need to wait*/
42839939100SWenping Zhang 		if (last_frame_done == -1)
42939939100SWenping Zhang 			break;
43093a7515aSWenping Zhang 		intr_status = readl(tcon->reg + EBC_INT_STATUS);
43139939100SWenping Zhang 		if (intr_status & DSP_END_INT)
43239939100SWenping Zhang 			break;
43339939100SWenping Zhang 		msleep(1);
43439939100SWenping Zhang 	}
43593a7515aSWenping Zhang #endif
43693a7515aSWenping Zhang 	tcon_update_bits(tcon, EBC_INT_STATUS,
43793a7515aSWenping Zhang 			 DSP_END_INT_CLR, DSP_END_INT_CLR);
43893a7515aSWenping Zhang 
43993a7515aSWenping Zhang 	return 0;
44093a7515aSWenping Zhang }
44193a7515aSWenping Zhang 
44293a7515aSWenping Zhang static int ebc_tcon_frame_start(struct udevice *dev, int frame_total)
44393a7515aSWenping Zhang {
44493a7515aSWenping Zhang 	struct ebc_tcon_priv *tcon = dev_get_priv(dev);
44593a7515aSWenping Zhang 
44693a7515aSWenping Zhang 	tcon_write(tcon, EBC_INT_STATUS,
44793a7515aSWenping Zhang 		   LINE_FLAG_INT_MASK | DSP_FRM_INT_MASK | FRM_END_INT_MASK);
44893a7515aSWenping Zhang 	tcon_update_bits(tcon, EBC_DSP_START,
44993a7515aSWenping Zhang 			 DSP_FRM_TOTAL_MASK, DSP_FRM_TOTAL(frame_total - 1));
45093a7515aSWenping Zhang 	tcon_cfg_done(tcon);
45193a7515aSWenping Zhang 
45293a7515aSWenping Zhang 	tcon_update_bits(tcon, EBC_DSP_START,
45393a7515aSWenping Zhang 			 DSP_FRM_START_MASK, DSP_FRM_START);
45439939100SWenping Zhang 	last_frame_done = 0;
45593a7515aSWenping Zhang 	return 0;
45693a7515aSWenping Zhang }
45793a7515aSWenping Zhang 
45893a7515aSWenping Zhang static int rk_ebc_tcon_probe(struct udevice *dev)
45993a7515aSWenping Zhang {
46093a7515aSWenping Zhang 	int ret;
46193a7515aSWenping Zhang 	struct ebc_tcon_priv *priv = dev_get_priv(dev);
46293a7515aSWenping Zhang 
46393a7515aSWenping Zhang 	/*Enable PD first*/
46493a7515aSWenping Zhang 	ret = ebc_power_domain(1);
46593a7515aSWenping Zhang 	if (ret) {
46693a7515aSWenping Zhang 		printf("%s, enable pd failed\n", __func__);
46793a7515aSWenping Zhang 		return -1;
46893a7515aSWenping Zhang 	}
46993a7515aSWenping Zhang 
47093a7515aSWenping Zhang 	priv->dev = dev;
471f968f3bcSZorro Liu 	ret = clk_get_by_index(dev, 1, &priv->dclk);
472f968f3bcSZorro Liu 	if (ret < 0) {
473f968f3bcSZorro Liu 		printf("%s get clock fail! %d\n", __func__, ret);
474f968f3bcSZorro Liu 		return -EINVAL;
475f968f3bcSZorro Liu 	}
47693a7515aSWenping Zhang 
47793a7515aSWenping Zhang #ifdef CONFIG_IRQ
47893a7515aSWenping Zhang 	irq_install_handler(IRQ_EBC, ebc_irq_handler, dev);
47993a7515aSWenping Zhang 	irq_handler_enable(IRQ_EBC);
48093a7515aSWenping Zhang #endif
48193a7515aSWenping Zhang 	return 0;
48293a7515aSWenping Zhang }
48393a7515aSWenping Zhang 
48493a7515aSWenping Zhang const struct rk_ebc_tcon_ops ebc_tcon_funcs = {
48593a7515aSWenping Zhang 	.enable = ebc_tcon_enable,
48693a7515aSWenping Zhang 	.disable = ebc_tcon_disable,
48793a7515aSWenping Zhang 	.dsp_mode_set = ebc_tcon_dsp_mode_set,
48893a7515aSWenping Zhang 	.image_addr_set = ebc_tcon_image_addr_set,
48993a7515aSWenping Zhang 	.frame_addr_set = ebc_tcon_frame_addr_set,
49093a7515aSWenping Zhang 	.lut_data_set = ebc_tcon_lut_data_set,
49193a7515aSWenping Zhang 	.frame_start = ebc_tcon_frame_start,
49293a7515aSWenping Zhang 	.wait_for_last_frame_complete = wait_for_last_frame_complete,
49393a7515aSWenping Zhang };
49493a7515aSWenping Zhang 
49593a7515aSWenping Zhang static int rk_ebc_tcon_ofdata_to_platdata(struct udevice *dev)
49693a7515aSWenping Zhang {
49793a7515aSWenping Zhang 	fdt_size_t size;
49893a7515aSWenping Zhang 	fdt_addr_t addr;
49993a7515aSWenping Zhang 	struct ebc_tcon_priv *priv = dev_get_priv(dev);
50093a7515aSWenping Zhang 
50193a7515aSWenping Zhang 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
50293a7515aSWenping Zhang 	if (priv->grf <= 0) {
50393a7515aSWenping Zhang 		debug("%s: Get syscon grf failed (ret=%p)\n",
50493a7515aSWenping Zhang 		      __func__, priv->grf);
50593a7515aSWenping Zhang 		return  -ENXIO;
50693a7515aSWenping Zhang 	}
50793a7515aSWenping Zhang 	priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
50893a7515aSWenping Zhang 	if (priv->pmugrf <= 0) {
50993a7515aSWenping Zhang 		debug("%s: Get syscon pmugrf failed (ret=%p)\n",
51093a7515aSWenping Zhang 		      __func__, priv->grf);
51193a7515aSWenping Zhang 		return  -ENXIO;
51293a7515aSWenping Zhang 	}
51393a7515aSWenping Zhang 	addr = dev_read_addr_size(dev, "reg", &size);
51493a7515aSWenping Zhang 	if (addr == FDT_ADDR_T_NONE) {
51593a7515aSWenping Zhang 		debug("%s: Get ebc_tcon address failed\n", __func__);
51693a7515aSWenping Zhang 		return  -ENXIO;
51793a7515aSWenping Zhang 	}
51893a7515aSWenping Zhang 
51993a7515aSWenping Zhang 	priv->reg = ioremap(addr, size);
52093a7515aSWenping Zhang 	priv->reg_len = size;
52193a7515aSWenping Zhang 	priv->regcache = malloc(size);
52293a7515aSWenping Zhang 	memset(priv->regcache, 0, size);
52393a7515aSWenping Zhang 	return 0;
52493a7515aSWenping Zhang }
52593a7515aSWenping Zhang 
52693a7515aSWenping Zhang static const struct udevice_id ebc_tcon_ids[] = {
52793a7515aSWenping Zhang 	{ .compatible = "rockchip,rk3568-ebc-tcon" },
52893a7515aSWenping Zhang 	{ }
52993a7515aSWenping Zhang };
53093a7515aSWenping Zhang 
53193a7515aSWenping Zhang U_BOOT_DRIVER(rk_ebc_tcon) = {
53293a7515aSWenping Zhang 	.name	= "rk_ebc_tcon",
53393a7515aSWenping Zhang 	.id	= UCLASS_EBC,
53493a7515aSWenping Zhang 	.of_match = ebc_tcon_ids,
53593a7515aSWenping Zhang 	.ofdata_to_platdata = rk_ebc_tcon_ofdata_to_platdata,
53693a7515aSWenping Zhang 	.probe	= rk_ebc_tcon_probe,
53793a7515aSWenping Zhang 	.ops	= &ebc_tcon_funcs,
53893a7515aSWenping Zhang 	.priv_auto_alloc_size   = sizeof(struct ebc_tcon_priv),
53993a7515aSWenping Zhang };
54093a7515aSWenping Zhang 
54193a7515aSWenping Zhang UCLASS_DRIVER(ebc_tcon) = {
54293a7515aSWenping Zhang 	.id	= UCLASS_EBC,
54393a7515aSWenping Zhang 	.name	= "ebc_tcon",
54493a7515aSWenping Zhang };
54593a7515aSWenping Zhang 
546