1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * FB driver for the WiseChip Semiconductor Inc. (UG-6028GDEBF02) display
4  * using the SEPS525 (Syncoam) LCD Controller
5  *
6  * Copyright (C) 2020 Xilinx Inc.
7  */
8 
9 #include <common.h>
10 #include <command.h>
11 #include <cpu_func.h>
12 #include <dm.h>
13 #include <errno.h>
14 #include <spi.h>
15 #include <video.h>
16 #include <asm/gpio.h>
17 #include <dm/device_compat.h>
18 #include <linux/delay.h>
19 
20 #define WIDTH		160
21 #define HEIGHT		128
22 
23 #define SEPS525_INDEX			0x00
24 #define SEPS525_STATUS_RD		0x01
25 #define SEPS525_OSC_CTL			0x02
26 #define SEPS525_IREF			0x80
27 #define SEPS525_CLOCK_DIV		0x03
28 #define SEPS525_REDUCE_CURRENT		0x04
29 #define SEPS525_SOFT_RST		0x05
30 #define SEPS525_DISP_ONOFF		0x06
31 #define SEPS525_PRECHARGE_TIME_R	0x08
32 #define SEPS525_PRECHARGE_TIME_G	0x09
33 #define SEPS525_PRECHARGE_TIME_B	0x0A
34 #define SEPS525_PRECHARGE_CURRENT_R	0x0B
35 #define SEPS525_PRECHARGE_CURRENT_G	0x0C
36 #define SEPS525_PRECHARGE_CURRENT_B	0x0D
37 #define SEPS525_DRIVING_CURRENT_R	0x10
38 #define SEPS525_DRIVING_CURRENT_G	0x11
39 #define SEPS525_DRIVING_CURRENT_B	0x12
40 #define SEPS525_DISPLAYMODE_SET		0x13
41 #define SEPS525_RGBIF			0x14
42 #define SEPS525_RGB_POL			0x15
43 #define SEPS525_MEMORY_WRITEMODE	0x16
44 #define SEPS525_MX1_ADDR		0x17
45 #define SEPS525_MX2_ADDR		0x18
46 #define SEPS525_MY1_ADDR		0x19
47 #define SEPS525_MY2_ADDR		0x1A
48 #define SEPS525_MEMORY_ACCESS_POINTER_X	0x20
49 #define SEPS525_MEMORY_ACCESS_POINTER_Y	0x21
50 #define SEPS525_DDRAM_DATA_ACCESS_PORT	0x22
51 #define SEPS525_GRAY_SCALE_TABLE_INDEX	0x50
52 #define SEPS525_GRAY_SCALE_TABLE_DATA	0x51
53 #define SEPS525_DUTY			0x28
54 #define SEPS525_DSL			0x29
55 #define SEPS525_D1_DDRAM_FAC		0x2E
56 #define SEPS525_D1_DDRAM_FAR		0x2F
57 #define SEPS525_D2_DDRAM_SAC		0x31
58 #define SEPS525_D2_DDRAM_SAR		0x32
59 #define SEPS525_SCR1_FX1		0x33
60 #define SEPS525_SCR1_FX2		0x34
61 #define SEPS525_SCR1_FY1		0x35
62 #define SEPS525_SCR1_FY2		0x36
63 #define SEPS525_SCR2_SX1		0x37
64 #define SEPS525_SCR2_SX2		0x38
65 #define SEPS525_SCR2_SY1		0x39
66 #define SEPS525_SCR2_SY2		0x3A
67 #define SEPS525_SCREEN_SAVER_CONTEROL	0x3B
68 #define SEPS525_SS_SLEEP_TIMER		0x3C
69 #define SEPS525_SCREEN_SAVER_MODE	0x3D
70 #define SEPS525_SS_SCR1_FU		0x3E
71 #define SEPS525_SS_SCR1_MXY		0x3F
72 #define SEPS525_SS_SCR2_FU		0x40
73 #define SEPS525_SS_SCR2_MXY		0x41
74 #define SEPS525_MOVING_DIRECTION	0x42
75 #define SEPS525_SS_SCR2_SX1		0x47
76 #define SEPS525_SS_SCR2_SX2		0x48
77 #define SEPS525_SS_SCR2_SY1		0x49
78 #define SEPS525_SS_SCR2_SY2		0x4A
79 
80 /* SEPS525_DISPLAYMODE_SET */
81 #define MODE_SWAP_BGR	BIT(7)
82 #define MODE_SM		BIT(6)
83 #define MODE_RD		BIT(5)
84 #define MODE_CD		BIT(4)
85 
86 /**
87  * struct seps525_priv - Private structure
88  * @reset_gpio: Reset gpio pin
89  * @dc_gpio: Data/command control gpio pin
90  * @dev: Device uclass for video_ops
91  */
92 struct seps525_priv {
93 	struct gpio_desc reset_gpio;
94 	struct gpio_desc dc_gpio;
95 	struct udevice *dev;
96 };
97 
seps525_spi_write_cmd(struct udevice * dev,u32 reg)98 static int seps525_spi_write_cmd(struct udevice *dev, u32 reg)
99 {
100 	struct seps525_priv *priv = dev_get_priv(dev);
101 	u8 buf8 = reg;
102 	int ret;
103 
104 	ret = dm_gpio_set_value(&priv->dc_gpio, 0);
105 	if (ret) {
106 		dev_dbg(dev, "Failed to handle dc\n");
107 		return ret;
108 	}
109 
110 	ret = dm_spi_xfer(dev, 8, &buf8, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
111 	if (ret)
112 		dev_dbg(dev, "Failed to write command\n");
113 
114 	return ret;
115 }
116 
seps525_spi_write_data(struct udevice * dev,u32 val)117 static int seps525_spi_write_data(struct udevice *dev, u32 val)
118 {
119 	struct seps525_priv *priv = dev_get_priv(dev);
120 	u8 buf8 = val;
121 	int ret;
122 
123 	ret = dm_gpio_set_value(&priv->dc_gpio, 1);
124 	if (ret) {
125 		dev_dbg(dev, "Failed to handle dc\n");
126 		return ret;
127 	}
128 
129 	ret = dm_spi_xfer(dev, 8, &buf8, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
130 	if (ret)
131 		dev_dbg(dev, "Failed to write data\n");
132 
133 	return ret;
134 }
135 
seps525_spi_write(struct udevice * dev,u32 reg,u32 val)136 static void seps525_spi_write(struct udevice *dev, u32 reg, u32 val)
137 {
138 	(void)seps525_spi_write_cmd(dev, reg);
139 	(void)seps525_spi_write_data(dev, val);
140 }
141 
seps525_display_init(struct udevice * dev)142 static int seps525_display_init(struct udevice *dev)
143 {
144 	/* Disable Oscillator Power Down */
145 	seps525_spi_write(dev, SEPS525_REDUCE_CURRENT, 0x03);
146 	mdelay(5);
147 
148 	/* Set Normal Driving Current */
149 	seps525_spi_write(dev, SEPS525_REDUCE_CURRENT, 0x00);
150 	mdelay(5);
151 
152 	seps525_spi_write(dev, SEPS525_SCREEN_SAVER_CONTEROL, 0x00);
153 	/* Set EXPORT1 Pin at Internal Clock */
154 	seps525_spi_write(dev, SEPS525_OSC_CTL, 0x01);
155 	/* Set Clock as 120 Frames/Sec */
156 	seps525_spi_write(dev, SEPS525_CLOCK_DIV, 0x90);
157 	/* Set Reference Voltage Controlled by External Resister */
158 	seps525_spi_write(dev, SEPS525_IREF, 0x01);
159 
160 	/* precharge time R G B */
161 	seps525_spi_write(dev, SEPS525_PRECHARGE_TIME_R, 0x04);
162 	seps525_spi_write(dev, SEPS525_PRECHARGE_TIME_G, 0x05);
163 	seps525_spi_write(dev, SEPS525_PRECHARGE_TIME_B, 0x05);
164 
165 	/* precharge current R G B (uA) */
166 	seps525_spi_write(dev, SEPS525_PRECHARGE_CURRENT_R, 0x9D);
167 	seps525_spi_write(dev, SEPS525_PRECHARGE_CURRENT_G, 0x8C);
168 	seps525_spi_write(dev, SEPS525_PRECHARGE_CURRENT_B, 0x57);
169 
170 	/* driving current R G B (uA) */
171 	seps525_spi_write(dev, SEPS525_DRIVING_CURRENT_R, 0x56);
172 	seps525_spi_write(dev, SEPS525_DRIVING_CURRENT_G, 0x4D);
173 	seps525_spi_write(dev, SEPS525_DRIVING_CURRENT_B, 0x46);
174 	/* Set Color Sequence */
175 	seps525_spi_write(dev, SEPS525_DISPLAYMODE_SET, 0x00);
176 	/* Set MCU Interface Mode */
177 	seps525_spi_write(dev, SEPS525_RGBIF, 0x01);
178 	/* Set Memory Write Mode */
179 	seps525_spi_write(dev, SEPS525_MEMORY_WRITEMODE, 0x66);
180 	/* 1/128 Duty (0x0F~0x7F) */
181 	seps525_spi_write(dev, SEPS525_DUTY, 0x7F);
182 	/* Set Mapping RAM Display Start Line (0x00~0x7F) */
183 	seps525_spi_write(dev, SEPS525_DSL, 0x00);
184 	/* Display On (0x00/0x01) */
185 	seps525_spi_write(dev, SEPS525_DISP_ONOFF, 0x01);
186 	/* Set All Internal Register Value as Normal Mode */
187 	seps525_spi_write(dev, SEPS525_SOFT_RST, 0x00);
188 	/* Set RGB Interface Polarity as Active Low */
189 	seps525_spi_write(dev, SEPS525_RGB_POL, 0x00);
190 
191 	/* Enable access for data */
192 	(void)seps525_spi_write_cmd(dev, SEPS525_DDRAM_DATA_ACCESS_PORT);
193 
194 	return 0;
195 }
196 
seps525_spi_startup(struct udevice * dev)197 static int seps525_spi_startup(struct udevice *dev)
198 {
199 	struct seps525_priv *priv = dev_get_priv(dev);
200 	int ret;
201 
202 	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
203 	if (ret)
204 		return ret;
205 
206 	ret = dm_gpio_set_value(&priv->reset_gpio, 0);
207 	if (ret)
208 		return ret;
209 
210 	ret = dm_spi_claim_bus(dev);
211 	if (ret) {
212 		dev_err(dev, "Failed to claim SPI bus: %d\n", ret);
213 		return ret;
214 	}
215 
216 	ret = seps525_display_init(dev);
217 	if (ret)
218 		return ret;
219 
220 	dm_spi_release_bus(dev);
221 
222 	return 0;
223 }
224 
seps525_sync(struct udevice * vid)225 static int seps525_sync(struct udevice *vid)
226 {
227 	struct video_priv *uc_priv = dev_get_uclass_priv(vid);
228 	struct seps525_priv *priv = dev_get_priv(vid);
229 	struct udevice *dev = priv->dev;
230 	int i, ret;
231 	u8 data1, data2;
232 	u8 *start = uc_priv->fb;
233 
234 	ret = dm_spi_claim_bus(dev);
235 	if (ret) {
236 		dev_err(dev, "Failed to claim SPI bus: %d\n", ret);
237 		return ret;
238 	}
239 
240 	/* start position X,Y */
241 	seps525_spi_write(dev, SEPS525_MEMORY_ACCESS_POINTER_X, 0);
242 	seps525_spi_write(dev, SEPS525_MEMORY_ACCESS_POINTER_Y, 0);
243 
244 	/* Enable access for data */
245 	(void)seps525_spi_write_cmd(dev, SEPS525_DDRAM_DATA_ACCESS_PORT);
246 
247 	for (i = 0; i < (uc_priv->xsize * uc_priv->ysize); i++) {
248 		data2 = *start++;
249 		data1 = *start++;
250 		(void)seps525_spi_write_data(dev, data1);
251 		(void)seps525_spi_write_data(dev, data2);
252 	}
253 
254 	dm_spi_release_bus(dev);
255 
256 	return 0;
257 }
258 
seps525_probe(struct udevice * dev)259 static int seps525_probe(struct udevice *dev)
260 {
261 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
262 	struct seps525_priv *priv = dev_get_priv(dev);
263 	u32 buswidth;
264 	int ret;
265 
266 	buswidth = dev_read_u32_default(dev, "buswidth", 0);
267 	if (buswidth != 8) {
268 		dev_err(dev, "Only 8bit buswidth is supported now");
269 		return -EINVAL;
270 	}
271 
272 	ret = gpio_request_by_name(dev, "reset-gpios", 0,
273 				   &priv->reset_gpio, GPIOD_IS_OUT);
274 	if (ret) {
275 		dev_err(dev, "missing reset GPIO\n");
276 		return ret;
277 	}
278 
279 	ret = gpio_request_by_name(dev, "dc-gpios", 0,
280 				   &priv->dc_gpio, GPIOD_IS_OUT);
281 	if (ret) {
282 		dev_err(dev, "missing dc GPIO\n");
283 		return ret;
284 	}
285 
286 	uc_priv->bpix = VIDEO_BPP16;
287 	uc_priv->xsize = WIDTH;
288 	uc_priv->ysize = HEIGHT;
289 	uc_priv->rot = 0;
290 
291 	priv->dev = dev;
292 
293 	ret = seps525_spi_startup(dev);
294 	if (ret)
295 		return ret;
296 
297 	return 0;
298 }
299 
seps525_bind(struct udevice * dev)300 static int seps525_bind(struct udevice *dev)
301 {
302 	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
303 
304 	plat->size = WIDTH * HEIGHT * 16;
305 
306 	return 0;
307 }
308 
309 static const struct video_ops seps525_ops = {
310 	.video_sync = seps525_sync,
311 };
312 
313 static const struct udevice_id seps525_ids[] = {
314 	{ .compatible = "syncoam,seps525" },
315 	{ }
316 };
317 
318 U_BOOT_DRIVER(seps525_video) = {
319 	.name = "seps525_video",
320 	.id = UCLASS_VIDEO,
321 	.of_match = seps525_ids,
322 	.ops = &seps525_ops,
323 	.plat_auto = sizeof(struct video_uc_plat),
324 	.bind = seps525_bind,
325 	.probe = seps525_probe,
326 	.priv_auto = sizeof(struct seps525_priv),
327 };
328