/* Framebuffer implementation - SSD1963 (S1D15G14 clone) LCD driver for J100i */ /* Based on ssd1963.c by Steve Markgraf and Harald Welte */ /* (C) 2010 by Christian Vogel * (C) 2012 by Steve Markgraf * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #define SSD1963_WIDTH 96 #define SSD1963_HEIGHT 64 #define SSD1963_UWIRE_BITLEN 9 #define SSD1963_DEV_ID 0 static uint8_t fb_ssd1963_mem[SSD1963_WIDTH * SSD1963_HEIGHT]; enum ssd1963_cmdflag { CMD, DATA, END }; struct ssd1963_cmdlist { enum ssd1963_cmdflag is_cmd:8; /* 1: is a command, 0: is data, 2: end marker! */ uint8_t data; /* 8 bit to send to LC display */ } __attribute__((packed)); static const struct ssd1963_cmdlist ssd1963_initdata[] = { { CMD, 0xb6 }, /* CMD Display Control, set panel parameters */ { DATA, 0x4b }, { DATA, 0xf1 }, { DATA, 0x40 }, { DATA, 0x40 }, { DATA, 0x00 }, { DATA, 0x8c }, { DATA, 0x00 }, { CMD, 0x3a }, /* CMD Set pixel format */ { DATA, 0x02 }, /* DATA: 8 bit per pixel */ { CMD, 0x2d }, /* Colour set, RGB332 -> RGB 565 mapping */ { DATA, 0x00 }, /* DATA red 000 */ { DATA, 0x04 }, /* DATA red 001 */ { DATA, 0x09 }, /* DATA red 010 */ { DATA, 0x0d }, /* DATA red 011 */ { DATA, 0x12 }, /* DATA red 100 */ { DATA, 0x16 }, /* DATA red 101 */ { DATA, 0x1b }, /* DATA red 110 */ { DATA, 0x1f }, /* DATA red 111 */ { DATA, 0x00 }, /* Those bytes are probably a second palette */ { DATA, 0x00 }, /* for an unused powersaving mode with reduced colors */ { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, /* DATA green 000 */ { DATA, 0x09 }, /* DATA green 001 */ { DATA, 0x12 }, /* DATA green 010 */ { DATA, 0x1b }, /* DATA green 011 */ { DATA, 0x24 }, /* DATA green 100 */ { DATA, 0x2d }, /* DATA green 101 */ { DATA, 0x36 }, /* DATA green 110 */ { DATA, 0x3f }, /* DATA green 111 */ { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, /* DATA blue 00 */ { DATA, 0x0a }, /* DATA blue 01 */ { DATA, 0x15 }, /* DATA blue 10 */ { DATA, 0x1f }, /* DATA blue 11 */ { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { DATA, 0x00 }, { CMD, 0x11 }, /* CMD Exit sleep mode*/ { CMD, 0xba }, /* CMD Set contrast/Electronic Volume Control */ { DATA, 0x5b }, /* DATA: */ { DATA, 0x84 }, /* DATA: */ { CMD, 0x36 }, /* CMD Memory access control */ { DATA, 0x00 }, /* DATA: */ { CMD, 0x13 }, /* CMD Enter normal mode */ { CMD, 0x29 }, /* CMD Set display on */ { END, 0x00 }, /* MARKER: end of list */ }; static void fb_ssd1963_send_cmdlist(const struct ssd1963_cmdlist *p) { int i=0; while(p->is_cmd != END){ uint16_t sendcmd = p->data; if(p->is_cmd == DATA) sendcmd |= 0x0100; /* 9th bit is cmd/data flag */ uwire_xfer(SSD1963_DEV_ID, SSD1963_UWIRE_BITLEN, &sendcmd, NULL); p++; i++; } } static void fb_ssd1963_init(void){ printf("%s: initializing LCD.\n",__FUNCTION__); calypso_reset_set(RESET_EXT, 0); delay_ms(5); uwire_init(); delay_ms(5); fb_ssd1963_send_cmdlist(ssd1963_initdata); } static void fb_ssd1963_flush(void){ int x,y; uint8_t *p; struct ssd1963_cmdlist prepare_disp_write_cmds[] = { { CMD, 0x2a }, /* set column address */ { DATA, fb_rgb332->damage_x1 }, { DATA, fb_rgb332->damage_x2-1 }, { CMD, 0x2b }, /* set page address (Y) */ { DATA, fb_rgb332->damage_y1 }, { DATA, fb_rgb332->damage_y2-1 }, { CMD, 0x2c }, /* enter write display ram mode */ { END, 0x00 } }; struct ssd1963_cmdlist nop[] = { { CMD, 0x00 }, // NOP command { END, 0x00 } }; /* If everything's clean, just return */ if(fb_rgb332->damage_x1 == fb_rgb332->damage_x2 || fb_rgb332->damage_y1 == fb_rgb332->damage_y2) { printf("%s: no damage\n",__FUNCTION__); return; } fb_ssd1963_send_cmdlist(prepare_disp_write_cmds); for(y=fb_rgb332->damage_y1;ydamage_y2;y++) { p = & fb_rgb332->mem[y * framebuffer->width]; // start of line p += fb_rgb332->damage_x1; // start of damage area for(x=fb_rgb332->damage_x1;xdamage_x2;x++) { uint16_t data = 0x0100 | *p++; uwire_xfer(SSD1963_DEV_ID, SSD1963_UWIRE_BITLEN, &data, NULL); } } fb_ssd1963_send_cmdlist(nop); fb_rgb332->damage_x1 = fb_rgb332->damage_x2 = 0; fb_rgb332->damage_y1 = fb_rgb332->damage_y2 = 0; } static struct framebuffer fb_ssd1963_framebuffer = { .name = "ssd1963", .init = fb_ssd1963_init, .clear = fb_rgb332_clear, .boxto = fb_rgb332_boxto, .lineto = fb_rgb332_lineto, .putstr = fb_rgb332_putstr, .flush = fb_ssd1963_flush, .width = SSD1963_WIDTH, .height = SSD1963_HEIGHT }; static struct fb_rgb332 fb_ssd1963_rgb332 = { .mem = fb_ssd1963_mem }; struct framebuffer *framebuffer = &fb_ssd1963_framebuffer; struct fb_rgb332 *fb_rgb332 = &fb_ssd1963_rgb332;