diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c | 314 |
1 files changed, 276 insertions, 38 deletions
diff --git a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c index 8efbdf77b9..dd815df05e 100644 --- a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c +++ b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c | |||
@@ -26,78 +26,316 @@ | |||
26 | #include "system.h" | 26 | #include "system.h" |
27 | #include "cpu.h" | 27 | #include "cpu.h" |
28 | 28 | ||
29 | static int display_type; | 29 | #define CLAMP(x,min,max) \ |
30 | if ((x)<(min)) (x)=(min);\ | ||
31 | if ((x)>(max)) (x)=(max); | ||
30 | 32 | ||
33 | /* the detected lcd type (0 or 1) */ | ||
34 | static int lcd_type; | ||
35 | |||
36 | /* initialises the host lcd hardware, returns the lcd type */ | ||
31 | int lcd_hw_init(void) | 37 | int lcd_hw_init(void) |
32 | { | 38 | { |
39 | /* configure SSP */ | ||
33 | bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE); | 40 | bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE); |
41 | SSP_CPSR = 8; /* TODO: use AS3525_SSP_PRESCALER, OF uses 8 */ | ||
42 | SSP_CR0 = (0 << 8) | /* SCR, serial clock rate divider = 1 */ | ||
43 | (1 << 7) | /* SPH, phase = 1 */ | ||
44 | (1 << 6) | /* SPO, polarity = 1 */ | ||
45 | (0 << 4) | /* FRF, frame format = motorola SPI */ | ||
46 | (7 << 0); /* DSS, data size select = 8 bits */ | ||
47 | SSP_CR1 = (1 << 3) | /* SOD, slave output disable = 1 */ | ||
48 | (0 << 2) | /* MS, master/slave = master */ | ||
49 | (1 << 1) | /* SSE, synchronous serial port enabled = true */ | ||
50 | (0 << 0); /* LBM, loopback mode = normal */ | ||
51 | SSP_IMSC &= ~0xF; /* disable interrupts */ | ||
52 | SSP_DMACR &= ~0x3; /* disable DMA */ | ||
34 | 53 | ||
35 | SSP_CPSR = AS3525_SSP_PRESCALER; /* OF = 0x10 */ | 54 | /* configure GPIO B2 (lcd D/C#) as output */ |
36 | SSP_CR0 = (1<<7) | (1<<6) | 7; /* Motorola SPI frame format, 8 bits */ | ||
37 | SSP_CR1 = (1<<3) | (1<<1); /* SSP Operation enabled */ | ||
38 | SSP_IMSC = 0; /* No interrupts */ | ||
39 | |||
40 | /* configure GPIO B2 (display D/C#) as output */ | ||
41 | GPIOB_DIR |= (1<<2); | 55 | GPIOB_DIR |= (1<<2); |
42 | 56 | ||
43 | /* configure GPIO B3 (display type detect) as input */ | 57 | /* configure GPIO B3 (lcd type detect) as input */ |
44 | GPIOB_DIR &= ~(1<<3); | 58 | GPIOB_DIR &= ~(1<<3); |
45 | 59 | ||
46 | /* set GPIO A5 (display RESET# ?) */ | 60 | /* configure GPIO A5 (lcd reset# ?) as output and set low */ |
47 | GPIOA_DIR |= (1<<5); | 61 | GPIOA_DIR |= (1 << 5); |
48 | GPIOA_PIN(5) = (1<<5); | 62 | GPIOA_PIN(5) = 0; |
49 | 63 | ||
50 | /* detect display type on GPIO B3 */ | 64 | /* detect lcd type on GPIO B3 */ |
51 | return GPIOB_PIN(3) ? 1 : 0; | 65 | return GPIOB_PIN(3) ? 1 : 0; |
52 | } | 66 | } |
53 | 67 | ||
54 | void lcd_write_command(int byte) | 68 | /* writes a command byte to the LCD */ |
69 | static void lcd_write_cmd(uint8_t byte) | ||
55 | { | 70 | { |
56 | while(SSP_SR & (1<<4)) /* BSY flag */ | 71 | /* wait until not busy */ |
57 | ; | 72 | while (SSP_SR & (1<<4)); |
58 | 73 | ||
59 | /* LCD command mode */ | 74 | /* LCD command mode */ |
60 | GPIOB_PIN(2) = 0; | 75 | GPIOB_PIN(2) = 0; |
61 | 76 | ||
77 | /* write data */ | ||
62 | SSP_DATA = byte; | 78 | SSP_DATA = byte; |
63 | while(SSP_SR & (1<<4)) /* BSY flag */ | 79 | |
64 | ; | 80 | /* wait until not busy */ |
81 | while (SSP_SR & (1<<4)); | ||
82 | |||
83 | /* LCD data mode */ | ||
84 | GPIOB_PIN(2) = (1 << 2); | ||
65 | } | 85 | } |
66 | 86 | ||
67 | void lcd_write_data(const fb_data* p_bytes, int count) | 87 | /* writes a data byte to the LCD */ |
88 | static void lcd_write_dat(uint8_t data) | ||
68 | { | 89 | { |
69 | /* LCD data mode */ | 90 | /* wait while transmit FIFO */ |
70 | GPIOB_PIN(2) = (1<<2); | 91 | while (!(SSP_SR & (1<<1))); |
71 | 92 | ||
72 | while (count--) | 93 | /* write data */ |
73 | { | 94 | SSP_DATA = data; |
74 | while(!(SSP_SR & (1<<1))) /* wait until transmit FIFO is not full */ | 95 | } |
75 | ; | ||
76 | 96 | ||
77 | SSP_DATA = *p_bytes++; | 97 | /* writes both a command and data value to the lcd */ |
78 | } | 98 | static void lcd_write(uint8_t cmd, uint8_t data) |
99 | { | ||
100 | lcd_write_cmd(cmd); | ||
101 | lcd_write_dat(data); | ||
79 | } | 102 | } |
80 | 103 | ||
81 | void lcd_update(void) | 104 | /* delays during lcd initialisation (for type 0 LCDs) */ |
105 | static void lcd_delay(int us) | ||
106 | { | ||
107 | udelay(us); | ||
108 | } | ||
109 | |||
110 | /* initialises lcd type 0 */ | ||
111 | static void lcd_init_type0(void) | ||
82 | { | 112 | { |
83 | /* TODO */ | 113 | lcd_write(0x01, 0x00); |
114 | lcd_write(0x14, 0x01); | ||
115 | lcd_delay(5); | ||
116 | |||
117 | lcd_write(0x14, 0x00); | ||
118 | lcd_delay(5); | ||
119 | |||
120 | lcd_write(0x0F, 0x41); | ||
121 | lcd_write(0xEA, 0x0A); | ||
122 | lcd_write(0xEB, 0x42); | ||
123 | lcd_write(0x18, 0x08); | ||
124 | lcd_write(0x1A, 0x0B); | ||
125 | lcd_write(0x48, 0x03); | ||
126 | |||
127 | /* lcd width/height */ | ||
128 | lcd_write(0x30, 0x00); | ||
129 | lcd_write(0x31, 0x5F); | ||
130 | lcd_write(0x32, 0x00); | ||
131 | lcd_write(0x33, 0x5F); | ||
132 | |||
133 | lcd_write(0xE0, 0x10); | ||
134 | lcd_write(0xE1, 0x00); | ||
135 | lcd_write(0xE5, 0x00); | ||
136 | lcd_write(0x0D, 0x00); | ||
137 | lcd_write(0x1D, 0x01); | ||
138 | lcd_write(0x09, 0x00); | ||
139 | lcd_write(0x13, 0x00); | ||
140 | lcd_write(0x16, 0x05); | ||
141 | lcd_write(0x3A, 0x03); | ||
142 | lcd_write(0x3B, 0x03); | ||
143 | lcd_write(0x3C, 0x03); | ||
144 | lcd_write(0x3D, 0x45); | ||
145 | lcd_write(0x3E, 0x45); | ||
146 | lcd_write(0x3F, 0x45); | ||
147 | lcd_write(0x40, 0x62); | ||
148 | lcd_write(0x41, 0x3D); | ||
149 | lcd_write(0x42, 0x46); | ||
150 | } | ||
151 | |||
152 | /* writes a table entry (for type 1 LCDs) */ | ||
153 | static void lcd_write_table(uint8_t val) | ||
154 | { | ||
155 | lcd_write_dat((val >> 4) & 0x07); | ||
156 | lcd_write_dat((val >> 0) & 0x0F); | ||
157 | } | ||
158 | |||
159 | /* initialises lcd type 1 */ | ||
160 | static void lcd_init_type1(void) | ||
161 | { | ||
162 | static const uint8_t curve[256] = { | ||
163 | /* 5-bit curve */ | ||
164 | 0, 5, 10, 15, 20, 25, 30, 35, 39, 43, 47, 51, 55, 59, 63, 67, | ||
165 | 71, 75, 79, 83, 87, 91, 95, 99, 103, 105, 109, 113, 117, 121, 123, 127, | ||
166 | /* 6-bit curve */ | ||
167 | 0, 2, 4, 6, 8, 10, 12, 16, 18, 24, 26, 28, 30, 32, 34, 36, | ||
168 | 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, | ||
169 | 70, 72, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, | ||
170 | 104, 106, 108, 110, 112, 114, 116, 118, 120, 121, 122, 123, 124, 125, 126, 127, | ||
171 | /* 5-bit curve */ | ||
172 | 0, 5, 10, 15, 20, 25, 30, 35, 39, 43, 47, 51, 55, 59, 63, 67, | ||
173 | 71, 75, 79, 83, 87, 91, 93, 97, 101, 105, 109, 113, 117, 121, 124, 127 | ||
174 | }; | ||
175 | int i; | ||
176 | |||
177 | lcd_write_cmd(0x02); | ||
178 | lcd_write_dat(0x00); | ||
179 | |||
180 | lcd_write_cmd(0x01); | ||
181 | |||
182 | lcd_write_cmd(0x03); | ||
183 | lcd_write_dat(0x00); | ||
184 | |||
185 | lcd_write_cmd(0x04); | ||
186 | lcd_write_dat(0x03); | ||
187 | |||
188 | lcd_write_cmd(0x05); | ||
189 | lcd_write_dat(0x08); | ||
190 | |||
191 | lcd_write_cmd(0x06); | ||
192 | lcd_write_dat(0x00); | ||
193 | |||
194 | lcd_write_cmd(0x07); | ||
195 | lcd_write_dat(0x00); | ||
196 | lcd_write_dat(0x00); | ||
197 | lcd_write_dat(0x04); | ||
198 | lcd_write_dat(0x1F); | ||
199 | lcd_write_dat(0x00); | ||
200 | lcd_write_dat(0x00); | ||
201 | lcd_write_dat(0x05); | ||
202 | lcd_write_dat(0x0F); | ||
203 | |||
204 | lcd_write_cmd(0x08); | ||
205 | lcd_write_dat(0x01); | ||
206 | |||
207 | lcd_write_cmd(0x09); | ||
208 | lcd_write_dat(0x07); | ||
209 | |||
210 | /* lcd width/height */ | ||
211 | lcd_write_cmd(0x0A); | ||
212 | lcd_write_dat(0x00); | ||
213 | lcd_write_dat(0x00); | ||
214 | lcd_write_dat(0x05); | ||
215 | lcd_write_dat(0x0F); | ||
216 | lcd_write_dat(0x00); | ||
217 | lcd_write_dat(0x00); | ||
218 | lcd_write_dat(0x05); | ||
219 | lcd_write_dat(0x0F); | ||
220 | |||
221 | lcd_write_cmd(0x0B); | ||
222 | lcd_write_dat(0x00); | ||
223 | lcd_write_dat(0x00); | ||
224 | lcd_write_dat(0x00); | ||
225 | lcd_write_dat(0x00); | ||
226 | |||
227 | lcd_write_cmd(0x0E); | ||
228 | lcd_write_dat(0x04); | ||
229 | lcd_write_dat(0x02); | ||
230 | lcd_write_dat(0x02); | ||
231 | lcd_write_dat(0x05); | ||
232 | lcd_write_dat(0x03); | ||
233 | lcd_write_dat(0x0F); | ||
234 | |||
235 | lcd_write_cmd(0x0F); | ||
236 | lcd_write_dat(0x0A); | ||
237 | lcd_write_dat(0x0A); | ||
238 | lcd_write_dat(0x0A); | ||
239 | |||
240 | lcd_write_cmd(0x1C); | ||
241 | lcd_write_dat(0x08); | ||
242 | |||
243 | lcd_write_cmd(0x1D); | ||
244 | lcd_write_dat(0x00); | ||
245 | lcd_write_dat(0x00); | ||
246 | lcd_write_dat(0x00); | ||
247 | |||
248 | lcd_write_cmd(0x1E); | ||
249 | lcd_write_dat(0x05); | ||
250 | |||
251 | lcd_write_cmd(0x1F); | ||
252 | lcd_write_dat(0x00); | ||
253 | |||
254 | lcd_write_cmd(0x30); | ||
255 | lcd_write_dat(0x10); | ||
256 | |||
257 | lcd_write_cmd(0x3A); | ||
258 | for (i = 0; i < 256; i++) { | ||
259 | lcd_write_table(curve[i]); | ||
260 | } | ||
261 | |||
262 | lcd_write_cmd(0x3C); | ||
263 | lcd_write_dat(0x00); | ||
264 | |||
265 | lcd_write_cmd(0x3D); | ||
266 | lcd_write_dat(0x00); | ||
84 | } | 267 | } |
85 | 268 | ||
269 | /* initialises the lcd */ | ||
86 | void lcd_init_device(void) | 270 | void lcd_init_device(void) |
87 | { | 271 | { |
88 | /* TODO */ | 272 | lcd_type = lcd_hw_init(); |
89 | display_type = lcd_hw_init(); | 273 | if (lcd_type == 0) { |
274 | lcd_init_type0(); | ||
275 | } | ||
276 | else { | ||
277 | lcd_init_type1(); | ||
278 | } | ||
90 | } | 279 | } |
91 | 280 | ||
92 | /* Update a fraction of the display. */ | 281 | /* sets up the lcd to receive frame buffer data */ |
282 | static void lcd_setup_rect(int x, int x_end, int y, int y_end) | ||
283 | { | ||
284 | if (lcd_type == 0) { | ||
285 | lcd_write(0x34, x); | ||
286 | lcd_write(0x35, x_end); | ||
287 | lcd_write(0x36, y); | ||
288 | lcd_write(0x37, y_end); | ||
289 | } | ||
290 | else { | ||
291 | lcd_write_cmd(0x0A); | ||
292 | lcd_write_dat((x >> 8) & 0xFF); | ||
293 | lcd_write_dat((x >> 0) & 0xFF); | ||
294 | lcd_write_dat((x_end >> 8) & 0xFF); | ||
295 | lcd_write_dat((x_end >> 0) & 0xFF); | ||
296 | lcd_write_dat((y >> 8) & 0xFF); | ||
297 | lcd_write_dat((y >> 0) & 0xFF); | ||
298 | lcd_write_dat((y_end >> 8) & 0xFF); | ||
299 | lcd_write_dat((y_end >> 0) & 0xFF); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /* Updates a fraction of the display. */ | ||
93 | void lcd_update_rect(int x, int y, int width, int height) | 304 | void lcd_update_rect(int x, int y, int width, int height) |
94 | { | 305 | { |
95 | (void) x; | 306 | fb_data *ptr; |
96 | (void) y; | 307 | fb_data pixel; |
97 | (void) width; | 308 | int row, col; |
98 | (void) height; | 309 | int x_end = x + width - 1; |
99 | 310 | int y_end = y + height - 1; | |
100 | /* TODO not implemented yet, do a full update instead */ | 311 | |
101 | lcd_update(); | 312 | /* check/correct bounds */ |
313 | CLAMP(x, 0, LCD_WIDTH - 1); | ||
314 | CLAMP(x_end, 0, LCD_WIDTH - 1); | ||
315 | CLAMP(y, 0, LCD_HEIGHT - 1); | ||
316 | CLAMP(y_end, 0, LCD_HEIGHT - 1); | ||
317 | if ((x > x_end) || (y > y_end)) { | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | /* setup GRAM write window */ | ||
322 | lcd_setup_rect(x, x_end, y, y_end); | ||
323 | |||
324 | /* write to GRAM */ | ||
325 | lcd_write_cmd((lcd_type == 0) ? 0x08 : 0x0C); | ||
326 | for (row = y; row <= y_end; row++) { | ||
327 | ptr = &lcd_framebuffer[row][x]; | ||
328 | for (col = x; col <= x_end; col++) { | ||
329 | pixel = *ptr++; | ||
330 | lcd_write_dat((pixel >> 8) & 0xFF); | ||
331 | lcd_write_dat((pixel >> 0) & 0xFF); | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | /* updates the entire lcd */ | ||
337 | void lcd_update(void) | ||
338 | { | ||
339 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
102 | } | 340 | } |
103 | 341 | ||