Commit 1fb3d0dab277a05507009ffd4a5bb0b7e2b66b6a
1 parent
3947c3d5
HD44780 LCD Controller
Only very simple emulation of the LCD controller is included. The controller features the standard HD44780 interface and supports character output on four lines using a static 5x7 font and optional backlight controlled by signal on a separate pin. Capabilities such as custom characters, cursor and 5x10 fonts are not implemented. Saving/loading of device state is not implemented either. Signed-off-by: Filip Navara <filip.navara@gmail.com>
Showing
3 changed files
with
431 additions
and
1 deletions
Makefile.target
@@ -433,7 +433,7 @@ obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o | @@ -433,7 +433,7 @@ obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o | ||
433 | obj-arm-y += syborg_virtio.o | 433 | obj-arm-y += syborg_virtio.o |
434 | obj-arm-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o at91_rtt.o | 434 | obj-arm-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o at91_rtt.o |
435 | obj-arm-y += at91_rstc.o at91_intor.o at91_tc.o at91_emac.o at91pes.o | 435 | obj-arm-y += at91_rstc.o at91_intor.o at91_tc.o at91_emac.o at91pes.o |
436 | -obj-arm-y += gpio_rotary.o gpio_keypad.o | 436 | +obj-arm-y += gpio_rotary.o gpio_keypad.o hd44780.o |
437 | 437 | ||
438 | ifeq ($(TARGET_BASE_ARCH), arm) | 438 | ifeq ($(TARGET_BASE_ARCH), arm) |
439 | CPPFLAGS += -DHAS_AUDIO | 439 | CPPFLAGS += -DHAS_AUDIO |
hw/at91pes.c
@@ -95,6 +95,17 @@ static void at91pes_init(ram_addr_t ram_size, | @@ -95,6 +95,17 @@ static void at91pes_init(ram_addr_t ram_size, | ||
95 | sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xFFFDC000); | 95 | sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xFFFDC000); |
96 | sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[16]); | 96 | sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[16]); |
97 | 97 | ||
98 | + dev = qdev_create(NULL, "gpio,hd44780"); | ||
99 | + qdev_init(dev); | ||
100 | + for (i = 0; i < 3; i++) { | ||
101 | + qdev_connect_gpio_out(pioa, 15 - i, qdev_get_gpio_in(dev, 8 + i)); | ||
102 | + } | ||
103 | + qdev_connect_gpio_out(piob, 28, qdev_get_gpio_in(dev, 11)); | ||
104 | + for (i = 0; i < 4; i++) { | ||
105 | + qdev_connect_gpio_out(pioa, 5 + i, qdev_get_gpio_in(dev, 4 + i)); | ||
106 | + qdev_connect_gpio_out(dev, 4 + i, qdev_get_gpio_in(pioa, 5 + i)); | ||
107 | + } | ||
108 | + | ||
98 | dev = qdev_create(NULL, "gpio,keypad"); | 109 | dev = qdev_create(NULL, "gpio,keypad"); |
99 | qdev_prop_set_ptr(dev, "keys", keys); | 110 | qdev_prop_set_ptr(dev, "keys", keys); |
100 | qdev_init(dev); | 111 | qdev_init(dev); |
hw/hd44780.c
0 → 100644
1 | +/* | ||
2 | + * HD44780 LCD Controller | ||
3 | + * | ||
4 | + * Copyright (c) 2009 Filip Navara | ||
5 | + * | ||
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | + * of this software and associated documentation files (the "Software"), to deal | ||
8 | + * in the Software without restriction, including without limitation the rights | ||
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | + * copies of the Software, and to permit persons to whom the Software is | ||
11 | + * furnished to do so, subject to the following conditions: | ||
12 | + * | ||
13 | + * The above copyright notice and this permission notice shall be included in | ||
14 | + * all copies or substantial portions of the Software. | ||
15 | + * | ||
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | + * THE SOFTWARE. | ||
23 | + */ | ||
24 | + | ||
25 | +#include "sysbus.h" | ||
26 | +#include "console.h" | ||
27 | +#include "pixel_ops.h" | ||
28 | + | ||
29 | +/* pin mapping: | ||
30 | + 8x Data | ||
31 | + Register Select (input only) | ||
32 | + Read/Write (input only) | ||
33 | + Enable (input only) | ||
34 | + Backlight (input only) */ | ||
35 | + | ||
36 | +#define D(x) x | ||
37 | + | ||
38 | +#define PIN_RS 8 | ||
39 | +#define PIN_RW 9 | ||
40 | +#define PIN_E 10 | ||
41 | +#define PIN_BL 11 | ||
42 | + | ||
43 | +#define LCD_CLR 1 /* DB0: clear display */ | ||
44 | +#define LCD_HOME 2 /* DB1: return to home position */ | ||
45 | +#define LCD_ENTRY_MODE 4 /* DB2: set entry mode */ | ||
46 | +#define LCD_ENTRY_INC 2 /* DB1: increment */ | ||
47 | +#define LCD_ENTRY_SHIFT 1 /* DB2: shift */ | ||
48 | +#define LCD_ON_CTRL 8 /* DB3: turn lcd/cursor on */ | ||
49 | +#define LCD_ON_DISPLAY 4 /* DB2: turn display on */ | ||
50 | +#define LCD_ON_CURSOR 2 /* DB1: turn cursor on */ | ||
51 | +#define LCD_ON_BLINK 1 /* DB0: blinking cursor */ | ||
52 | +#define LCD_MOVE 16 /* DB4: move cursor/display */ | ||
53 | +#define LCD_MOVE_DISP 8 /* DB3: move display (0-> move cursor) */ | ||
54 | +#define LCD_MOVE_RIGHT 4 /* DB2: move right (0-> left) */ | ||
55 | +#define LCD_FUNCTION 32 /* DB5: function set */ | ||
56 | +#define LCD_FUNCTION_8BIT 16 /* DB4: set 8BIT mode (0->4BIT mode) */ | ||
57 | +#define LCD_FUNCTION_2LINES 8 /* DB3: two lines (0->one line) */ | ||
58 | +#define LCD_FUNCTION_10DOTS 4 /* DB2: 5x10 font (0->5x7 font) */ | ||
59 | +#define LCD_CGRAM 64 /* DB6: set CG RAM address */ | ||
60 | +#define LCD_DDRAM 128 /* DB7: set DD RAM address */ | ||
61 | +#define LCD_BUSY 64 /* DB7: LCD is busy */ | ||
62 | + | ||
63 | +#define WIDTH 20 | ||
64 | +#define HEIGHT 4 | ||
65 | +#define CZOOM 3 | ||
66 | + | ||
67 | +uint8_t font5x7[][7]={ | ||
68 | +/* */ {0x00,0x00,0x00,0x00,0x00,0x00,0x00}, | ||
69 | +/* ! */ {0x04,0x04,0x04,0x04,0x00,0x00,0x04}, | ||
70 | +/* " */ {0x0A,0x0A,0x0A,0x00,0x00,0x00,0x00}, | ||
71 | +/* # */ {0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A}, | ||
72 | +/* $ */ {0x04,0x0F,0x14,0x0E,0x05,0x1E,0x04}, | ||
73 | +/* % */ {0x18,0x19,0x02,0x04,0x08,0x13,0x03}, | ||
74 | +/* & */ {0x00,0x00,0x00,0x00,0x00,0x00,0x00}, | ||
75 | +/* ' */ {0x0C,0x04,0x08,0x00,0x00,0x00,0x00}, | ||
76 | +/* ( */ {0x02,0x04,0x08,0x08,0x08,0x04,0x02}, | ||
77 | +/* ) */ {0x08,0x04,0x02,0x02,0x02,0x04,0x08}, | ||
78 | +/* * */ {0x00,0x04,0x15,0x0E,0x15,0x04,0x00}, | ||
79 | +/* + */ {0x00,0x04,0x04,0x1F,0x04,0x04,0x00}, | ||
80 | +/* , */ {0x00,0x00,0x00,0x00,0x0C,0x04,0x08}, | ||
81 | +/* - */ {0x00,0x00,0x00,0x1F,0x00,0x00,0x00}, | ||
82 | +/* . */ {0x00,0x00,0x00,0x00,0x00,0x0C,0x0C}, | ||
83 | +/* / */ {0x00,0x01,0x02,0x04,0x08,0x10,0x00}, | ||
84 | +/* 0 */ {0x0E,0x11,0x13,0x15,0x19,0x11,0x0E}, | ||
85 | +/* 1 */ {0x04,0x0C,0x04,0x04,0x04,0x04,0x0E}, | ||
86 | +/* 2 */ {0x0E,0x11,0x01,0x02,0x04,0x08,0x1F}, | ||
87 | +/* 3 */ {0x1F,0x02,0x04,0x02,0x01,0x11,0x0E}, | ||
88 | +/* 4 */ {0x02,0x06,0x0A,0x12,0x1F,0x02,0x02}, | ||
89 | +/* 5 */ {0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E}, | ||
90 | +/* 6 */ {0x06,0x08,0x10,0x1E,0x11,0x11,0x0E}, | ||
91 | +/* 7 */ {0x1F,0x01,0x02,0x04,0x08,0x08,0x08}, | ||
92 | +/* 8 */ {0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E}, | ||
93 | +/* 9 */ {0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C}, | ||
94 | +/* : */ {0x00,0x0C,0x0C,0x00,0x0C,0x0C,0x00}, | ||
95 | +/* ; */ {0x00,0x0C,0x0C,0x00,0x0C,0x04,0x08}, | ||
96 | +/* < */ {0x02,0x04,0x08,0x10,0x08,0x04,0x02}, | ||
97 | +/* = */ {0x00,0x00,0x1F,0x00,0x1F,0x00,0x00}, | ||
98 | +/* > */ {0x08,0x04,0x02,0x01,0x02,0x04,0x08}, | ||
99 | +/* ? */ {0x0E,0x11,0x01,0x02,0x04,0x00,0x04}, | ||
100 | +/* @ */ {0x0E,0x11,0x01,0x0D,0x15,0x15,0x0E}, | ||
101 | +/* A */ {0x0E,0x11,0x11,0x11,0x1F,0x11,0x11}, | ||
102 | +/* B */ {0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E}, | ||
103 | +/* C */ {0x0E,0x11,0x10,0x10,0x10,0x11,0x0E}, | ||
104 | +/* D */ {0x1C,0x12,0x11,0x11,0x11,0x12,0x1C}, | ||
105 | +/* E */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F}, | ||
106 | +/* F */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x10}, | ||
107 | +/* G */ {0x0E,0x11,0x10,0x17,0x11,0x11,0x0F}, | ||
108 | +/* H */ {0x11,0x11,0x11,0x1F,0x11,0x11,0x11}, | ||
109 | +/* I */ {0x0E,0x04,0x04,0x04,0x04,0x04,0x0E}, | ||
110 | +/* J */ {0x07,0x02,0x02,0x02,0x02,0x12,0x0C}, | ||
111 | +/* K */ {0x11,0x12,0x14,0x18,0x14,0x12,0x11}, | ||
112 | +/* L */ {0x10,0x10,0x10,0x10,0x10,0x10,0x1F}, | ||
113 | +/* M */ {0x11,0x1B,0x15,0x15,0x11,0x11,0x11}, | ||
114 | +/* N */ {0x11,0x11,0x19,0x15,0x13,0x11,0x11}, | ||
115 | +/* O */ {0x0E,0x11,0x11,0x11,0x11,0x11,0x0E}, | ||
116 | +/* P */ {0x1E,0x11,0x11,0x1E,0x10,0x10,0x10}, | ||
117 | +/* Q */ {0x0E,0x11,0x11,0x11,0x15,0x12,0x0D}, | ||
118 | +/* R */ {0x1E,0x11,0x11,0x1E,0x14,0x12,0x11}, | ||
119 | +/* S */ {0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E}, | ||
120 | +/* T */ {0x1F,0x04,0x04,0x04,0x04,0x04,0x04}, | ||
121 | +/* U */ {0x11,0x11,0x11,0x11,0x11,0x11,0x0E}, | ||
122 | +/* V */ {0x11,0x11,0x11,0x11,0x11,0x0A,0x04}, | ||
123 | +/* W */ {0x11,0x11,0x11,0x15,0x15,0x15,0x0A}, | ||
124 | +/* X */ {0x11,0x11,0x0A,0x04,0x0A,0x11,0x11}, | ||
125 | +/* Y */ {0x11,0x11,0x11,0x0A,0x04,0x04,0x04}, | ||
126 | +/* Z */ {0x1F,0x01,0x02,0x04,0x08,0x10,0x1F}, | ||
127 | +/* [ */ {0x0E,0x08,0x08,0x08,0x08,0x08,0x0E}, | ||
128 | +/* \ */ {0x00,0x10,0x08,0x04,0x02,0x01,0x00}, | ||
129 | +/* ] */ {0x0E,0x02,0x02,0x02,0x02,0x02,0x0E}, | ||
130 | +/* ^ */ {0x04,0x0A,0x11,0x00,0x00,0x00,0x00}, | ||
131 | +/* _ */ {0x00,0x00,0x00,0x00,0x00,0x00,0x1F}, | ||
132 | +/* ` */ {0x08,0x04,0x02,0x00,0x00,0x00,0x00}, | ||
133 | +/* a */ {0x00,0x00,0x0E,0x01,0x0F,0x11,0x0F}, | ||
134 | +/* b */ {0x10,0x10,0x10,0x16,0x19,0x11,0x1E}, | ||
135 | +/* c */ {0x00,0x00,0x0E,0x10,0x10,0x11,0x0E}, | ||
136 | +/* d */ {0x01,0x01,0x01,0x0D,0x13,0x11,0x0F}, | ||
137 | +/* e */ {0x00,0x00,0x0E,0x11,0x1F,0x10,0x0E}, | ||
138 | +/* f */ {0x06,0x09,0x08,0x1C,0x08,0x08,0x08}, | ||
139 | +/* g */ {0x00,0x0F,0x11,0x11,0x0F,0x01,0x0E}, | ||
140 | +/* h */ {0x10,0x10,0x16,0x19,0x11,0x11,0x11}, | ||
141 | +/* i */ {0x00,0x04,0x00,0x04,0x04,0x04,0x04}, | ||
142 | +/* j */ {0x02,0x00,0x06,0x02,0x02,0x12,0x0C}, | ||
143 | +/* k */ {0x10,0x10,0x12,0x14,0x18,0x14,0x12}, | ||
144 | +/* l */ {0x04,0x04,0x04,0x04,0x04,0x04,0x0F}, | ||
145 | +/* m */ {0x00,0x00,0x1A,0x15,0x15,0x11,0x11}, | ||
146 | +/* n */ {0x00,0x00,0x16,0x19,0x11,0x11,0x11}, | ||
147 | +/* o */ {0x00,0x00,0x0E,0x11,0x11,0x11,0x0E}, | ||
148 | +/* p */ {0x00,0x00,0x1E,0x11,0x1E,0x10,0x10}, | ||
149 | +/* q */ {0x00,0x00,0x0D,0x13,0x0F,0x01,0x01}, | ||
150 | +/* r */ {0x00,0x00,0x16,0x19,0x10,0x10,0x10}, | ||
151 | +/* s */ {0x00,0x00,0x0E,0x10,0x0E,0x01,0x1E}, | ||
152 | +/* t */ {0x08,0x08,0x1C,0x08,0x08,0x09,0x06}, | ||
153 | +/* u */ {0x00,0x00,0x11,0x11,0x11,0x13,0x0D}, | ||
154 | +/* v */ {0x00,0x00,0x11,0x11,0x11,0x0A,0x04}, | ||
155 | +/* w */ {0x00,0x00,0x11,0x11,0x15,0x15,0x0A}, | ||
156 | +/* x */ {0x00,0x00,0x11,0x0A,0x04,0x0A,0x11}, | ||
157 | +/* y */ {0x00,0x00,0x11,0x11,0x0F,0x01,0x0E}, | ||
158 | +/* z */ {0x00,0x00,0x1F,0x02,0x04,0x08,0x1F}, | ||
159 | +/* { */ {0x02,0x04,0x04,0x08,0x04,0x04,0x02}, | ||
160 | +/* | */ {0x04,0x04,0x04,0x04,0x04,0x04,0x04}, | ||
161 | +/* } */ {0x08,0x04,0x04,0x02,0x04,0x04,0x08}, | ||
162 | +}; | ||
163 | + | ||
164 | +typedef struct LCDState { | ||
165 | + SysBusDevice busdev; | ||
166 | + qemu_irq out[8]; | ||
167 | + DisplayState *ds; | ||
168 | + | ||
169 | + uint8_t input; | ||
170 | + uint32_t control : 1; | ||
171 | + uint32_t rw : 1; | ||
172 | + uint32_t backlight : 1; | ||
173 | + | ||
174 | + uint8_t mode8bit : 1; | ||
175 | + uint8_t write_low : 1; | ||
176 | + | ||
177 | + uint8_t ac; /* address counter */ | ||
178 | + uint8_t dispcol; /* first visible column (display shift!) */ | ||
179 | + uint8_t id : 1; /* cursor move increase(1)/decrease(0) */ | ||
180 | + uint8_t sh : 1; /* shift display(1) */ | ||
181 | + uint8_t ddram : 1; /* access ddram(1)/cgram(0) */ | ||
182 | + | ||
183 | + uint8_t display : 1; | ||
184 | + uint8_t cursor : 1; | ||
185 | + uint8_t blink : 1; | ||
186 | + | ||
187 | + uint8_t two_lines : 1; | ||
188 | + uint8_t font5x10 : 1; | ||
189 | + | ||
190 | + uint8_t need_update : 1; | ||
191 | + char data[20 * 4]; | ||
192 | +} LCDState; | ||
193 | + | ||
194 | +static void draw_char(DisplayState *ds, int x, int y, char ch, uint32_t color, uint32_t backcolor) | ||
195 | +{ | ||
196 | + uint8_t *d; | ||
197 | + uint8_t cdata; | ||
198 | + int i, bpp, line; | ||
199 | + | ||
200 | + bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; | ||
201 | + for (line = 0; line < 7 * CZOOM; line++) { | ||
202 | + d = ds_get_data(ds) + ds_get_linesize(ds) * y + bpp * x; | ||
203 | + if (ch >= ' ' && (ch - ' ') < sizeof(font5x7)/sizeof(font5x7[0])) | ||
204 | + cdata = font5x7[(int)(ch - ' ')][line / CZOOM]; | ||
205 | + else | ||
206 | + cdata = font5x7[0][line / CZOOM]; | ||
207 | + switch(bpp) { | ||
208 | + case 1: | ||
209 | + d += 5 * CZOOM; | ||
210 | + for (i = 0; i < 5 * CZOOM; i++) { | ||
211 | + *((uint8_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor; | ||
212 | + d--; | ||
213 | + } | ||
214 | + break; | ||
215 | + case 2: | ||
216 | + d += 10 * CZOOM; | ||
217 | + for (i = 0; i < 5 * CZOOM; i++) { | ||
218 | + *((uint16_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor; | ||
219 | + d -= 2; | ||
220 | + } | ||
221 | + break; | ||
222 | + case 4: | ||
223 | + d += 20 * CZOOM; | ||
224 | + for (i = 0; i < 5 * CZOOM; i++) { | ||
225 | + *((uint32_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor; | ||
226 | + d -= 4; | ||
227 | + } | ||
228 | + break; | ||
229 | + } | ||
230 | + y++; | ||
231 | + } | ||
232 | +} | ||
233 | + | ||
234 | +static void hd44780_enable(LCDState *s) | ||
235 | +{ | ||
236 | + if (s->control) { | ||
237 | + //D(printf("CONTROL: %x\n", s->input)); | ||
238 | + if (s->input & LCD_DDRAM) { | ||
239 | + int ddram_addr = s->input & ~LCD_DDRAM; | ||
240 | + if (ddram_addr >= 0 && ddram_addr < WIDTH) | ||
241 | + s->ac = ddram_addr; | ||
242 | + else if (ddram_addr >= 64 && ddram_addr < 64 + WIDTH) | ||
243 | + s->ac = (ddram_addr - 64) + WIDTH; | ||
244 | + else if (ddram_addr >= 20 && ddram_addr < 20 + WIDTH) | ||
245 | + s->ac = (ddram_addr - 20) + WIDTH * 2; | ||
246 | + else if (ddram_addr >= 84 && ddram_addr < 84 + WIDTH) | ||
247 | + s->ac = (ddram_addr - 84) + WIDTH * 3; | ||
248 | + s->ddram = 1; | ||
249 | + } else if (s->input & LCD_CGRAM) { | ||
250 | + s->ac = s->input & ~LCD_CGRAM; | ||
251 | + s->ddram = 0; | ||
252 | + } else if (s->input & LCD_FUNCTION) { | ||
253 | + s->mode8bit = !!(s->input & LCD_FUNCTION_8BIT); | ||
254 | + s->two_lines = !!(s->input & LCD_FUNCTION_2LINES); | ||
255 | + s->font5x10 = !!(s->input & LCD_FUNCTION_10DOTS); | ||
256 | + } else if (s->input & LCD_MOVE) { | ||
257 | + if (s->input & LCD_MOVE_DISP) { | ||
258 | + if (s->input & LCD_MOVE_RIGHT) { | ||
259 | + s->dispcol--; | ||
260 | + } else { | ||
261 | + s->dispcol++; | ||
262 | + } | ||
263 | + s->dispcol %= sizeof(s->data); | ||
264 | + } else { | ||
265 | + // ... | ||
266 | + } | ||
267 | + } else if (s->input & LCD_ON_CTRL) { | ||
268 | + s->display = !!(s->input & LCD_ON_DISPLAY); | ||
269 | + s->cursor = !!(s->input & LCD_ON_CURSOR); | ||
270 | + s->blink = !!(s->input & LCD_ON_BLINK); | ||
271 | + } else if (s->input & LCD_ENTRY_MODE) { | ||
272 | + s->id = !!(s->input & LCD_ENTRY_INC); | ||
273 | + s->sh = !!(s->input & LCD_ENTRY_SHIFT); | ||
274 | + } else if (s->input & LCD_HOME) { | ||
275 | + s->ac = 0; | ||
276 | + s->dispcol = 0; | ||
277 | + s->ddram = 1; | ||
278 | + } else if (s->input & LCD_CLR) { | ||
279 | + memset(s->data, 32, sizeof(s->data)); | ||
280 | + s->ac = 0; | ||
281 | + s->dispcol = 0; | ||
282 | + s->id = 1; | ||
283 | + s->ddram = 1; | ||
284 | + } | ||
285 | + } else { | ||
286 | + if (s->ddram) { | ||
287 | + s->data[s->ac] = s->input; | ||
288 | + s->ac++; | ||
289 | + s->ac %= sizeof(s->data); | ||
290 | + if (s->sh) { | ||
291 | + if (s->id) { | ||
292 | + s->dispcol++; | ||
293 | + } else { | ||
294 | + s->dispcol--; | ||
295 | + } | ||
296 | + s->dispcol %= sizeof(s->data); | ||
297 | + } | ||
298 | + s->need_update = 1; | ||
299 | + } else { | ||
300 | + // ... | ||
301 | + } | ||
302 | + } | ||
303 | +} | ||
304 | + | ||
305 | +static void hd44780_set_pin(void *opaque, int pin, int level) | ||
306 | +{ | ||
307 | + LCDState *s = opaque; | ||
308 | + | ||
309 | + if (pin >= 0 && pin <= 7) { | ||
310 | + if (!s->rw) { | ||
311 | + if (!s->mode8bit && s->write_low) | ||
312 | + pin -= 4; | ||
313 | + if (level) | ||
314 | + s->input |= 1 << pin; | ||
315 | + else | ||
316 | + s->input &= ~(1 << pin); | ||
317 | + } | ||
318 | + } else if (pin == PIN_RS) { | ||
319 | + s->control = !level; | ||
320 | + } else if (pin == PIN_RW) { | ||
321 | + s->rw = level; | ||
322 | + } else if (pin == PIN_E) { | ||
323 | + if (!level && !s->rw) { | ||
324 | + if (!s->mode8bit) { | ||
325 | + s->write_low = !s->write_low; | ||
326 | + if (!s->write_low) | ||
327 | + hd44780_enable(s); | ||
328 | + } else { | ||
329 | + hd44780_enable(s); | ||
330 | + } | ||
331 | + } | ||
332 | + } else if (pin == PIN_BL) { | ||
333 | + s->backlight = level; | ||
334 | + s->need_update = 1; | ||
335 | + } | ||
336 | +} | ||
337 | + | ||
338 | +static void hd44780_update_display(void *opaque) | ||
339 | +{ | ||
340 | + LCDState *s = opaque; | ||
341 | + uint32_t color_segment, color_led; | ||
342 | + int y, x, r, g, b; | ||
343 | + | ||
344 | + if (s->need_update) { | ||
345 | + if (s->backlight) { | ||
346 | + r = 0; | ||
347 | + g = 0xff; | ||
348 | + b = 0x80; | ||
349 | + } else { | ||
350 | + r = 0xf0; | ||
351 | + g = 0xe0; | ||
352 | + b = 0xb0; | ||
353 | + } | ||
354 | + | ||
355 | + switch (ds_get_bits_per_pixel(s->ds)) { | ||
356 | + case 8: | ||
357 | + color_segment = rgb_to_pixel8(0, 0, 0); | ||
358 | + color_led = rgb_to_pixel8(r, g, b); | ||
359 | + break; | ||
360 | + case 15: | ||
361 | + color_segment = rgb_to_pixel15(0, 0, 0); | ||
362 | + color_led = rgb_to_pixel15(r, g, b); | ||
363 | + break; | ||
364 | + case 16: | ||
365 | + color_segment = rgb_to_pixel16(0, 0, 0); | ||
366 | + color_led = rgb_to_pixel16(r, g, b); | ||
367 | + break; | ||
368 | + case 24: | ||
369 | + color_segment = rgb_to_pixel24(0, 0, 0); | ||
370 | + color_led = rgb_to_pixel24(r, g, b); | ||
371 | + break; | ||
372 | + case 32: | ||
373 | + color_segment = rgb_to_pixel32(0, 0, 0); | ||
374 | + color_led = rgb_to_pixel32(r, g, b); | ||
375 | + break; | ||
376 | + default: | ||
377 | + return; | ||
378 | + } | ||
379 | + | ||
380 | + if (s->display) { | ||
381 | + for (y = 0; y < HEIGHT; y++) { | ||
382 | + for (x = 0; x < WIDTH; x++) { | ||
383 | + draw_char(s->ds, x * 5 * CZOOM, y * 7 * CZOOM, s->data[y * WIDTH + x], color_segment, color_led); | ||
384 | + } | ||
385 | + } | ||
386 | + } | ||
387 | + | ||
388 | + dpy_update(s->ds, 0, 0, WIDTH * CZOOM * 5, HEIGHT * CZOOM * 7); | ||
389 | + } | ||
390 | +} | ||
391 | + | ||
392 | +static void hd44780_invalidate_display(void * opaque) | ||
393 | +{ | ||
394 | + LCDState *s = opaque; | ||
395 | + s->need_update = 1; | ||
396 | +} | ||
397 | + | ||
398 | +static void hd44780_init(SysBusDevice *dev) | ||
399 | +{ | ||
400 | + LCDState *s = FROM_SYSBUS(LCDState, dev); | ||
401 | + | ||
402 | + s->need_update = 1; | ||
403 | + | ||
404 | + qdev_init_gpio_in(&dev->qdev, hd44780_set_pin, 12); | ||
405 | + qdev_init_gpio_out(&dev->qdev, s->out, 8); | ||
406 | + | ||
407 | + s->ds = graphic_console_init(hd44780_update_display, | ||
408 | + hd44780_invalidate_display, | ||
409 | + NULL, NULL, s); | ||
410 | + qemu_console_resize(s->ds, WIDTH * CZOOM * 5, HEIGHT * CZOOM * 7); | ||
411 | +} | ||
412 | + | ||
413 | +static void hd44780_register(void) | ||
414 | +{ | ||
415 | + sysbus_register_dev("gpio,hd44780", sizeof(LCDState), | ||
416 | + hd44780_init); | ||
417 | +} | ||
418 | + | ||
419 | +device_init(hd44780_register) |