blob: e05b2465ede2aa9e1a563f279a162bc6fe9ac768 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * st7335 LCD panel driver.
3 *
4 * Copyright (C) 2015 Marvell
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include <common.h>
10#include <malloc.h>
11#include <spi.h>
12#include <asm/gpio.h>
13
14#define ST7735_NOP (0x0)
15#define ST7735_SWRESET (0x01)
16#define ST7735_SLPIN (0x10)
17#define ST7735_SLPOUT (0x11)
18#define ST7735_PTLON (0x12)
19#define ST7735_NORON (0x13)
20#define ST7735_INVOFF (0x20)
21#define ST7735_INVON (0x21)
22#define ST7735_DISPON (0x29)
23#define ST7735_CASET (0x2A)
24#define ST7735_RASET (0x2B)
25#define ST7735_RAMWR (0x2C)
26#define ST7735_COLMOD (0x3A)
27#define ST7735_MADCTL (0x36)
28#define ST7735_FRMCTR1 (0xB1)
29#define ST7735_FRMCTR2 (0xB2)
30#define ST7735_FRMCTR3 (0xB3)
31#define ST7735_INVCTR (0xB4)
32#define ST7735_DISSET5 (0xB6)
33#define ST7735_PWCTR1 (0xC0)
34#define ST7735_PWCTR2 (0xC1)
35#define ST7735_PWCTR3 (0xC2)
36#define ST7735_PWCTR4 (0xC3)
37#define ST7735_PWCTR5 (0xC4)
38#define ST7735_VMCTR1 (0xC5)
39#define ST7735_PWCTR6 (0xFC)
40#define ST7735_GMCTRP1 (0xE0)
41#define ST7735_GMCTRN1 (0xE1)
42
43#define LCD_177_SIZE
44
45uint16_t cmd01[3] = {0x102,0x135,0x136};
46uint16_t cmd02[3] = {0x102,0x135,0x136};
47uint16_t cmd03[6] = {0x102,0x135,0x136,0x102,0x135,0x136};
48uint16_t cmd04[1] = {0x100};
49uint16_t cmd05[3] = {0x1a2,0x102,0x184};
50uint16_t cmd06[1] = {0x1c5};
51uint16_t cmd07[2] = {0x10d,0x100};
52uint16_t cmd08[2] = {0x18a,0x12a};
53uint16_t cmd09[2] = {0x18d,0x1ee};
54uint16_t cmd10[1] = {0x112};
55
56#if REVERSE_LEFT_90_DEGREE
57uint16_t cmd11[1] = {0x108};
58#elif REVERSE_RIGHT_90_DEGREE
59uint16_t cmd11[1] = {0x1c8};
60#else
61uint16_t cmd11[1] = {0x168};
62#endif
63uint16_t cmd12[16] = {0x112,0x11c,0x110,0x118,0x133,0x12c,0x125,0x128,
64 0x128,0x127,0x12f,0x13c,0x100,0x103,0x103,0x110};
65uint16_t cmd13[16] = {0x112,0x11c,0x110,0x118,0x12d,0x128,0x123,0x128,
66 0x128,0x126,0x12f,0x13b,0x100,0x103,0x103,0x110};
67uint16_t cmd14[1] = {0x105};
68uint16_t cmd15[4] = {0x100,0x102,0x100,0x181};
69uint16_t cmd16[4] = {0x100,0x103,0x100,0x1a2};
70
71#define data_size(x) sizeof(x)/sizeof(uint16_t)
72
73#define LCD_PWR_GPIO 13
74#define LCD_RST_GPIO35 35
75#define SPI_9BIT_MODE 9
76
77#ifdef LCD_177_SIZE
78#define DEFAULT_FB_XRES 160
79#else
80#define DEFAULT_FB_XRES 128
81#endif
82
83#define DEFAULT_FB_YRES 128
84#define DEFAULT_FB_SIZE (DEFAULT_FB_XRES * DEFAULT_FB_YRES * 4)
85
86#define DATA_HR 0x100
87#define DataH(x) DATA_HR | (x)
88
89static uint16_t *lcd_buff;
90struct spi_slave *spi;
91void lcdFillRGB(uint16_t color);
92static void st7735fb_draw_logo(void);
93
94const u8 marvell_logo[1][64][4] =
95{
96 { // marvell
97 {0x01, 0x00, 0x00, 0x00}, {0x03, 0x00, 0x00, 0x00}, {0x07, 0x00, 0x00, 0x00}, {0x0f, 0x00, 0x00, 0x00},
98 {0x1f, 0x00, 0x00, 0x00}, {0x3f, 0x00, 0x00, 0x00}, {0x7f, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x00},
99 {0xff, 0x01, 0x00, 0x00}, {0xff, 0x03, 0x00, 0x00}, {0xff, 0x07, 0x00, 0x00}, {0xff, 0x0f, 0x00, 0x00}, // 11
100 {0xff, 0x1f, 0x00, 0x00}, {0xff, 0x3f, 0x00, 0x00}, {0xfe, 0x7f, 0x00, 0x00}, {0xfc, 0xff, 0x00, 0x00},
101 {0xf8, 0xff, 0x01, 0x00}, {0xf0, 0xff, 0x03, 0x00}, {0xe0, 0xff, 0x07, 0x00}, {0xc0, 0xff, 0x0f, 0x00},
102 {0x80, 0xff, 0x1f, 0x00}, {0x00, 0xff, 0x3f, 0x00}, {0x00, 0xfe, 0x7f, 0x00}, {0x01, 0xfc, 0xff, 0x00},
103 {0x03, 0xf8, 0xff, 0x01}, {0x77, 0xf7, 0xff, 0x03}, {0x5d, 0x15, 0x00, 0x02}, {0x5d, 0x15, 0x00, 0x02},
104 {0x5d, 0x15, 0x00, 0x02}, {0x5d, 0x15, 0x00, 0x02}, {0xdd, 0x15, 0x00, 0x02}, {0xdd, 0x15, 0x00, 0x02},
105 {0xdd, 0x15, 0x00, 0x02}, {0xdd, 0x15, 0x00, 0x02}, {0xdd, 0x15, 0x00, 0x02}, {0xdd, 0x1d, 0x00, 0x02},
106 {0xdd, 0x1d, 0x00, 0x02}, {0xdd, 0x1d, 0x00, 0x02}, {0xff, 0xff, 0xff, 0x03}, {0xfc, 0xff, 0x00, 0x00}, // 39
107 {0xf8, 0xff, 0x01, 0x00}, {0xf0, 0xff, 0x03, 0x00}, {0xe0, 0xff, 0x07, 0x00}, {0xc0, 0xff, 0x0f, 0x00},
108 {0x80, 0xff, 0x1f, 0x00}, {0x00, 0xff, 0x3f, 0x00}, {0x00, 0xfe, 0x7f, 0x00}, {0x00, 0xfc, 0xff, 0x00},
109 {0x00, 0xf8, 0xff, 0x01}, {0x77, 0xf7, 0xff, 0x03}, {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02},
110 {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02},
111 {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02},
112 {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02}, {0x55, 0x15, 0x00, 0x02}, {0x77, 0xf7, 0xff, 0x03}
113 }
114};
115
116void write_command_data(uint16_t cmd, uint16_t *data_addr, uint32_t data_size)
117{
118 int ret;
119
120 ret = spi_xfer(spi, SPI_9BIT_MODE, &cmd, NULL,
121 SPI_XFER_BEGIN | SPI_XFER_END);
122 if (ret)
123 debug("SPILCD: Failed to send command %d\n", cmd);
124
125 if (data_addr && data_size > 0) {
126 ret = spi_xfer(spi, SPI_9BIT_MODE * data_size, data_addr, NULL,
127 SPI_XFER_BEGIN | SPI_XFER_END);
128 if (ret)
129 debug("SPILCD: Failed to send data.\n");
130 }
131}
132
133void st7735InitDisplay(void)
134{
135 write_command_data(ST7735_SLPOUT, NULL, 0);
136 mdelay(300);
137
138 write_command_data(ST7735_FRMCTR1, cmd01, data_size(cmd01));
139 write_command_data(ST7735_FRMCTR2, cmd02, data_size(cmd02));
140 write_command_data(ST7735_FRMCTR3, cmd03, data_size(cmd03));
141 write_command_data(ST7735_INVCTR, cmd04, data_size(cmd04));
142 write_command_data(ST7735_PWCTR1, cmd05, data_size(cmd05));
143 write_command_data(ST7735_PWCTR2, cmd06, data_size(cmd06));
144 write_command_data(ST7735_PWCTR3, cmd07, data_size(cmd07));
145 write_command_data(ST7735_PWCTR4, cmd08, data_size(cmd08));
146 write_command_data(ST7735_PWCTR5, cmd09, data_size(cmd09));
147 write_command_data(ST7735_PWCTR6, cmd10, data_size(cmd10));
148 write_command_data(ST7735_MADCTL, cmd11, data_size(cmd11));
149 write_command_data(ST7735_GMCTRP1, cmd12, data_size(cmd12));
150 write_command_data(ST7735_GMCTRN1, cmd13, data_size(cmd13));
151 write_command_data(ST7735_COLMOD, cmd14, data_size(cmd14));
152 write_command_data(ST7735_CASET, cmd15, data_size(cmd15));
153 write_command_data(ST7735_RASET, cmd16, data_size(cmd16));
154
155 write_command_data(ST7735_DISPON, NULL, 0);
156 write_command_data(ST7735_RAMWR, NULL, 0);
157}
158
159void lcdBacklight(bool state)
160{
161 gpio_direction_output(LCD_PWR_GPIO, state);
162}
163
164int ST7735_lcdInit(void)
165{
166 int ret;
167 int bus = 0;
168
169 lcd_buff = malloc(DEFAULT_FB_SIZE);
170
171 spi_init();
172 spi = spi_setup_slave(bus, 25, 0, SPI_MODE_3);
173 if (!spi) {
174 printf("SF: Failed to set up slave\n");
175 return -1;
176 }
177
178 ret = spi_claim_bus(spi);
179 if (ret) {
180 debug("SF: Failed to claim SPI bus: %d\n", ret);
181 return -1;
182 }
183 spi_set_wordlen(spi, 9);
184
185 gpio_direction_output(LCD_RST_GPIO35, 1);
186 mdelay(50);
187 gpio_direction_output(LCD_RST_GPIO35, 0);
188 mdelay(50);
189 gpio_direction_output(LCD_RST_GPIO35, 1);
190 mdelay(150);
191
192 // Run LCD init sequence
193 st7735InitDisplay();
194
195 //lcdFillRGB(0x0);
196 st7735fb_draw_logo();
197 lcdBacklight(1);
198 return 0;
199}
200
201void st7735SetAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
202{
203 uint16_t buf[4];
204 buf[0] = DataH(0);
205#ifdef LCD_177_SIZE
206 buf[1] = DataH(x0);
207#else
208 buf[1] = DataH(x0+2);
209#endif
210 buf[2] = DataH(0);
211#ifdef LCD_177_SIZE
212 buf[3] = DataH(x1);
213#else
214 buf[3] = DataH(x1+2);
215#endif
216 write_command_data(ST7735_CASET, buf, 4); // column addr set
217
218 buf[0] = DataH(0);
219#ifdef LCD_177_SIZE
220 buf[1] = DataH(y0);
221#else
222 buf[1] = DataH(y0+3);
223#endif
224 buf[2] = DataH(0);
225#ifdef LCD_177_SIZE
226 buf[3] = DataH(y1);
227#else
228 buf[3] = DataH(y1+3);
229#endif
230 write_command_data(ST7735_RASET, buf, 4); // row addr set
231}
232
233void lcdFillRGB(uint16_t color)
234{
235 uint8_t x, y;
236 uint16_t *buff;
237
238 buff = lcd_buff;
239 memset(buff, 0x00, DEFAULT_FB_SIZE);
240
241 st7735SetAddrWindow(0, 0, DEFAULT_FB_XRES - 1, DEFAULT_FB_YRES - 1);
242
243 for (x=0; x < DEFAULT_FB_XRES; x++)
244 {
245 for (y=0; y < DEFAULT_FB_YRES; y++)
246 {
247 *(uint16_t *)(buff++) = DataH(color >> 8);
248 *(uint16_t *)(buff++) = DataH(color);
249 }
250 }
251
252 flush_cache((unsigned long)lcd_buff, DEFAULT_FB_SIZE);
253 write_command_data(ST7735_RAMWR, lcd_buff, DEFAULT_FB_SIZE / 2);
254}
255
256void lcdDrawPixel(uint16_t x, uint16_t y, uint16_t color)
257{
258 uint16_t buf[2];
259 st7735SetAddrWindow(x, y, x+1, y+1);
260 buf[0] = DataH(color >> 8);
261 buf[1] = DataH(color);
262 write_command_data(ST7735_RAMWR, buf, 2);
263}
264
265void lcdDrawHLine(uint16_t x0, uint16_t x1, uint16_t y, uint16_t color)
266{
267 // Allows for slightly better performance than setting individual pixels
268 uint16_t x, pixels;
269 uint16_t *buff = lcd_buff;
270
271 if (x1 < x0) // Switch x1 and x0
272 {
273 x = x1;
274 x1 = x0;
275 x0 = x;
276 }
277
278 // Check limits
279 if (x1 >= DEFAULT_FB_XRES)
280 x1 = DEFAULT_FB_XRES - 1;
281 if (x0 >= DEFAULT_FB_XRES)
282 x0 = DEFAULT_FB_XRES - 1;
283
284 st7735SetAddrWindow(x0, y, DEFAULT_FB_XRES, y + 1);
285 for (pixels = 0; pixels < x1 - x0 + 1; pixels++)
286 {
287 *(uint16_t *)buff = DataH(color >> 8);
288 buff++;
289 }
290 write_command_data(ST7735_RAMWR, lcd_buff, (x1 - x0));
291 write_command_data(ST7735_NOP, NULL, 0);
292}
293
294/*************************************************/
295void lcdDrawVLine(uint16_t x, uint16_t y0, uint16_t y1, uint16_t color)
296{
297 // Allows for slightly better performance than setting individual pixels
298 uint16_t y, pixels;
299
300 if (y1 < y0)
301 {
302 y = y1;
303 y1 = y0;
304 y0 = y;
305 }
306
307 // Check limits
308 if (y1 >= DEFAULT_FB_YRES)
309 y1 = DEFAULT_FB_YRES - 1;
310 if (y0 >= DEFAULT_FB_YRES)
311 y0 = DEFAULT_FB_YRES - 1;
312
313 st7735SetAddrWindow(x, y0, x, DEFAULT_FB_YRES);
314 for (pixels = 0; pixels < y1 - y0 + 1; pixels++)
315 {
316 *(uint16_t *)lcd_buff = DataH(color >> 8);
317 lcd_buff++;
318 }
319 write_command_data(ST7735_RAMWR, lcd_buff, (y1 - y0));
320}
321
322static void st7735fb_display_picture(u8 p_x, u8 line, u8 W, u8 H,
323 u8 *buf,u16 txt_color, u16 bg_color){
324 int i,j,k;
325 u8 c;
326 int index,size;
327 uint16_t *buff = lcd_buff;
328
329 st7735SetAddrWindow(line, p_x, (line+H-1), (p_x+W-1));
330
331 index = 0;
332 for(i=0;i<W;i++){
333 for(k=(H/8 -1);k>=0;k--){
334 c = *buf++;
335 for(j=(8-1);j>=0;j--){
336 if((1<<(7-j)) & c){
337 *(uint16_t *)(buff++) = DataH((txt_color >> 8)&0xff);
338 *(uint16_t *)(buff++) = DataH(txt_color&0xff);
339 }else{
340 *(uint16_t *)(buff++) = DataH((bg_color >> 8)&0xff);
341 *(uint16_t *)(buff++) = DataH(bg_color&0xff);
342 }
343 index++;
344 }
345 }
346 }
347 size = index;
348 write_command_data(ST7735_RAMWR, lcd_buff, size*8);
349}
350
351static void st7735fb_draw_logo(void)
352{
353 st7735fb_display_picture(0x20, 0x40, 0x40, 0x20,
354 (u8 *)marvell_logo, 0xffff, 0x0000);
355}
356
357void lcdTest(void)
358{
359 uint8_t i = 0;
360 for (i = 0; i < 100; i++)
361 {
362 lcdDrawPixel(i, i, 0xFFFF);
363 }
364}