x86: Make coreboot sysinfo available to any x86 board
[platform/kernel/u-boot.git] / drivers / video / seps525.c
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
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
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
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
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
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
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
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
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 };