| #include <common.h> |
| #include <malloc.h> |
| #include <asm/gpio.h> |
| |
| /* Only support 3-wire 9bits spi-lcd for now */ |
| |
| #define LCD_SUB_ID_CNT 3 |
| static u8 sub_id_reg[LCD_SUB_ID_CNT] = {0xDA, 0xDB, 0xDC}; |
| |
| struct lcd_sub_id { |
| u8 val; |
| u8 mask; |
| }; |
| |
| struct lcd_info { |
| const char *name; |
| u8 type; |
| struct lcd_sub_id sub_id[LCD_SUB_ID_CNT]; |
| }; |
| |
| static struct lcd_info lcd_info[] = { |
| {"st7735", 1, {{0x7C, 0x7F}, {0x89, 0xFE}, {0xF0, 0xFF}} }, |
| }; |
| |
| static inline void SPI_DELAY(u16 a) |
| { |
| while (a--) |
| nop(); |
| } |
| |
| static inline void SPI_CS(u16 a) |
| { |
| gpio_direction_output(CONFIG_SPI_CS_PIN, a); |
| } |
| |
| static inline void SPI_SCL(u16 a) |
| { |
| gpio_direction_output(CONFIG_SPI_SCL_PIN, a); |
| } |
| |
| static inline void SPI_TX(u16 a) |
| { |
| gpio_direction_output(CONFIG_SPI_TX_PIN, a); |
| } |
| |
| static inline u8 SPI_READ(void) |
| { |
| return !!gpio_get_value(CONFIG_SPI_TX_PIN); |
| } |
| |
| static inline void SPI_TX_TO_RX(void) |
| { |
| gpio_direction_input(CONFIG_SPI_TX_PIN); |
| } |
| |
| static u8 __lcd_readid(u8 reg) |
| { |
| SPI_CS(0); |
| u16 cmd = reg; |
| int i; |
| /* May need to tune this delay for different panel. |
| * For ST7735, this delay can be set to 0. |
| */ |
| u16 delay = 0; |
| |
| for (i = 0; i < 9; i++) |
| { |
| SPI_TX(cmd & 0x100); |
| SPI_DELAY(delay); |
| SPI_SCL(1); |
| SPI_DELAY(delay); |
| SPI_SCL(0); |
| cmd <<= 1; |
| } |
| |
| SPI_TX_TO_RX(); |
| |
| cmd = 0; |
| for (i = 0; i < 8; i++) |
| { |
| SPI_DELAY(delay); |
| SPI_SCL(1); |
| cmd <<= 1; |
| cmd |= SPI_READ(); |
| SPI_SCL(0); |
| } |
| |
| SPI_CS(1); |
| printf("LCD ID 0x%x: 0x%x\n", reg, cmd); |
| return cmd; |
| } |
| |
| static void do_lcd_rst(void) |
| { |
| gpio_direction_output(CONFIG_LCD_RST_PIN, 1); |
| mdelay(50); |
| gpio_direction_output(CONFIG_LCD_RST_PIN, 0); |
| mdelay(50); |
| gpio_direction_output(CONFIG_LCD_RST_PIN, 1); |
| mdelay(150); |
| } |
| |
| static u8 check_id(u8 id, u8 mask, u8 val) |
| { |
| if ((val & mask) == (id & mask)) |
| return 0; |
| return 1; |
| } |
| |
| u8 lcd_gettype(void) |
| { |
| u32 id = 0; |
| int i; |
| u8 id1, id2, id3; |
| u8 type = 0; |
| |
| lcd_readid_pin_config(); |
| do_lcd_rst(); |
| for (i = 0; i < LCD_SUB_ID_CNT; i++) { |
| id <<= 8; |
| id |= __lcd_readid(sub_id_reg[i]); |
| } |
| lcd_readid_pin_restore(); |
| |
| id1 = (id & 0xFF0000) >> 16; |
| id2 = (id & 0xFF00) >> 8; |
| id3 = id & 0xFF; |
| |
| for (i = 0; i < sizeof(lcd_info) / sizeof(lcd_info[0]); i++) { |
| if (check_id(id1, lcd_info[i].sub_id[0].mask, lcd_info[i].sub_id[0].val) == 0 && |
| check_id(id2, lcd_info[i].sub_id[1].mask, lcd_info[i].sub_id[1].val) == 0 && |
| check_id(id3, lcd_info[i].sub_id[2].mask, lcd_info[i].sub_id[2].val) == 0) |
| { |
| printf("LCD Name: %s, ID: 0x%x, Type: %d\n", |
| lcd_info[i].name, id, lcd_info[i].type); |
| type = lcd_info[i].type; |
| goto end; |
| } |
| } |
| |
| printf("UNSUPPORTTED LCD ID: 0x%x, Type: 0\n", id); |
| end: |
| return type; |
| } |