xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/ebc-dev/tcon/eink_tcon.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
4  *
5  * Author: Zorro Liu <zorro.liu@rock-chips.com>
6  */
7 
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/err.h>
12 #include <linux/io.h>
13 #include <linux/of.h>
14 #include <linux/slab.h>
15 #include <linux/device.h>
16 #include <linux/delay.h>
17 #include <linux/init.h>
18 #include <linux/interrupt.h>
19 #include <linux/platform_device.h>
20 #include <linux/clk.h>
21 #include <linux/irq.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/mfd/syscon.h>
24 #include <linux/regmap.h>
25 #include "ebc_tcon.h"
26 
27 #define HIWORD_UPDATE(x, l, h)	(((x) << (l)) | (GENMASK(h, l) << 16))
28 #define UPDATE(x, h, l)		(((x) << (l)) & GENMASK((h), (l)))
29 
30 /* eink register define */
31 #define EINK_IP_ENABLE					0x00
32 #define EINK_SFT_UPDATE					0x04
33 #define EINK_SIT_UPDATE					0x08
34 #define EINK_PRE_IMAGE_BUF_ADDR			0x0c
35 #define EINK_CUR_IMAGE_BUF_ADDR			0x10
36 #define EINK_IMAGE_PROCESS_BUF_ADDR	0x14
37 #define EINK_LINE_DATA_ADDR_OFFSET		0x18
38 #define EINK_IMAGE_WIDTH					0x1c
39 #define EINK_IMAGE_HEIGHT				0x20
40 #define EINK_DATA_FORMAT				0x24
41 #define EINK_IP_STATUS					0x28
42 #define EINK_IP_VERSION					0x2c
43 #define EINK_IP_CLR_INT					0x30
44 #define EINK_INT_SETTING0					0x34
45 #define EINK_INT_SETTING1					0x38
46 #define EINK_INT_SETTING2					0x3c
47 #define EINK_INT_SETTING3					0x40
48 #define EINK_INT_SETTING4					0x44
49 #define EINK_INT_SETTING5					0x48
50 #define EINK_INT_SETTING6					0x4c
51 #define EINK_INT_SETTING7					0x50
52 #define EINK_WF_SETTING0					0x54
53 #define EINK_WF_SETTING1					0x58
54 #define EINK_WF_SETTING2					0x5c
55 #define EINK_WF_SETTING3					0x60
56 #define EINK_WF_SETTING4					0x64
57 #define EINK_WF_SETTING5					0x68
58 #define EINK_WF_SETTING6					0x6c
59 #define EINK_WF_SETTING7					0x70
60 
61 struct eink_reg_data {
62 	int addr;
63 	int value;
64 };
65 
66 static const struct eink_reg_data PANEL_1200x825_INIT[] = {
67 	{ EINK_SFT_UPDATE, 0x00030001 },
68 	{ EINK_SIT_UPDATE, 0x00050000 },
69 	{ EINK_LINE_DATA_ADDR_OFFSET, 0x000004b0 }, //width
70 	{ EINK_IMAGE_WIDTH, 0x000004af }, //width - 1
71 	{ EINK_IMAGE_HEIGHT, 0x00000338 }, //height - 1
72 
73 	{ EINK_INT_SETTING0, 0x0e56676f },
74 	{ EINK_INT_SETTING1, 0x40674408 },
75 	{ EINK_INT_SETTING2, 0xd7eb7743 },
76 	{ EINK_INT_SETTING3, 0x19414d35 },
77 	{ EINK_INT_SETTING4, 0x12561c00 },
78 	{ EINK_INT_SETTING5, 0x05552e0a },
79 	{ EINK_INT_SETTING6, 0x4a400e10 },
80 	{ EINK_INT_SETTING7, 0x15496e2b },
81 
82 	{ EINK_WF_SETTING0, 0xb3f33a52 },
83 	{ EINK_WF_SETTING1, 0x2042b122 },
84 	{ EINK_WF_SETTING2, 0xbdb0f3be },
85 	{ EINK_WF_SETTING3, 0xe289a0ca },
86 	{ EINK_WF_SETTING4, 0xb0d3b2c8 },
87 	{ EINK_WF_SETTING5, 0x3a32ab20 },
88 	{ EINK_WF_SETTING6, 0xa69a634c },
89 	{ EINK_WF_SETTING7, 0xd87af2c0 },
90 };
91 
92 static const struct eink_reg_data PANEL_1872x1404_INIT[] = {
93 	{ EINK_SFT_UPDATE, 0x00030001 },
94 	{ EINK_SIT_UPDATE, 0x00050000 },
95 	{ EINK_LINE_DATA_ADDR_OFFSET, 0x00000750 }, //width
96 	{ EINK_IMAGE_WIDTH, 0x0000074f }, //width - 1
97 	{ EINK_IMAGE_HEIGHT, 0x0000057c }, //height -1
98 
99 	{ EINK_INT_SETTING0, 0x0e56676f },
100 	{ EINK_INT_SETTING1, 0x40674408 },
101 	{ EINK_INT_SETTING2, 0xb14a4643 },
102 	{ EINK_INT_SETTING3, 0x19414d35 },
103 	{ EINK_INT_SETTING4, 0x12561c00 },
104 	{ EINK_INT_SETTING5, 0x05552e0a },
105 	{ EINK_INT_SETTING6, 0x4a400e10 },
106 	{ EINK_INT_SETTING7, 0x15496e2b },
107 
108 	{ EINK_WF_SETTING0, 0xb3f33a52 },
109 	{ EINK_WF_SETTING1, 0x2042b122 },
110 	{ EINK_WF_SETTING2, 0x34b0708b },
111 	{ EINK_WF_SETTING3, 0xe289a0ca },
112 	{ EINK_WF_SETTING4, 0xb0d3b2c8 },
113 	{ EINK_WF_SETTING5, 0x3a32ab20 },
114 	{ EINK_WF_SETTING6, 0x2f9ae079 },
115 	{ EINK_WF_SETTING7, 0xd87af2c0 },
116 };
117 
tcon_write(struct eink_tcon * tcon,unsigned int reg,unsigned int value)118 static inline void tcon_write(struct eink_tcon *tcon, unsigned int reg,
119 			      unsigned int value)
120 {
121 	regmap_write(tcon->regmap_base, reg, value);
122 }
123 
tcon_read(struct eink_tcon * tcon,unsigned int reg)124 static inline unsigned int tcon_read(struct eink_tcon *tcon, unsigned int reg)
125 {
126 	unsigned int value;
127 
128 	regmap_read(tcon->regmap_base, reg, &value);
129 
130 	return value;
131 }
132 
tcon_update_bits(struct eink_tcon * tcon,unsigned int reg,unsigned int mask,unsigned int val)133 static inline void tcon_update_bits(struct eink_tcon *tcon, unsigned int reg,
134 				    unsigned int mask, unsigned int val)
135 {
136 	regmap_update_bits(tcon->regmap_base, reg, mask, val);
137 }
138 
tcon_enable(struct eink_tcon * tcon,struct ebc_panel * panel)139 static int tcon_enable(struct eink_tcon *tcon, struct ebc_panel *panel)
140 {
141 	int reg_num = 0;
142 	int i;
143 	const struct eink_reg_data *pre_init_reg;
144 
145 	clk_prepare_enable(tcon->pclk);
146 	clk_prepare_enable(tcon->hclk);
147 	pm_runtime_get_sync(tcon->dev);
148 
149 	if ((panel->width == 1872) && (panel->height == 1404)) {
150 		pre_init_reg = PANEL_1872x1404_INIT;
151 		reg_num = ARRAY_SIZE(PANEL_1872x1404_INIT);
152 	} else if ((panel->width == 1200) && (panel->height == 825)) {
153 		pre_init_reg = PANEL_1200x825_INIT;
154 		reg_num = ARRAY_SIZE(PANEL_1200x825_INIT);
155 	} else {
156 		pre_init_reg = PANEL_1872x1404_INIT;
157 		reg_num = ARRAY_SIZE(PANEL_1872x1404_INIT);
158 	}
159 	for (i = 0; i < reg_num; i++) {
160 		tcon_write(tcon, pre_init_reg[i].addr, pre_init_reg[i].value);
161 	}
162 
163 	enable_irq(tcon->irq);
164 
165 	return 0;
166 }
167 
tcon_disable(struct eink_tcon * tcon)168 static void tcon_disable(struct eink_tcon *tcon)
169 {
170 	disable_irq(tcon->irq);
171 
172 	pm_runtime_put_sync(tcon->dev);
173 	clk_disable_unprepare(tcon->hclk);
174 	clk_disable_unprepare(tcon->pclk);
175 }
176 
tcon_image_addr_set(struct eink_tcon * tcon,u32 pre_image_buf_addr,u32 cur_image_buf_addr,u32 image_process_buf_addr)177 static void tcon_image_addr_set(struct eink_tcon *tcon, u32 pre_image_buf_addr,
178 				u32 cur_image_buf_addr, u32 image_process_buf_addr)
179 {
180 	tcon_write(tcon, EINK_PRE_IMAGE_BUF_ADDR, pre_image_buf_addr);
181 	tcon_write(tcon, EINK_CUR_IMAGE_BUF_ADDR, cur_image_buf_addr);
182 	tcon_write(tcon, EINK_IMAGE_PROCESS_BUF_ADDR, image_process_buf_addr);
183 }
184 
tcon_frame_start(struct eink_tcon * tcon)185 static void tcon_frame_start(struct eink_tcon *tcon)
186 {
187 	tcon_write(tcon, EINK_IP_ENABLE, 1);
188 }
189 
tcon_irq_hanlder(int irq,void * dev_id)190 static irqreturn_t tcon_irq_hanlder(int irq, void *dev_id)
191 {
192 	struct eink_tcon *tcon = (struct eink_tcon *)dev_id;
193 	u32 intr_status;
194 
195 	intr_status = tcon_read(tcon, EINK_IP_STATUS);
196 
197 	if (intr_status & 0x1) {
198 		tcon_update_bits(tcon, EINK_IP_CLR_INT, 0x1, 0x1);
199 
200 		if (tcon->dsp_end_callback)
201 			tcon->dsp_end_callback();
202 	}
203 
204 	return IRQ_HANDLED;
205 }
206 
207 static struct regmap_config eink_regmap_config = {
208 	.reg_bits = 32,
209 	.val_bits = 32,
210 	.reg_stride = 4,
211 };
212 
eink_tcon_probe(struct platform_device * pdev)213 static int eink_tcon_probe(struct platform_device *pdev)
214 {
215 	struct device *dev = &pdev->dev;
216 	struct eink_tcon *tcon;
217 	struct resource *res;
218 	int ret;
219 
220 	tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
221 	if (!tcon)
222 		return -ENOMEM;
223 
224 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
225 	tcon->regs = devm_ioremap_resource(dev, res);
226 	if (IS_ERR(tcon->regs))
227 		return PTR_ERR(tcon->regs);
228 
229 	tcon->len = resource_size(res);
230 	eink_regmap_config.max_register = resource_size(res) - 4;
231 	eink_regmap_config.name = "rockchip,eink_tcon";
232 	tcon->regmap_base = devm_regmap_init_mmio(dev, tcon->regs, &eink_regmap_config);
233 	if (IS_ERR(tcon->regmap_base))
234 		return PTR_ERR(tcon->regmap_base);
235 
236 	tcon->hclk = devm_clk_get(dev, "hclk");
237 	if (IS_ERR(tcon->hclk)) {
238 		ret = PTR_ERR(tcon->hclk);
239 		dev_err(dev, "failed to get hclk clock: %d\n", ret);
240 		return ret;
241 	}
242 
243 	tcon->pclk = devm_clk_get(dev, "pclk");
244 	if (IS_ERR(tcon->pclk)) {
245 		ret = PTR_ERR(tcon->pclk);
246 		dev_err(dev, "failed to get dclk clock: %d\n", ret);
247 		return ret;
248 	}
249 
250 	tcon->irq = platform_get_irq(pdev, 0);
251 	if (tcon->irq < 0) {
252 		dev_err(dev, "No IRQ resource!\n");
253 		return tcon->irq;
254 	}
255 
256 	irq_set_status_flags(tcon->irq, IRQ_NOAUTOEN);
257 	ret = devm_request_irq(dev, tcon->irq, tcon_irq_hanlder,
258 			       0, dev_name(dev), tcon);
259 	if (ret < 0) {
260 		dev_err(dev, "failed to requeset irq: %d\n", ret);
261 		return ret;
262 	}
263 
264 	tcon->dev = dev;
265 	tcon->enable = tcon_enable;
266 	tcon->disable = tcon_disable;
267 	tcon->image_addr_set = tcon_image_addr_set;
268 	tcon->frame_start = tcon_frame_start;
269 	platform_set_drvdata(pdev, tcon);
270 
271 	pm_runtime_enable(dev);
272 
273 	return 0;
274 }
275 
eink_tcon_remove(struct platform_device * pdev)276 static int eink_tcon_remove(struct platform_device *pdev)
277 {
278 	pm_runtime_disable(&pdev->dev);
279 
280 	return 0;
281 }
282 
283 static const struct of_device_id eink_tcon_of_match[] = {
284 	{ .compatible = "rockchip,rk3568-eink-tcon" },
285 	{}
286 };
287 MODULE_DEVICE_TABLE(of, eink_tcon_of_match);
288 
289 static struct platform_driver eink_tcon_driver = {
290 	.driver = {
291 		.name = "rk-eink-tcon",
292 		.of_match_table = eink_tcon_of_match,
293 	},
294 	.probe = eink_tcon_probe,
295 	.remove = eink_tcon_remove,
296 };
297 module_platform_driver(eink_tcon_driver);
298 
299 MODULE_AUTHOR("Zorro Liu <zorro.liu@rock-chips.com>");
300 MODULE_DESCRIPTION("ROCKCHIP EINK tcon driver");
301 MODULE_LICENSE("GPL v2");
302