summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Vogel <vogelchr@vogel.cx>2010-10-11 20:54:57 +0200
committerHarald Welte <laforge@gnumonks.org>2012-02-03 23:59:35 +0100
commitdf4218c8fd6d4a20c8840fd6246e41c58172bc09 (patch)
treeaff0c481d77ab8a070b847fcbdc4a26c63fce0a3
parent080124619d964ccb0ebcb3fb9703423e79029b1f (diff)
Calypso FB: C155 / SSD1783 Color Support
-rw-r--r--src/target/firmware/board/compal_e99/init.c4
-rw-r--r--src/target/firmware/fb/fb_rgb332.c283
-rw-r--r--src/target/firmware/fb/fb_ssd1783.c194
-rw-r--r--src/target/firmware/include/fb/fb_rgb332.h27
4 files changed, 508 insertions, 0 deletions
diff --git a/src/target/firmware/board/compal_e99/init.c b/src/target/firmware/board/compal_e99/init.c
index 8714368a..1d587fa5 100644
--- a/src/target/firmware/board/compal_e99/init.c
+++ b/src/target/firmware/board/compal_e99/init.c
@@ -45,6 +45,8 @@
#include <abb/twl3025.h>
#include <rf/trf6151.h>
+#include <fb/framebuffer.h>
+
#define ARMIO_LATCH_OUT 0xfffe4802
#define IO_CNTL_REG 0xfffe4804
#define ASIC_CONF_REG 0xfffef008
@@ -129,6 +131,8 @@ void board_init(void)
bl_mode_pwl(1);
bl_level(50);
+ fb_init();
+
/* Initialize keypad driver */
keypad_init(1);
diff --git a/src/target/firmware/fb/fb_rgb332.c b/src/target/firmware/fb/fb_rgb332.c
new file mode 100644
index 00000000..223e792d
--- /dev/null
+++ b/src/target/firmware/fb/fb_rgb332.c
@@ -0,0 +1,283 @@
+/* utility functions for a color framebuffer organized
+ as one pixel per byte, with bits mapped as RRRGGGBB.
+ This matches the SSD1783 LC Display Controller used
+ on the Motorola C155 */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+fb_rgb332_clear(){
+ int i,n;
+
+ /* bytes to clear */
+ n = framebuffer->height * framebuffer->width;
+ for(i=0;i<n;i++)
+ fb_rgb332->mem[i]=0xff; /* white */
+
+ /* mark everything as dirty */
+ fb_rgb332->damage_x1 = 0;
+ fb_rgb332->damage_x2 = framebuffer->width;
+ fb_rgb332->damage_y1 = 0;
+ fb_rgb332->damage_y2 = framebuffer->height;
+}
+
+/* update damage rectangle to include the area
+ x1,y1 (upper left) to x2,y2 (lower right)
+ Note that all pixels *including* x1y2 and x2y2 are
+ marked as dirty */
+static void
+fb_rgb332_update_damage(
+ uint16_t x1,uint16_t y1, /* left upper corner (inclusive) */
+ uint16_t x2,uint16_t y2 /* right lower corner (inclusive) */
+){
+ fb_sanitize_box(&x1,&y1,&x2,&y2);
+
+ x2++; /* see definition of fb_rgb332->damage_x2/y2 */
+ y2++;
+
+ /* maybe currently everything is clean? */
+ if(fb_rgb332->damage_x1 == fb_rgb332->damage_x2 ||
+ fb_rgb332->damage_y1 == fb_rgb332->damage_y2
+ ){
+ fb_rgb332->damage_x1 = x1;
+ fb_rgb332->damage_y1 = y1;
+ fb_rgb332->damage_x2 = x2;
+ fb_rgb332->damage_y2 = y2;
+ return;
+ }
+
+ /* grow damage box */
+ if(x1 < fb_rgb332->damage_x1)
+ fb_rgb332->damage_x1 = x1;
+ if(y1 < fb_rgb332->damage_y1)
+ fb_rgb332->damage_y1 = y1;
+ if(x2 > fb_rgb332->damage_x2)
+ fb_rgb332->damage_x2 = x2;
+ if(y2 > fb_rgb332->damage_y2)
+ fb_rgb332->damage_y2 = y2;
+#if 0
+ printf("%s: damage now %d %d %d %d\n",
+ __FUNCTION__,fb_rgb332->damage_x1,fb_rgb332->damage_y1,
+ fb_rgb332->damage_x2,fb_rgb332->damage_y2);
+#endif
+}
+
+/* we trust gcc to move this expensive bitshifting out of
+ the loops in the drawing funtcions */
+static uint8_t rgb_to_pixel(uint32_t color){
+ uint8_t ret;
+ ret = (FB_COLOR_TO_R(color) & 0xe0); /* 765 = RRR */
+ ret |= (FB_COLOR_TO_G(color) & 0xe0) >> 2; /* 432 = GGG */
+ ret |= (FB_COLOR_TO_B(color) & 0xc0) >> 6; /* 10 = BB */
+ return ret;
+}
+
+static void set_pix(uint8_t *pixel,uint32_t color){
+ if(color == FB_COLOR_TRANSP)
+ return;
+ *pixel = rgb_to_pixel(color);
+}
+
+static void set_fg(uint8_t *pixel){
+ set_pix(pixel,framebuffer->fg_color);
+}
+
+static void set_bg(uint8_t *pixel){
+ set_pix(pixel,framebuffer->bg_color);
+}
+
+void fb_rgb332_boxto(uint16_t x2,uint16_t y2)
+{
+ uint16_t x1 = framebuffer->cursor_x;
+ uint16_t y1 = framebuffer->cursor_y;
+ int x,y;
+ uint8_t *p;
+
+ framebuffer->cursor_x = x2;
+ framebuffer->cursor_y = y2;
+
+ fb_sanitize_box(&x1,&y1,&x2,&y2);
+ fb_rgb332_update_damage(x1,y1,x2,y2);
+
+ for(y=y1; y<=y2; y++){
+ p = & fb_rgb332->mem[x1 + framebuffer->width * y];
+ for(x=x1;x<=x2;x++){
+ set_bg(p);
+ if(y==y1 || y==y2 || x==x1 || x==x2) /* border */
+ set_fg(p);
+ p++;
+ }
+ }
+}
+
+/* draw a line like Brensenham did... (roughly) */
+void fb_rgb332_lineto(uint16_t x2,uint16_t y2){
+ uint8_t *p,pixel; /* framebuffer pointer */
+ int delta_regular; /* framebuffer offset per step */
+ int delta_step; /* " */
+
+ uint16_t x1 = framebuffer->cursor_x; /* start */
+ uint16_t y1 = framebuffer->cursor_y;
+
+ int t,tmax; /* counter for steps */
+ int err_inc,err_accu=0; /* error delta and accumulator for */
+ /* Brensenham's algorhithm */
+
+ fb_limit_fb_range(&x1,&y1);
+ fb_limit_fb_range(&x2,&y2);
+ fb_rgb332_update_damage(x1,y1,x2,y2);
+
+ framebuffer->cursor_x = x2; /* end pixel */
+ framebuffer->cursor_y = y2;
+
+ /* pointer to first pixel, pixel value in FB memory */
+ p = fb_rgb332->mem + framebuffer->width * y1 + x1;
+ pixel = rgb_to_pixel(framebuffer->fg_color);
+
+ if(abs(x2-x1) >= abs(y2-y1)){ /* shallow line */
+ /* set pointer deltas for directions */
+ delta_regular = 1; /* X */
+ if(x2 < x1)
+ delta_regular = -delta_regular;
+ delta_step = framebuffer->width; /* Y */
+ if(y2 < y1)
+ delta_step = -delta_step;
+ tmax = abs(x2-x1);
+ err_inc = abs(y2-y1);
+ } else { /* steep line */
+ delta_regular = framebuffer->width; /* Y */
+ if(y2 < y1)
+ delta_regular = -delta_regular;
+ delta_step = 1; /* X */
+ if(x2 < x1)
+ delta_step = -1;
+ tmax = abs(y2-y1);
+ err_inc = abs(x2-y1);
+ }
+
+#if 0
+ printf("%s: (%d,%d) -> (%d,%d) step=%d regular=%d err_inc=%d tmax=%d\n",
+ __FUNCTION__,x1,y1,x2,y2,delta_step,delta_regular,err_inc,tmax);
+#endif
+
+ for(t=0;t<=tmax;t++){
+ *p = pixel;
+ err_accu += err_inc;
+ if(err_accu >= tmax){
+ p += delta_step;
+ err_accu -= tmax;
+ }
+ p += delta_regular;
+ }
+}
+
+int fb_rgb332_putstr(char *str,int maxwidth){
+ const struct fb_font *font = fb_fonts[framebuffer->font];
+ const struct fb_char *fchr;
+
+ int x1,y1,x2,y2; // will become bounding box
+ int y; // coordinates in display
+ int char_x,char_y; // coordinates in font character
+ int bitmap_x,bitmap_y; // coordinates in character's bitmap
+ int byte_per_line; // depending on character width in font
+ int bitmap_offs,bitmap_bit; // offset inside bitmap, bit number of pixel
+ uint8_t *p,fgpixel,bgpixel; // pointer into framebuffer memory
+
+ x1 = framebuffer->cursor_x; // first col (incl!)
+ x2 = x1 + maxwidth - 1; // last col (incl!)
+ if(x2 >= framebuffer->width)
+ x2 = framebuffer->width - 1;
+
+ y1 = framebuffer->cursor_y - font->ascent + 1; // first row
+ y2 = y1 + font->height - 1; // last row
+
+ fgpixel = rgb_to_pixel(framebuffer->fg_color);
+ bgpixel = rgb_to_pixel(framebuffer->bg_color);
+
+ if(y1 < 0) // sanitize in case of overflow
+ y1 = 0;
+ if(y2 >= framebuffer->height)
+ y2 = framebuffer->height - 1;
+
+ /* iterate over all characters */
+ for(;*str && framebuffer->cursor_x <= x2;str++){
+ fchr = fb_font_get_char(font,*str);
+ if(!fchr) /* FIXME: Does '?' exist in every font? */
+ fchr = fb_font_get_char(font,'?');
+ if(!fchr)
+ return 0;
+ byte_per_line = (fchr->bbox_w+7)/8;
+
+ for(y=y1;y<=y2;y++){
+ p=fb_rgb332->mem+y*framebuffer->width;
+ p+=framebuffer->cursor_x;
+
+ for(char_x=0;
+ char_x<fchr->width &&
+ char_x+framebuffer->cursor_x <= x2;
+ char_x++
+ ){
+ /* bitmap coordinates, X= left to right */
+ bitmap_x = char_x - fchr->bbox_x;
+ /* character coords. Y increases from
+ cursor upwards */
+ char_y = framebuffer->cursor_y-y;
+ /* bitmap index = height-(bitmap coords)-1 */
+ bitmap_y = fchr->bbox_h -
+ (char_y - fchr->bbox_y) - 1;
+
+ /* outside pixel data of this
+ character? */
+ if(bitmap_x < 0 ||
+ bitmap_x >= fchr->bbox_w ||
+ bitmap_y < 0 ||
+ bitmap_y >= fchr->bbox_h
+ )
+ goto outside_char_bitmap;
+
+ /* check bit in pixel data for
+ this character */
+ bitmap_offs=bitmap_x/8+bitmap_y*byte_per_line;
+ bitmap_bit=7-(bitmap_x%8);
+
+ /* bit is set */
+ if(fchr->data[bitmap_offs]&(1<<bitmap_bit)){
+ *p = fgpixel;
+ } else { // unset, or outside bitmap
+outside_char_bitmap:
+ *p = bgpixel;
+ }
+ p++;
+ } // for(x...)
+ } // for(char_x...)
+ framebuffer->cursor_x += char_x;
+ } // str
+
+ x2 = framebuffer->cursor_x;
+ fb_rgb332_update_damage(x1,y1,x2,y2);
+ return x2-x1;
+}
+
diff --git a/src/target/firmware/fb/fb_ssd1783.c b/src/target/firmware/fb/fb_ssd1783.c
new file mode 100644
index 00000000..19aa86db
--- /dev/null
+++ b/src/target/firmware/fb/fb_ssd1783.c
@@ -0,0 +1,194 @@
+/* Framebuffer implementation - SSD1783 LCD driver for C155 */
+/* Based on ssd1783.c by Steve Markgraf and Harald Welte */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <delay.h>
+#include <uwire.h>
+#include <calypso/clock.h>
+
+#define SSD1783_WIDTH 98
+#define SSD1783_HEIGHT 67
+#define SSD1783_UWIRE_BITLEN 9
+#define SSD1783_DEV_ID 0
+
+#define LCD_TOP_FREE_ROWS 3
+#define LCD_LEFT_FREE_COLS 0
+#define PIXEL_BYTES 3
+#define FONT_HEIGHT 8
+#define FONT_WIDTH 8
+
+static uint8_t fb_ssd1783_mem[SSD1783_WIDTH * SSD1783_HEIGHT];
+
+enum ssd1783_cmdflag { CMD, DATA, END };
+
+struct ssd1783_cmdlist {
+ enum ssd1783_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 ssd1783_cmdlist
+ssd1783_initdata[] = {
+ { CMD, 0xD1 }, /* CMD set internal oscillator on */
+ { CMD, 0x94 }, /* CMD leave sleep mode */
+ { CMD, 0xbb }, /* CMD Set COM Output Scan Direction: */
+ { DATA, 0x01 }, /* DATA: 01: COM0-79, then COM159-80 */
+/* -------- DIFFERENT FROM ORIGINAL CODE: -------------- */
+/* we use 8bit per pixel packed RGB 332 */
+ { CMD, 0xbc }, /* CMD Set Data Output Scan Direction */
+ { DATA, 0x00 }, /* DATA: column scan, normal rotation, normal display */
+ { DATA, 0x00 }, /* DATA: RGB color arrangement R G B R G B ... */
+/*-->*/ { DATA, 0x01 }, /* DATA: 8 bit per pixel mode MSB <RRRGGGBB> LSB */
+/* --------- /DIFFERENT ---------- */
+ { CMD, 0xce }, /* CMD Set 256 Color Look Up Table LUT */
+ { DATA, 0x00 }, /* DATA: R[000], G[000], B[00] 3-bit R and G have */
+ { DATA, 0x09 }, /* DATA: R[001], G[001] eight levels defined */
+ { DATA, 0x12 }, /* DATA: R[010], G[010] of which the first and */
+ { DATA, 0x1b }, /* DATA: R[011], G[011] the last are shared */
+ { DATA, 0x24 }, /* DATA: R[100], G[100] by 2-bit blue */
+ { DATA, 0x2d }, /* DATA: R[101], G[101] The intermediate two */
+ { DATA, 0x36 }, /* DATA: R[110], G[110] steps are defined */
+ { DATA, 0x3f }, /* DATA: R[111], G[111], B[11] separately */
+ { DATA, 0x12 }, /* DATA: B[01] */
+ { DATA, 0x24 }, /* DATA: B[10] */
+ { CMD, 0xca }, /* CMD Set Display Control - Driver Duty Selection */
+ { DATA, 0xff }, // can't find description of the values in the original
+ { DATA, 0x10 }, // display/ssd1783.c in my datasheet :-(
+ { DATA, 0x01 }, //
+ { CMD, 0xab }, /* CMD Set Scroll Start */
+ { DATA, 0x00 }, /* DATA: Starting address at block 0 */
+ { CMD, 0x20 }, /* CMD Set power control register */
+ { DATA, 0x0b }, /* DATA: booster 6x, reference gen. & int regulator */
+ { CMD, 0x81 }, /* CMD Contrast Lvl & Int. Regul. Resistor Ratio */
+ { DATA, 0x29 }, /* DATA: contrast = 0x29 */
+ { DATA, 0x05 }, /* DATA: 0x05 = 0b101 -> 1+R2/R1 = 11.37 */
+ { CMD, 0xa7 }, /* CMD Invert Display */
+ { CMD, 0x82 }, /* CMD Set Temperature Compensation Coefficient */
+ { DATA, 0x00 }, /* DATA: Gradient is -0.10 % / degC */
+ { CMD, 0xfb }, /* CMD Set Biasing Ratio */
+ { DATA, 0x03 }, /* DATA: 1/10 bias */
+ { CMD, 0xf2 }, /* CMD Set Frame Frequency and N-line inversion */
+ { DATA, 0x08 }, /* DATA: 75 Hz (POR) */
+ { DATA, 0x06 }, /* DATA: n-line inversion: 6 lines */
+ { CMD, 0xf7 }, /* CMD Select PWM/FRC Select Full Col./8col mode */
+ { DATA, 0x28 }, /* DATA: always 0x28 */
+ { DATA, 0x8c }, /* DATA: 4bit PWM + 2 bit FRC */
+ { DATA, 0x05 }, /* DATA: full color mode */
+ { CMD, 0xaf }, /* CMD Display On */
+ { END, 0x00 }, /* MARKER: end of list */
+};
+
+static void
+fb_ssd1783_send_cmdlist(const struct ssd1783_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(SSD1783_DEV_ID, SSD1783_UWIRE_BITLEN, &sendcmd, NULL);
+ p++;
+ i++;
+ }
+}
+
+static void
+fb_ssd1783_init(void){
+ printf("%s: initializing LCD.\n",__FUNCTION__);
+ calypso_reset_set(RESET_EXT, 0);
+ delay_ms(5);
+ uwire_init();
+ delay_ms(5);
+ fb_ssd1783_send_cmdlist(ssd1783_initdata);
+}
+
+/* somehow the palette is messed up, RRR seems to have the
+ bits reversed! R0 R1 R2 G G G B B ---> R2 R1 R0 G G G B B */
+static uint8_t fix_rrr(uint8_t v){
+ return (v & 0x5f) | (v & 0x80) >> 2 | (v & 0x20) << 2;
+}
+
+static void
+fb_ssd1783_flush(void){
+ int x,y;
+ uint8_t *p;
+ struct ssd1783_cmdlist prepare_disp_write_cmds[] = {
+ { CMD, 0x15 }, /* set column address */
+ { DATA, fb_rgb332->damage_x1 },
+ { DATA, fb_rgb332->damage_x2-1 },
+ { CMD, 0x75 }, /* set page address (Y) */
+ { DATA, fb_rgb332->damage_y1 },
+ { DATA, fb_rgb332->damage_y2-1 },
+ { CMD, 0x5c }, /* enter write display ram mode */
+ { END, 0x00 }
+ };
+ struct ssd1783_cmdlist nop[] = {
+ { CMD, 0x25 }, // 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_ssd1783_send_cmdlist(prepare_disp_write_cmds);
+
+ for(y=fb_rgb332->damage_y1;y<fb_rgb332->damage_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;x<fb_rgb332->damage_x2;x++){
+ uint16_t data = 0x0100 | fix_rrr(*p++); // dummy data
+ uwire_xfer(SSD1783_DEV_ID, SSD1783_UWIRE_BITLEN,
+ &data, NULL);
+ }
+ }
+ fb_ssd1783_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_ssd1783_framebuffer = {
+ .name = "ssd1783",
+ .init = fb_ssd1783_init,
+ .clear = fb_rgb332_clear,
+ .boxto = fb_rgb332_boxto,
+ .lineto = fb_rgb332_lineto,
+ .putstr = fb_rgb332_putstr,
+ .flush = fb_ssd1783_flush,
+ .width = SSD1783_WIDTH,
+ .height = SSD1783_HEIGHT
+};
+
+static struct fb_rgb332 fb_ssd1783_rgb332 = {
+ .mem = fb_ssd1783_mem
+};
+
+struct framebuffer *framebuffer = &fb_ssd1783_framebuffer;
+struct fb_rgb332 *fb_rgb332 = &fb_ssd1783_rgb332;
diff --git a/src/target/firmware/include/fb/fb_rgb332.h b/src/target/firmware/include/fb/fb_rgb332.h
new file mode 100644
index 00000000..8bf8168f
--- /dev/null
+++ b/src/target/firmware/include/fb/fb_rgb332.h
@@ -0,0 +1,27 @@
+#ifndef FB_RGB332_H
+#define FB_RGB332_H
+
+/* RGB framebuffer with 1 byte per pixel, bits mapped as RRRGGGBB */
+
+struct fb_rgb332 {
+ uint8_t *mem; /* set to backingstore memory */
+ uint16_t damage_x1,damage_y1; /* current damage window, ul (incl) */
+ uint16_t damage_x2,damage_y2; /* current damage window, lr (excl) */
+};
+
+extern void fb_rgb332_clear();
+
+/* draw a box from cursor to x,y */
+extern void fb_rgb332_boxto(uint16_t x,uint16_t y);
+/* draw a line from cursor to x,y */
+extern void fb_rgb332_lineto(uint16_t x,uint16_t y);
+
+/* put string str onto framebuffer with line (bottom
+ left pixel of, e.g. "m") starting at cursor.
+ Maximum width consumed is maxwidth, actual width
+ needed is returned */
+extern int fb_rgb332_putstr(char *str,int maxwidth);
+
+extern struct fb_rgb332 *fb_rgb332;
+
+#endif