summaryrefslogtreecommitdiffstats
path: root/src/target/firmware/fb/fb_ssd1783.c
blob: d05cbf7204a0ab48fc12707c2db9d28f5428cd80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/* 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 red 000 */
	{ DATA, 0x03 },	/* DATA red 001 */
	{ DATA, 0x05 },	/* DATA red 010 */
	{ DATA, 0x07 },	/* DATA red 011 */
	{ DATA, 0x09 },	/* DATA red 100 */
	{ DATA, 0x0b },	/* DATA red 101 */
	{ DATA, 0x0d },	/* DATA red 110 */
	{ DATA, 0x0f },	/* DATA red 111 */
	{ DATA, 0x00 },	/* DATA green 000 */
	{ DATA, 0x03 },	/* DATA green 001 */
	{ DATA, 0x05 },	/* DATA green 010 */
	{ DATA, 0x07 },	/* DATA green 011 */
	{ DATA, 0x09 },	/* DATA green 100 */
	{ DATA, 0x0b },	/* DATA green 101 */
	{ DATA, 0x0d },	/* DATA green 110 */
	{ DATA, 0x0f },	/* DATA green 111 */
	{ DATA, 0x00 },	/* DATA blue 00 */
	{ DATA, 0x05 },	/* DATA blue 01 */
	{ DATA, 0x0a },	/* DATA blue 10 */
	{ DATA, 0x0f },	/* DATA blue 11 */
	{ 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(2);
	uwire_init();
	delay_ms(2);
	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;