1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Wenping Zhang <wenping.zhang@rock-chips.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <clk.h>
9*4882a593Smuzhiyun #include <dm.h>
10*4882a593Smuzhiyun #include <dm/pinctrl.h>
11*4882a593Smuzhiyun #include <pwm.h>
12*4882a593Smuzhiyun #include <regmap.h>
13*4882a593Smuzhiyun #include <syscon.h>
14*4882a593Smuzhiyun #include <asm/arch/clock.h>
15*4882a593Smuzhiyun #include <asm/io.h>
16*4882a593Smuzhiyun #include <syscon.h>
17*4882a593Smuzhiyun #include <linux/io.h>
18*4882a593Smuzhiyun #include "rk_ebc.h"
19*4882a593Smuzhiyun #ifdef CONFIG_IRQ
20*4882a593Smuzhiyun #include <irq-generic.h>
21*4882a593Smuzhiyun #endif
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct ebc_tcon_priv {
24*4882a593Smuzhiyun struct udevice *dev;
25*4882a593Smuzhiyun void __iomem *reg;
26*4882a593Smuzhiyun u32 *regcache;
27*4882a593Smuzhiyun u32 reg_len;
28*4882a593Smuzhiyun void *grf;
29*4882a593Smuzhiyun void *pmugrf;
30*4882a593Smuzhiyun struct clk dclk;
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define msleep(a) udelay((a) * 1000)
34*4882a593Smuzhiyun #define HIWORD_UPDATE(x, l, h) (((x) << (l)) | (GENMASK(h, l) << 16))
35*4882a593Smuzhiyun #define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define REG_LOAD_GLOBAL_EN 0x1
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /* ebc register define */
40*4882a593Smuzhiyun #define EBC_DSP_START 0x0000 //Frame statrt register
41*4882a593Smuzhiyun #define EBC_EPD_CTRL 0x0004 //EPD control register
42*4882a593Smuzhiyun #define EBC_DSP_CTRL 0x0008 //Display control register
43*4882a593Smuzhiyun #define EBC_DSP_HTIMING0 0x000c //H-Timing setting register0
44*4882a593Smuzhiyun #define EBC_DSP_HTIMING1 0x0010 //H-Timing setting register1
45*4882a593Smuzhiyun #define EBC_DSP_VTIMING0 0x0014 //V-Timing setting register0
46*4882a593Smuzhiyun #define EBC_DSP_VTIMING1 0x0018 //V-Timing setting register1
47*4882a593Smuzhiyun #define EBC_DSP_ACT_INFO 0x001c //ACTIVE width/height
48*4882a593Smuzhiyun #define EBC_WIN_CTRL 0x0020 //Window ctrl
49*4882a593Smuzhiyun #define EBC_WIN_MST0 0x0024 //Current win memory start
50*4882a593Smuzhiyun #define EBC_WIN_MST1 0x0028 //Next win memory start
51*4882a593Smuzhiyun #define EBC_WIN_VIR 0x002c //Window vir width/height
52*4882a593Smuzhiyun #define EBC_WIN_ACT 0x0030 //Window act width/height
53*4882a593Smuzhiyun #define EBC_WIN_DSP 0x0034 //Window dsp width/height
54*4882a593Smuzhiyun #define EBC_WIN_DSP_ST 0x0038 //Window display start point
55*4882a593Smuzhiyun #define EBC_INT_STATUS 0x003c //Interrupt register
56*4882a593Smuzhiyun #define EBC_VCOM0 0x0040 //VCOM setting register0
57*4882a593Smuzhiyun #define EBC_VCOM1 0x0044 //VCOM setting register1
58*4882a593Smuzhiyun #define EBC_VCOM2 0x0048 //VCOM setting register2
59*4882a593Smuzhiyun #define EBC_VCOM3 0x004c //VCOM setting register3
60*4882a593Smuzhiyun #define EBC_CONFIG_DONE 0x0050 //Config done register
61*4882a593Smuzhiyun #define EBC_VNUM 0x0054 //Line flag num
62*4882a593Smuzhiyun #define EBC_WIN_MST2 0x0058 //Framecount memory start
63*4882a593Smuzhiyun #define EBC_LUT_DATA_ADDR 0x1000 //lut data address
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun #define DSP_HTOTAL(x) UPDATE(x, 27, 16)
66*4882a593Smuzhiyun #define DSP_HS_END(x) UPDATE(x, 7, 0)
67*4882a593Smuzhiyun #define DSP_HACT_END(x) UPDATE(x, 26, 16)
68*4882a593Smuzhiyun #define DSP_HACT_ST(x) UPDATE(x, 7, 0)
69*4882a593Smuzhiyun #define DSP_VTOTAL(x) UPDATE(x, 26, 16)
70*4882a593Smuzhiyun #define DSP_VS_END(x) UPDATE(x, 7, 0)
71*4882a593Smuzhiyun #define DSP_VACT_END(x) UPDATE(x, 26, 16)
72*4882a593Smuzhiyun #define DSP_VACT_ST(x) UPDATE(x, 7, 0)
73*4882a593Smuzhiyun #define DSP_HEIGHT(x) UPDATE(x, 26, 16)
74*4882a593Smuzhiyun #define DSP_WIDTH(x) UPDATE(x, 11, 0)
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #define WIN2_FIFO_ALMOST_FULL_LEVEL(x) UPDATE(x, 27, 19)
77*4882a593Smuzhiyun #define WIN_EN(x) UPDATE(x, 18, 18)
78*4882a593Smuzhiyun #define BURST_REG(x) UPDATE(x, 12, 10)
79*4882a593Smuzhiyun #define WIN_FIFO_ALMOST_FULL_LEVEL(x) UPDATE(x, 9, 2)
80*4882a593Smuzhiyun #define WIN_FMT(x) UPDATE(x, 1, 0)
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun #define WIN_VIR_HEIGHT(x) UPDATE(x, 31, 16)
83*4882a593Smuzhiyun #define WIN_VIR_WIDTH(x) UPDATE(x, 15, 0)
84*4882a593Smuzhiyun #define WIN_ACT_HEIGHT(x) UPDATE(x, 26, 16)
85*4882a593Smuzhiyun #define WIN_ACT_WIDTH(x) UPDATE(x, 11, 0)
86*4882a593Smuzhiyun #define WIN_DSP_HEIGHT(x) UPDATE(x, 26, 16)
87*4882a593Smuzhiyun #define WIN_DSP_WIDTH(x) UPDATE(x, 11, 0)
88*4882a593Smuzhiyun #define WIN_DSP_YST(x) UPDATE(x, 26, 16)
89*4882a593Smuzhiyun #define WIN_DSP_XST(x) UPDATE(x, 11, 0)
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun #define DSP_OUT_LOW BIT(31)
92*4882a593Smuzhiyun #define DSP_EINK_MODE(x) UPDATE(x, 13, 13)
93*4882a593Smuzhiyun #define DSP_EINK_MODE_MASK BIT(13)
94*4882a593Smuzhiyun #define DSP_SDCE_WIDTH(x) UPDATE(x, 25, 16)
95*4882a593Smuzhiyun #define DSP_FRM_TOTAL(x) UPDATE(x, 9, 2)
96*4882a593Smuzhiyun #define DSP_FRM_TOTAL_MASK GENMASK(9, 2)
97*4882a593Smuzhiyun #define DSP_FRM_START BIT(0)
98*4882a593Smuzhiyun #define DSP_FRM_START_MASK BIT(0)
99*4882a593Smuzhiyun #define SW_BURST_CTRL BIT(12)
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun #define EINK_MODE_SWAP(x) UPDATE(x, 31, 31)
102*4882a593Smuzhiyun #define EINK_MODE_FRM_SEL(x) UPDATE(x, 30, 30)
103*4882a593Smuzhiyun #define DSP_GD_END(x) UPDATE(x, 26, 16)
104*4882a593Smuzhiyun #define DSP_GD_ST(x) UPDATE(x, 15, 8)
105*4882a593Smuzhiyun #define DSP_THREE_WIN_MODE(x) UPDATE(x, 7, 7)
106*4882a593Smuzhiyun #define THREE_WIN_MODE_MASK BIT(7)
107*4882a593Smuzhiyun #define DSP_SDDW_MODE(x) UPDATE(x, 6, 6)
108*4882a593Smuzhiyun #define EPD_AUO(x) UPDATE(x, 5, 5)
109*4882a593Smuzhiyun #define EPD_PWR(x) UPDATE(x, 4, 2)
110*4882a593Smuzhiyun #define EPD_GDRL(x) UPDATE(x, 1, 1)
111*4882a593Smuzhiyun #define EPD_SDSHR(x) UPDATE(x, 0, 0)
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun #define DSP_SWAP_MODE(x) UPDATE(x, 31, 30)
114*4882a593Smuzhiyun #define DSP_SWAP_MODE_MASK GENMASK(31, 30)
115*4882a593Smuzhiyun #define DSP_SDCLK_DIV(x) UPDATE(x, 19, 16)
116*4882a593Smuzhiyun #define DSP_SDCLK_DIV_MASK GENMASK(19, 16)
117*4882a593Smuzhiyun #define DSP_VCOM_MODE(x) UPDATE(x, 27, 27)
118*4882a593Smuzhiyun #define DSP_VCOM_MODE_MASK BIT(27)
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun #define DSP_UPDATE_MODE(x) UPDATE(x, 29, 29)
121*4882a593Smuzhiyun #define DSP_DISPLAY_MODE(x) UPDATE(x, 28, 28)
122*4882a593Smuzhiyun #define UPDATE_MODE_MASK BIT(29)
123*4882a593Smuzhiyun #define DISPLAY_MODE_MASK BIT(28)
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun #define DSP_FRM_INT_NUM(x) UPDATE(x, 19, 12)
126*4882a593Smuzhiyun #define FRM_END_INT BIT(0)
127*4882a593Smuzhiyun #define DSP_END_INT BIT(1)
128*4882a593Smuzhiyun #define DSP_FRM_INT BIT(2)
129*4882a593Smuzhiyun #define LINE_FLAG_INT BIT(3)
130*4882a593Smuzhiyun #define FRM_END_INT_MASK BIT(4)
131*4882a593Smuzhiyun #define DSP_END_INT_MASK BIT(5)
132*4882a593Smuzhiyun #define DSP_FRM_INT_MASK BIT(6)
133*4882a593Smuzhiyun #define LINE_FLAG_INT_MASK BIT(7)
134*4882a593Smuzhiyun #define FRM_END_INT_CLR BIT(8)
135*4882a593Smuzhiyun #define DSP_END_INT_CLR BIT(9)
136*4882a593Smuzhiyun #define DSP_FRM_INT_CLR BIT(10)
137*4882a593Smuzhiyun #define LINE_FLAG_INT_CLR BIT(11)
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define PMU_BASE_ADDR 0xfdd90000
140*4882a593Smuzhiyun #define PMU_PWR_GATE_SFTCON 0xA0
141*4882a593Smuzhiyun #define PMU_PWR_DWN_ST 0x98
142*4882a593Smuzhiyun #define RGA_PD_OFF BIT(5)
143*4882a593Smuzhiyun #define RGA_PD_STAT BIT(5)
144*4882a593Smuzhiyun enum ebc_win_data_fmt {
145*4882a593Smuzhiyun Y_DATA_4BPP = 0,
146*4882a593Smuzhiyun Y_DATA_8BPP = 1,
147*4882a593Smuzhiyun RGB888 = 2,
148*4882a593Smuzhiyun RGB565 = 3,
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun #ifdef CONFIG_IRQ
152*4882a593Smuzhiyun #define IRQ_EBC 49
153*4882a593Smuzhiyun #endif
154*4882a593Smuzhiyun static volatile int last_frame_done = -1;
regs_dump(struct ebc_tcon_priv * tcon)155*4882a593Smuzhiyun static inline void regs_dump(struct ebc_tcon_priv *tcon)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun int i;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun printf("dump registers:\n");
160*4882a593Smuzhiyun for (i = 0; i <= EBC_WIN_MST2; i = i + 4) {
161*4882a593Smuzhiyun if (!(i % 16))
162*4882a593Smuzhiyun printf("\n 0x%p:\t", tcon->reg + i);
163*4882a593Smuzhiyun printf("0x%x\t", readl(tcon->reg + i));
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun printf("\nlut data:\n");
166*4882a593Smuzhiyun for (i = 0x1000; i <= 0x1100; i = i + 4) {
167*4882a593Smuzhiyun if (!(i % 16))
168*4882a593Smuzhiyun printf("\n 0x%p:\t", tcon->reg + i);
169*4882a593Smuzhiyun printf("0x%x\t", readl(tcon->reg + i));
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun printf("\n");
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
ebc_power_domain(int on)174*4882a593Smuzhiyun static int ebc_power_domain(int on)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun u32 pd_reg;
177*4882a593Smuzhiyun u32 pd_stat;
178*4882a593Smuzhiyun int delay = 0;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun if (on) {
181*4882a593Smuzhiyun pd_reg = RGA_PD_OFF << 16;
182*4882a593Smuzhiyun pd_stat = RGA_PD_STAT;
183*4882a593Smuzhiyun } else {
184*4882a593Smuzhiyun pd_reg = RGA_PD_OFF | (RGA_PD_OFF << 16);
185*4882a593Smuzhiyun pd_stat = ~((u32)RGA_PD_STAT);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* enable rga pd for ebc tcon*/
189*4882a593Smuzhiyun writel(pd_reg, PMU_BASE_ADDR + PMU_PWR_GATE_SFTCON);
190*4882a593Smuzhiyun delay = 1000;
191*4882a593Smuzhiyun do {
192*4882a593Smuzhiyun udelay(1);
193*4882a593Smuzhiyun delay--;
194*4882a593Smuzhiyun if (delay == 0) {
195*4882a593Smuzhiyun printf("Enable rga pd for ebc failed !\n");
196*4882a593Smuzhiyun return -1;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun } while (readl(PMU_BASE_ADDR + PMU_PWR_DWN_ST) & pd_stat);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun return 0;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
tcon_write(struct ebc_tcon_priv * tcon,unsigned int reg,unsigned int value)203*4882a593Smuzhiyun static inline void tcon_write(struct ebc_tcon_priv *tcon, unsigned int reg,
204*4882a593Smuzhiyun unsigned int value)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun unsigned int *cache = tcon->regcache + (reg >> 2);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun writel(value, tcon->reg + reg);
209*4882a593Smuzhiyun *cache = value;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
tcon_read(struct ebc_tcon_priv * tcon,unsigned int reg)212*4882a593Smuzhiyun static inline unsigned int tcon_read(struct ebc_tcon_priv *tcon,
213*4882a593Smuzhiyun unsigned int reg)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun return readl(tcon->reg + reg);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
tcon_update_bits(struct ebc_tcon_priv * tcon,unsigned int reg,unsigned int mask,unsigned int val)218*4882a593Smuzhiyun static inline void tcon_update_bits(struct ebc_tcon_priv *tcon,
219*4882a593Smuzhiyun unsigned int reg, unsigned int mask,
220*4882a593Smuzhiyun unsigned int val)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun unsigned int tmp;
223*4882a593Smuzhiyun unsigned int *cache = tcon->regcache + (reg >> 2);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun tmp = *cache & ~mask;
226*4882a593Smuzhiyun tmp |= val & mask;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun writel(tmp, tcon->reg + reg);
229*4882a593Smuzhiyun *cache = tmp;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun #ifdef CONFIG_IRQ
ebc_irq_handler(int irq,void * data)233*4882a593Smuzhiyun static void ebc_irq_handler(int irq, void *data)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun u32 intr_status;
236*4882a593Smuzhiyun struct udevice *dev = data;
237*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun intr_status = readl(tcon->reg + EBC_INT_STATUS);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (intr_status & DSP_END_INT) {
242*4882a593Smuzhiyun tcon_update_bits(tcon, EBC_INT_STATUS,
243*4882a593Smuzhiyun DSP_END_INT_CLR, DSP_END_INT_CLR);
244*4882a593Smuzhiyun last_frame_done = 1;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun #endif
248*4882a593Smuzhiyun
tcon_cfg_done(struct ebc_tcon_priv * tcon)249*4882a593Smuzhiyun static inline void tcon_cfg_done(struct ebc_tcon_priv *tcon)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun writel(REG_LOAD_GLOBAL_EN, tcon->reg + EBC_CONFIG_DONE);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
ebc_tcon_enable(struct udevice * dev,struct ebc_panel * panel)254*4882a593Smuzhiyun static int ebc_tcon_enable(struct udevice *dev, struct ebc_panel *panel)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun int ret;
257*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
258*4882a593Smuzhiyun u32 width, height, vir_width, vir_height;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (panel->rearrange) {
261*4882a593Smuzhiyun width = panel->width * 2;
262*4882a593Smuzhiyun height = panel->height / 2;
263*4882a593Smuzhiyun vir_width = panel->vir_width * 2;
264*4882a593Smuzhiyun vir_height = panel->vir_height / 2;
265*4882a593Smuzhiyun } else {
266*4882a593Smuzhiyun width = panel->width;
267*4882a593Smuzhiyun height = panel->height;
268*4882a593Smuzhiyun vir_width = panel->vir_width;
269*4882a593Smuzhiyun vir_height = panel->vir_height;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* panel timing and win info config */
273*4882a593Smuzhiyun tcon_write(tcon, EBC_DSP_HTIMING0,
274*4882a593Smuzhiyun DSP_HTOTAL(panel->lsl + panel->lbl + panel->ldl +
275*4882a593Smuzhiyun panel->lel) | DSP_HS_END(panel->lsl));
276*4882a593Smuzhiyun tcon_write(tcon, EBC_DSP_HTIMING1,
277*4882a593Smuzhiyun DSP_HACT_END(panel->lsl + panel->lbl + panel->ldl) |
278*4882a593Smuzhiyun DSP_HACT_ST(panel->lsl + panel->lbl - 1));
279*4882a593Smuzhiyun tcon_write(tcon, EBC_DSP_VTIMING0,
280*4882a593Smuzhiyun DSP_VTOTAL(panel->fsl + panel->fbl + panel->fdl +
281*4882a593Smuzhiyun panel->fel) | DSP_VS_END(panel->fsl));
282*4882a593Smuzhiyun tcon_write(tcon, EBC_DSP_VTIMING1,
283*4882a593Smuzhiyun DSP_VACT_END(panel->fsl + panel->fbl + panel->fdl) |
284*4882a593Smuzhiyun DSP_VACT_ST(panel->fsl + panel->fbl));
285*4882a593Smuzhiyun tcon_write(tcon, EBC_DSP_ACT_INFO,
286*4882a593Smuzhiyun DSP_HEIGHT(height) |
287*4882a593Smuzhiyun DSP_WIDTH(width));
288*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_VIR,
289*4882a593Smuzhiyun WIN_VIR_HEIGHT(vir_height) |
290*4882a593Smuzhiyun WIN_VIR_WIDTH(vir_width));
291*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_ACT,
292*4882a593Smuzhiyun WIN_ACT_HEIGHT(height) |
293*4882a593Smuzhiyun WIN_ACT_WIDTH(width));
294*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_DSP,
295*4882a593Smuzhiyun WIN_DSP_HEIGHT(height) |
296*4882a593Smuzhiyun WIN_DSP_WIDTH(width));
297*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_DSP_ST,
298*4882a593Smuzhiyun WIN_DSP_YST(panel->fsl + panel->fbl) |
299*4882a593Smuzhiyun WIN_DSP_XST(panel->lsl + panel->lbl));
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* win2 fifo is 512x128, win fifo is 256x128,
302*4882a593Smuzhiyun * we set fifo almost value (fifo_size - 16)
303*4882a593Smuzhiyun * burst_reg = 7 mean ahb burst is incr16
304*4882a593Smuzhiyun */
305*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_CTRL,
306*4882a593Smuzhiyun WIN2_FIFO_ALMOST_FULL_LEVEL(496) | WIN_EN(1) |
307*4882a593Smuzhiyun BURST_REG(7) | WIN_FIFO_ALMOST_FULL_LEVEL(240) |
308*4882a593Smuzhiyun WIN_FMT(Y_DATA_4BPP));
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /*
311*4882a593Smuzhiyun * EBC_EPD_CTRL info:
312*4882a593Smuzhiyun * DSP_GD_ST: GCLK rising edge point(SCLK), which count from
313*4882a593Smuzhiyun * the rasing edge of hsync(spec is wrong, count
314*4882a593Smuzhiyun * from rasing edge of hsync, not falling edge of hsync)
315*4882a593Smuzhiyun * DSP_GD_END : GCLK falling edge point(SCLK), which count from
316*4882a593Smuzhiyun * the rasing edge of hsync
317*4882a593Smuzhiyun * DSP_THREE_WIN_MODE: 0: lut mode or direct mode; 1: three win mode
318*4882a593Smuzhiyun * DSP_SDDW_MODE: 0: 8 bit data output; 1: 16 bit data output
319*4882a593Smuzhiyun * EPD_AUO: 0: EINK; 1:AUO
320*4882a593Smuzhiyun * EPD_GDRL: gate scanning direction: 1:button to top 0:top to button
321*4882a593Smuzhiyun * EPD_SDSHR: source scanning direction 1:right to left 0:left to right
322*4882a593Smuzhiyun */
323*4882a593Smuzhiyun tcon_write(tcon, EBC_EPD_CTRL,
324*4882a593Smuzhiyun EINK_MODE_SWAP(1) |
325*4882a593Smuzhiyun DSP_GD_ST(panel->lsl + panel->gdck_sta) |
326*4882a593Smuzhiyun DSP_GD_END(panel->lsl + panel->gdck_sta + panel->lgonl) |
327*4882a593Smuzhiyun DSP_THREE_WIN_MODE(0) |
328*4882a593Smuzhiyun DSP_SDDW_MODE(!!panel->panel_16bit) |
329*4882a593Smuzhiyun EPD_AUO(0) |
330*4882a593Smuzhiyun EPD_GDRL(1) |
331*4882a593Smuzhiyun EPD_SDSHR(1));
332*4882a593Smuzhiyun tcon_write(tcon, EBC_DSP_START,
333*4882a593Smuzhiyun DSP_SDCE_WIDTH(panel->ldl) | SW_BURST_CTRL);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun tcon_write(tcon, EBC_DSP_CTRL,
336*4882a593Smuzhiyun DSP_SWAP_MODE(panel->panel_16bit ? 2 : 3) |
337*4882a593Smuzhiyun DSP_VCOM_MODE(1) |
338*4882a593Smuzhiyun DSP_SDCLK_DIV(panel->panel_16bit ? 7 : 3));
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun tcon_cfg_done(tcon);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun ret = clk_set_rate(&tcon->dclk, panel->sdck * ((panel->panel_16bit ? 7 : 3) + 1));
343*4882a593Smuzhiyun if (ret < 0) {
344*4882a593Smuzhiyun printf("%s: set clock rate failed, %d\n", __func__, ret);
345*4882a593Smuzhiyun return ret;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun return 0;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
ebc_tcon_disable(struct udevice * dev)351*4882a593Smuzhiyun static int ebc_tcon_disable(struct udevice *dev)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun return 0;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
ebc_tcon_dsp_mode_set(struct udevice * dev,int update_mode,int display_mode,int three_win_mode,int eink_mode)356*4882a593Smuzhiyun static int ebc_tcon_dsp_mode_set(struct udevice *dev, int update_mode,
357*4882a593Smuzhiyun int display_mode, int three_win_mode,
358*4882a593Smuzhiyun int eink_mode)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun tcon_update_bits(tcon, EBC_DSP_CTRL,
363*4882a593Smuzhiyun UPDATE_MODE_MASK | DISPLAY_MODE_MASK,
364*4882a593Smuzhiyun DSP_UPDATE_MODE(!!update_mode) |
365*4882a593Smuzhiyun DSP_DISPLAY_MODE(!!display_mode));
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun tcon_update_bits(tcon, EBC_EPD_CTRL, THREE_WIN_MODE_MASK,
368*4882a593Smuzhiyun DSP_THREE_WIN_MODE(!!three_win_mode));
369*4882a593Smuzhiyun /* always set frm start bit 0 before real frame start */
370*4882a593Smuzhiyun tcon_update_bits(tcon, EBC_DSP_START,
371*4882a593Smuzhiyun DSP_EINK_MODE_MASK | DSP_FRM_START_MASK,
372*4882a593Smuzhiyun DSP_EINK_MODE(!!eink_mode));
373*4882a593Smuzhiyun tcon_cfg_done(tcon);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
ebc_tcon_image_addr_set(struct udevice * dev,u32 pre_image_addr,u32 cur_image_addr)378*4882a593Smuzhiyun static int ebc_tcon_image_addr_set(struct udevice *dev, u32 pre_image_addr,
379*4882a593Smuzhiyun u32 cur_image_addr)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_MST0, pre_image_addr);
384*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_MST1, cur_image_addr);
385*4882a593Smuzhiyun tcon_cfg_done(tcon);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun return 0;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
ebc_tcon_frame_addr_set(struct udevice * dev,u32 frame_addr)390*4882a593Smuzhiyun static int ebc_tcon_frame_addr_set(struct udevice *dev, u32 frame_addr)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun tcon_write(tcon, EBC_WIN_MST2, frame_addr);
395*4882a593Smuzhiyun tcon_cfg_done(tcon);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
ebc_tcon_lut_data_set(struct udevice * dev,unsigned int * lut_data,int frame_count,int lut_32)400*4882a593Smuzhiyun static int ebc_tcon_lut_data_set(struct udevice *dev, unsigned int *lut_data,
401*4882a593Smuzhiyun int frame_count, int lut_32)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun int i, lut_size;
404*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun if ((!lut_32 && frame_count > 256) || (lut_32 && frame_count > 64)) {
407*4882a593Smuzhiyun dev_err(tcon->dev, "frame count over flow\n");
408*4882a593Smuzhiyun return -1;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (lut_32)
412*4882a593Smuzhiyun lut_size = frame_count * 64;
413*4882a593Smuzhiyun else
414*4882a593Smuzhiyun lut_size = frame_count * 16;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun for (i = 0; i < lut_size; i++)
417*4882a593Smuzhiyun tcon_write(tcon, EBC_LUT_DATA_ADDR + (i * 4), lut_data[i]);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun tcon_cfg_done(tcon);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun return 0;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
wait_for_last_frame_complete(struct udevice * dev)424*4882a593Smuzhiyun static int wait_for_last_frame_complete(struct udevice *dev)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun #ifndef CONFIG_IRQ
427*4882a593Smuzhiyun u32 intr_status;
428*4882a593Smuzhiyun #endif
429*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun #ifdef CONFIG_IRQ
432*4882a593Smuzhiyun while (1) {
433*4882a593Smuzhiyun if ((last_frame_done == -1) || (last_frame_done == 1))
434*4882a593Smuzhiyun break;
435*4882a593Smuzhiyun msleep(1);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun #else
438*4882a593Smuzhiyun /* wait for frame display end*/
439*4882a593Smuzhiyun while (1) {
440*4882a593Smuzhiyun /* first frame don't need to wait*/
441*4882a593Smuzhiyun if (last_frame_done == -1)
442*4882a593Smuzhiyun break;
443*4882a593Smuzhiyun intr_status = readl(tcon->reg + EBC_INT_STATUS);
444*4882a593Smuzhiyun if (intr_status & DSP_END_INT)
445*4882a593Smuzhiyun break;
446*4882a593Smuzhiyun msleep(1);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun #endif
449*4882a593Smuzhiyun tcon_update_bits(tcon, EBC_INT_STATUS,
450*4882a593Smuzhiyun DSP_END_INT_CLR, DSP_END_INT_CLR);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun return 0;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
ebc_tcon_frame_start(struct udevice * dev,int frame_total)455*4882a593Smuzhiyun static int ebc_tcon_frame_start(struct udevice *dev, int frame_total)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun struct ebc_tcon_priv *tcon = dev_get_priv(dev);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun tcon_write(tcon, EBC_INT_STATUS,
460*4882a593Smuzhiyun LINE_FLAG_INT_MASK | DSP_FRM_INT_MASK | FRM_END_INT_MASK);
461*4882a593Smuzhiyun tcon_update_bits(tcon, EBC_DSP_START,
462*4882a593Smuzhiyun DSP_FRM_TOTAL_MASK, DSP_FRM_TOTAL(frame_total - 1));
463*4882a593Smuzhiyun tcon_cfg_done(tcon);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun tcon_update_bits(tcon, EBC_DSP_START,
466*4882a593Smuzhiyun DSP_FRM_START_MASK, DSP_FRM_START);
467*4882a593Smuzhiyun last_frame_done = 0;
468*4882a593Smuzhiyun return 0;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
rk_ebc_tcon_probe(struct udevice * dev)471*4882a593Smuzhiyun static int rk_ebc_tcon_probe(struct udevice *dev)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun int ret;
474*4882a593Smuzhiyun struct ebc_tcon_priv *priv = dev_get_priv(dev);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /*Enable PD first*/
477*4882a593Smuzhiyun ret = ebc_power_domain(1);
478*4882a593Smuzhiyun if (ret) {
479*4882a593Smuzhiyun printf("%s, enable pd failed\n", __func__);
480*4882a593Smuzhiyun return -1;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun priv->dev = dev;
484*4882a593Smuzhiyun ret = clk_get_by_index(dev, 1, &priv->dclk);
485*4882a593Smuzhiyun if (ret < 0) {
486*4882a593Smuzhiyun printf("%s get clock fail! %d\n", __func__, ret);
487*4882a593Smuzhiyun return -EINVAL;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun #ifdef CONFIG_IRQ
491*4882a593Smuzhiyun irq_install_handler(IRQ_EBC, ebc_irq_handler, dev);
492*4882a593Smuzhiyun irq_handler_enable(IRQ_EBC);
493*4882a593Smuzhiyun #endif
494*4882a593Smuzhiyun return 0;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun const struct rk_ebc_tcon_ops ebc_tcon_funcs = {
498*4882a593Smuzhiyun .enable = ebc_tcon_enable,
499*4882a593Smuzhiyun .disable = ebc_tcon_disable,
500*4882a593Smuzhiyun .dsp_mode_set = ebc_tcon_dsp_mode_set,
501*4882a593Smuzhiyun .image_addr_set = ebc_tcon_image_addr_set,
502*4882a593Smuzhiyun .frame_addr_set = ebc_tcon_frame_addr_set,
503*4882a593Smuzhiyun .lut_data_set = ebc_tcon_lut_data_set,
504*4882a593Smuzhiyun .frame_start = ebc_tcon_frame_start,
505*4882a593Smuzhiyun .wait_for_last_frame_complete = wait_for_last_frame_complete,
506*4882a593Smuzhiyun };
507*4882a593Smuzhiyun
rk_ebc_tcon_ofdata_to_platdata(struct udevice * dev)508*4882a593Smuzhiyun static int rk_ebc_tcon_ofdata_to_platdata(struct udevice *dev)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun fdt_size_t size;
511*4882a593Smuzhiyun fdt_addr_t addr;
512*4882a593Smuzhiyun struct ebc_tcon_priv *priv = dev_get_priv(dev);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
515*4882a593Smuzhiyun if (priv->grf <= 0) {
516*4882a593Smuzhiyun debug("%s: Get syscon grf failed (ret=%p)\n",
517*4882a593Smuzhiyun __func__, priv->grf);
518*4882a593Smuzhiyun return -ENXIO;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
521*4882a593Smuzhiyun if (priv->pmugrf <= 0) {
522*4882a593Smuzhiyun debug("%s: Get syscon pmugrf failed (ret=%p)\n",
523*4882a593Smuzhiyun __func__, priv->grf);
524*4882a593Smuzhiyun return -ENXIO;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun addr = dev_read_addr_size(dev, "reg", &size);
527*4882a593Smuzhiyun if (addr == FDT_ADDR_T_NONE) {
528*4882a593Smuzhiyun debug("%s: Get ebc_tcon address failed\n", __func__);
529*4882a593Smuzhiyun return -ENXIO;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun priv->reg = ioremap(addr, size);
533*4882a593Smuzhiyun priv->reg_len = size;
534*4882a593Smuzhiyun priv->regcache = malloc(size);
535*4882a593Smuzhiyun memset(priv->regcache, 0, size);
536*4882a593Smuzhiyun return 0;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun static const struct udevice_id ebc_tcon_ids[] = {
540*4882a593Smuzhiyun { .compatible = "rockchip,rk3568-ebc-tcon" },
541*4882a593Smuzhiyun { }
542*4882a593Smuzhiyun };
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun U_BOOT_DRIVER(rk_ebc_tcon) = {
545*4882a593Smuzhiyun .name = "rk_ebc_tcon",
546*4882a593Smuzhiyun .id = UCLASS_EBC,
547*4882a593Smuzhiyun .of_match = ebc_tcon_ids,
548*4882a593Smuzhiyun .ofdata_to_platdata = rk_ebc_tcon_ofdata_to_platdata,
549*4882a593Smuzhiyun .probe = rk_ebc_tcon_probe,
550*4882a593Smuzhiyun .ops = &ebc_tcon_funcs,
551*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct ebc_tcon_priv),
552*4882a593Smuzhiyun };
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun UCLASS_DRIVER(ebc_tcon) = {
555*4882a593Smuzhiyun .id = UCLASS_EBC,
556*4882a593Smuzhiyun .name = "ebc_tcon",
557*4882a593Smuzhiyun };
558*4882a593Smuzhiyun
559