1 /* u-boot driver for the tpo JBT6K74-AS LCM ASIC
3 * Copyright (C) 2006-2007 by OpenMoko, Inc.
4 * Author: Harald Welte <laforge@openmoko.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 #include <asm/errno.h>
31 #define DEBUGP(x, args...) printf("%s: " x, __FUNCTION__, ## args);
32 #define DEBUGPC(x, args...) printf(x, ## args);
34 #define DEBUGP(x, args...) do { } while (0)
35 #define DEBUGPC(x, args...) do { } while (0)
40 JBT_REG_SLEEP_IN
= 0x10,
41 JBT_REG_SLEEP_OUT
= 0x11,
43 JBT_REG_DISPLAY_OFF
= 0x28,
44 JBT_REG_DISPLAY_ON
= 0x29,
46 JBT_REG_RGB_FORMAT
= 0x3a,
47 JBT_REG_QUAD_RATE
= 0x3b,
49 JBT_REG_POWER_ON_OFF
= 0xb0,
50 JBT_REG_BOOSTER_OP
= 0xb1,
51 JBT_REG_BOOSTER_MODE
= 0xb2,
52 JBT_REG_BOOSTER_FREQ
= 0xb3,
53 JBT_REG_OPAMP_SYSCLK
= 0xb4,
54 JBT_REG_VSC_VOLTAGE
= 0xb5,
55 JBT_REG_VCOM_VOLTAGE
= 0xb6,
56 JBT_REG_EXT_DISPL
= 0xb7,
57 JBT_REG_OUTPUT_CONTROL
= 0xb8,
58 JBT_REG_DCCLK_DCEV
= 0xb9,
59 JBT_REG_DISPLAY_MODE1
= 0xba,
60 JBT_REG_DISPLAY_MODE2
= 0xbb,
61 JBT_REG_DISPLAY_MODE
= 0xbc,
62 JBT_REG_ASW_SLEW
= 0xbd,
63 JBT_REG_DUMMY_DISPLAY
= 0xbe,
64 JBT_REG_DRIVE_SYSTEM
= 0xbf,
66 JBT_REG_SLEEP_OUT_FR_A
= 0xc0,
67 JBT_REG_SLEEP_OUT_FR_B
= 0xc1,
68 JBT_REG_SLEEP_OUT_FR_C
= 0xc2,
69 JBT_REG_SLEEP_IN_LCCNT_D
= 0xc3,
70 JBT_REG_SLEEP_IN_LCCNT_E
= 0xc4,
71 JBT_REG_SLEEP_IN_LCCNT_F
= 0xc5,
72 JBT_REG_SLEEP_IN_LCCNT_G
= 0xc6,
74 JBT_REG_GAMMA1_FINE_1
= 0xc7,
75 JBT_REG_GAMMA1_FINE_2
= 0xc8,
76 JBT_REG_GAMMA1_INCLINATION
= 0xc9,
77 JBT_REG_GAMMA1_BLUE_OFFSET
= 0xca,
79 JBT_REG_BLANK_CONTROL
= 0xcf,
80 JBT_REG_BLANK_TH_TV
= 0xd0,
81 JBT_REG_CKV_ON_OFF
= 0xd1,
82 JBT_REG_CKV_1_2
= 0xd2,
83 JBT_REG_OEV_TIMING
= 0xd3,
84 JBT_REG_ASW_TIMING_1
= 0xd4,
85 JBT_REG_ASW_TIMING_2
= 0xd5,
87 JBT_REG_HCLOCK_VGA
= 0xec,
88 JBT_REG_HCLOCK_QVGA
= 0xed,
92 static const char *jbt_state_names
[] = {
93 [JBT_STATE_DEEP_STANDBY
] = "deep-standby",
94 [JBT_STATE_SLEEP
] = "sleep",
95 [JBT_STATE_NORMAL
] = "normal",
98 #ifndef CONFIG_GTA02_REVISION
100 #define GTA01_SCLK (1 << 7) /* GPG7 */
101 #define GTA01_MOSI (1 << 6) /* GPG6 */
102 #define GTA01_MISO (1 << 5) /* GPG5 */
103 #define GTA01_CS (1 << 3) /* GPG3 */
105 #define SPI_READ ((immr->GPGDAT & GTA01_MISO) != 0)
107 #define SPI_CS(bit) if (bit) gpio->GPGDAT |= GTA01_CS; \
108 else gpio->GPGDAT &= ~GTA01_CS
110 #define SPI_SDA(bit) if (bit) gpio->GPGDAT |= GTA01_MOSI; \
111 else gpio->GPGDAT &= ~GTA01_MOSI
113 #define SPI_SCL(bit) if (bit) gpio->GPGDAT |= GTA01_SCLK; \
114 else gpio->GPGDAT &= ~GTA01_SCLK
118 extern void smedia3362_spi_cs(int);
119 extern void smedia3362_spi_sda(int);
120 extern void smedia3362_spi_scl(int);
121 extern void smedia3362_lcm_reset(int);
123 #define SPI_CS(b) smedia3362_spi_cs(b)
124 #define SPI_SDA(b) smedia3362_spi_sda(b)
125 #define SPI_SCL(b) smedia3362_spi_scl(b)
130 /* 150uS minimum clock cycle, we have two of this plus our other
132 #define SPI_DELAY udelay(100) /* 200uS */
135 #define JBT_TX_BUF_SIZE
137 enum jbt_state state
;
139 struct spi_device
*spi_dev
;
142 static struct jbt_info _jbt
, *jbt
= &_jbt
;
144 static int jbt_spi_xfer(int wordnum
, int bitlen
, u_int16_t
*dout
)
146 S3C24X0_GPIO
* const gpio
= S3C24X0_GetBase_GPIO();
147 u_int16_t tmpdout
= 0;
150 DEBUGP("spi_xfer: dout %08X wordnum %u bitlen %d\n",
151 *(uint
*)dout
, wordnum
, bitlen
);
155 for (i
= 0; i
< wordnum
; i
++) {
158 for (j
= 0; j
< bitlen
; j
++) {
160 if (tmpdout
& (1 << bitlen
-1)) {
181 #define JBT_COMMAND 0x000
182 #define JBT_DATA 0x100
184 static int jbt_reg_write_nodata(struct jbt_info
*jbt
, u_int8_t reg
)
188 jbt
->tx_buf
[0] = JBT_COMMAND
| reg
;
190 rc
= jbt_spi_xfer(1, 9, jbt
->tx_buf
);
196 static int jbt_reg_write(struct jbt_info
*jbt
, u_int8_t reg
, u_int8_t data
)
200 jbt
->tx_buf
[0] = JBT_COMMAND
| reg
;
201 jbt
->tx_buf
[1] = JBT_DATA
| data
;
203 rc
= jbt_spi_xfer(2, 9, jbt
->tx_buf
);
208 static int jbt_reg_write16(struct jbt_info
*jbt
, u_int8_t reg
, u_int16_t data
)
212 jbt
->tx_buf
[0] = JBT_COMMAND
| reg
;
213 jbt
->tx_buf
[1] = JBT_DATA
| (data
>> 8);
214 jbt
->tx_buf
[2] = JBT_DATA
| (data
& 0xff);
216 rc
= jbt_spi_xfer(3, 9, jbt
->tx_buf
);
221 static int jbt_init_regs(struct jbt_info
*jbt
)
225 DEBUGP("entering\n");
227 rc
= jbt_reg_write(jbt
, JBT_REG_DISPLAY_MODE1
, 0x01);
228 rc
|= jbt_reg_write(jbt
, JBT_REG_DISPLAY_MODE2
, 0x00);
229 rc
|= jbt_reg_write(jbt
, JBT_REG_RGB_FORMAT
, 0x60);
230 rc
|= jbt_reg_write(jbt
, JBT_REG_DRIVE_SYSTEM
, 0x10);
231 rc
|= jbt_reg_write(jbt
, JBT_REG_BOOSTER_OP
, 0x56);
232 rc
|= jbt_reg_write(jbt
, JBT_REG_BOOSTER_MODE
, 0x33);
233 rc
|= jbt_reg_write(jbt
, JBT_REG_BOOSTER_FREQ
, 0x11);
234 rc
|= jbt_reg_write(jbt
, JBT_REG_BOOSTER_FREQ
, 0x11);
235 rc
|= jbt_reg_write(jbt
, JBT_REG_OPAMP_SYSCLK
, 0x02);
236 rc
|= jbt_reg_write(jbt
, JBT_REG_VSC_VOLTAGE
, 0x2b);
237 rc
|= jbt_reg_write(jbt
, JBT_REG_VCOM_VOLTAGE
, 0x40);
238 rc
|= jbt_reg_write(jbt
, JBT_REG_EXT_DISPL
, 0x03);
239 rc
|= jbt_reg_write(jbt
, JBT_REG_DCCLK_DCEV
, 0x04);
241 * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement
242 * to avoid red / blue flicker
244 rc
|= jbt_reg_write(jbt
, JBT_REG_ASW_SLEW
, 0x04);
245 rc
|= jbt_reg_write(jbt
, JBT_REG_DUMMY_DISPLAY
, 0x00);
247 rc
|= jbt_reg_write(jbt
, JBT_REG_SLEEP_OUT_FR_A
, 0x11);
248 rc
|= jbt_reg_write(jbt
, JBT_REG_SLEEP_OUT_FR_B
, 0x11);
249 rc
|= jbt_reg_write(jbt
, JBT_REG_SLEEP_OUT_FR_C
, 0x11);
250 rc
|= jbt_reg_write16(jbt
, JBT_REG_SLEEP_IN_LCCNT_D
, 0x2040);
251 rc
|= jbt_reg_write16(jbt
, JBT_REG_SLEEP_IN_LCCNT_E
, 0x60c0);
252 rc
|= jbt_reg_write16(jbt
, JBT_REG_SLEEP_IN_LCCNT_F
, 0x1020);
253 rc
|= jbt_reg_write16(jbt
, JBT_REG_SLEEP_IN_LCCNT_G
, 0x60c0);
255 rc
|= jbt_reg_write16(jbt
, JBT_REG_GAMMA1_FINE_1
, 0x5533);
256 rc
|= jbt_reg_write(jbt
, JBT_REG_GAMMA1_FINE_2
, 0x00);
257 rc
|= jbt_reg_write(jbt
, JBT_REG_GAMMA1_INCLINATION
, 0x00);
258 rc
|= jbt_reg_write(jbt
, JBT_REG_GAMMA1_BLUE_OFFSET
, 0x00);
259 rc
|= jbt_reg_write(jbt
, JBT_REG_GAMMA1_BLUE_OFFSET
, 0x00);
261 rc
|= jbt_reg_write16(jbt
, JBT_REG_HCLOCK_VGA
, 0x1f0);
262 rc
|= jbt_reg_write(jbt
, JBT_REG_BLANK_CONTROL
, 0x02);
263 rc
|= jbt_reg_write16(jbt
, JBT_REG_BLANK_TH_TV
, 0x0804);
264 rc
|= jbt_reg_write16(jbt
, JBT_REG_BLANK_TH_TV
, 0x0804);
266 rc
|= jbt_reg_write(jbt
, JBT_REG_CKV_ON_OFF
, 0x01);
267 rc
|= jbt_reg_write16(jbt
, JBT_REG_CKV_1_2
, 0x0000);
269 rc
|= jbt_reg_write16(jbt
, JBT_REG_OEV_TIMING
, 0x0d0e);
270 rc
|= jbt_reg_write16(jbt
, JBT_REG_ASW_TIMING_1
, 0x11a4);
271 rc
|= jbt_reg_write(jbt
, JBT_REG_ASW_TIMING_2
, 0x0e);
274 rc
|= jbt_reg_write16(jbt
, JBT_REG_HCLOCK_QVGA
, 0x00ff);
275 rc
|= jbt_reg_write16(jbt
, JBT_REG_HCLOCK_QVGA
, 0x00ff);
281 static int standby_to_sleep(struct jbt_info
*jbt
)
285 DEBUGP("entering\n");
287 /* three times command zero */
288 rc
= jbt_reg_write_nodata(jbt
, 0x00);
290 rc
= jbt_reg_write_nodata(jbt
, 0x00);
292 rc
= jbt_reg_write_nodata(jbt
, 0x00);
295 /* deep standby out */
296 rc
|= jbt_reg_write(jbt
, JBT_REG_POWER_ON_OFF
, 0x17);
301 static int sleep_to_normal(struct jbt_info
*jbt
)
304 DEBUGP("entering\n");
306 /* RGB I/F on, RAM wirte off, QVGA through, SIGCON enable */
307 rc
= jbt_reg_write(jbt
, JBT_REG_DISPLAY_MODE
, 0x80);
310 rc
|= jbt_reg_write(jbt
, JBT_REG_QUAD_RATE
, 0x00);
312 /* AVDD on, XVDD on */
313 rc
|= jbt_reg_write(jbt
, JBT_REG_POWER_ON_OFF
, 0x16);
316 rc
|= jbt_reg_write16(jbt
, JBT_REG_OUTPUT_CONTROL
, 0xfff9);
319 rc
|= jbt_reg_write_nodata(jbt
, JBT_REG_SLEEP_OUT
);
321 /* at this point we have like 50% grey */
323 /* initialize register set */
324 rc
|= jbt_init_regs(jbt
);
328 static int normal_to_sleep(struct jbt_info
*jbt
)
331 DEBUGP("entering\n");
333 rc
= jbt_reg_write_nodata(jbt
, JBT_REG_DISPLAY_OFF
);
334 rc
|= jbt_reg_write16(jbt
, JBT_REG_OUTPUT_CONTROL
, 0x8002);
335 rc
|= jbt_reg_write_nodata(jbt
, JBT_REG_SLEEP_IN
);
340 static int sleep_to_standby(struct jbt_info
*jbt
)
342 DEBUGP("entering\n");
343 return jbt_reg_write(jbt
, JBT_REG_POWER_ON_OFF
, 0x00);
346 /* frontend function */
347 int jbt6k74_enter_state(enum jbt_state new_state
)
351 DEBUGP("entering(old_state=%u, new_state=%u)\n", jbt
->state
, new_state
);
353 switch (jbt
->state
) {
354 case JBT_STATE_DEEP_STANDBY
:
356 case JBT_STATE_DEEP_STANDBY
:
359 case JBT_STATE_SLEEP
:
360 rc
= standby_to_sleep(jbt
);
362 case JBT_STATE_NORMAL
:
363 /* first transition into sleep */
364 rc
= standby_to_sleep(jbt
);
365 /* then transition into normal */
366 rc
|= sleep_to_normal(jbt
);
370 case JBT_STATE_SLEEP
:
372 case JBT_STATE_SLEEP
:
375 case JBT_STATE_DEEP_STANDBY
:
376 rc
= sleep_to_standby(jbt
);
378 case JBT_STATE_NORMAL
:
379 rc
= sleep_to_normal(jbt
);
383 case JBT_STATE_NORMAL
:
385 case JBT_STATE_NORMAL
:
388 case JBT_STATE_DEEP_STANDBY
:
389 /* first transition into sleep */
390 rc
= normal_to_sleep(jbt
);
391 /* then transition into deep standby */
392 rc
|= sleep_to_standby(jbt
);
394 case JBT_STATE_SLEEP
:
395 rc
= normal_to_sleep(jbt
);
404 int jbt6k74_display_onoff(int on
)
406 DEBUGP("entering\n");
408 return jbt_reg_write_nodata(jbt
, JBT_REG_DISPLAY_ON
);
410 return jbt_reg_write_nodata(jbt
, JBT_REG_DISPLAY_OFF
);
413 int jbt6k74_init(void)
415 S3C24X0_GPIO
* const gpio
= S3C24X0_GetBase_GPIO();
417 #ifndef CONFIG_GTA02_REVISION
418 /* initialize SPI for GPIO bitbang */
419 gpio
->GPGCON
&= 0xffff033f;
420 gpio
->GPGCON
|= 0x00005440;
422 /* get LCM out of reset */
423 gpio
->GPCDAT
|= (1 << 6);
425 smedia3362_lcm_reset(1);
427 /* according to data sheet: wait 50ms (Tpos of LCM). However, 50ms
428 * seems unreliable with later LCM batches, increasing to 90ms */
434 void board_video_init(GraphicDevice
*pGD
)
436 S3C24X0_LCD
* const lcd
= S3C24X0_GetBase_LCD();
438 lcd
->LCDCON1
= 0x00000178; /* CLKVAL=1, BPPMODE=16bpp, TFT, ENVID=0 */
440 lcd
->LCDCON2
= 0x019fc3c1;
441 lcd
->LCDCON3
= 0x0039df67;
442 lcd
->LCDCON4
= 0x00000007;
443 lcd
->LCDCON5
= 0x0001cf09;
444 lcd
->LPCSEL
= 0x00000000;