Root/userspace/nanonote/lcd.ccp

1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// boot-programs/lcd.ccp: Display driver.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "devices.hh"
20#define ARCH
21#include "arch.hh"
22
23__asm__ volatile (".section .rodata\n.globl charset\ncharset:\n.incbin \"userspace/data/charset.data\"\n.section .text")
24extern unsigned char const charset[127-32][8][6]
25
26#define assert(x) do { if (!(x)) { kdebug ("assertion failed " #x); while (true) {} } } while (0)
27
28#if defined (TRENDTAC)
29static unsigned h = 800, v = 480, fps = 60, Bpp = 2
30#define LOG_X_BASE 1
31#define LOG_Y_BASE 1
32#elif defined (NANONOTE)
33static unsigned h = 320, v = 240, fps = 60, Bpp = 4
34#define LOG_X_BASE 0
35#define LOG_Y_BASE 0
36#else
37#error unknown board
38#endif
39#define frame_size (v * h * Bpp)
40
41static unsigned physical_descriptor
42
43/**/struct Descriptor {
44    unsigned next;
45    unsigned frame;
46    unsigned id;
47    unsigned cmd;
48 } __attribute__ ((packed))
49
50#if defined (NANONOTE)
51#define SP_PORT 2
52#define SPEN 21
53#define SPDA 22
54#define SPCK 23
55
56static void udelay (unsigned num):
57    for unsigned i = 0; i < num * (JZ_EXTAL / 1000000); ++i:
58        // set 0 does nothing, but costs at least one clock pulse.
59        gpio_set (SP_PORT, 0)
60
61// Register names. The registers are not named in the datasheet, and in some cases the name only describes a part of the bits in it.
62// The registers with bit 6 set have bit 7 set instead, because of the transfer method.
63enum spi_reg:
64    AC = 0x00
65    DC = 0x01
66    BRIGHTNESS = 0x03
67    FORMAT = 0x04
68    BACKLIGHT1 = 0x05
69    VBLANK = 0x06
70    HBLANK = 0x07
71    BACKLIGHT2 = 0x08
72    SYNC = 0x0b
73    POLARITY = 0x0c
74    CONTRAST_RGB = 0x0d
75    SUB_CONTRAST_R = 0x0e
76    SUB_BRIGHTNESS_R= 0x0f
77    SUB_CONTRAST_B = 0x10
78    SUB_BRIGHTNESS_B= 0x11
79    TRIM = 0x12
80    COLOR = 0x13
81    GAMMA = 0x16
82    GAMMA1 = 0x17
83    GAMMA2 = 0x18
84    GAMMA3 = 0x19
85    GAMMA4 = 0x1a
86    INVERSION = 0xa5
87    HLEVEL = 0xa6
88    LLEVEL = 0xa7
89    FB = 0xb1
90
91static void write_reg (unsigned reg, unsigned val):
92    unsigned value = (reg << 8) | (val & 0xff)
93    gpio_clear (SP_PORT, 1 << SPEN)
94    udelay (1)
95    for unsigned i = 0; i < 16; ++i, value <<= 1:
96        gpio_clear (SP_PORT, 1 << SPCK)
97        if value & 0x8000:
98            gpio_set (SP_PORT, 1 << SPDA)
99        else:
100            gpio_clear (SP_PORT, 1 << SPDA)
101        udelay (4)
102        gpio_set (SP_PORT, 1 << SPCK)
103        udelay (4)
104    gpio_set (SP_PORT, 1 << SPEN)
105    udelay(4)
106#endif
107
108static void reset ():
109    #if defined (TRENDTAC)
110    // Note that the sync pulse is part of the pre-display region.
111    // Vertical timings.
112    unsigned vsync = 20, vpre = 20, vpost = 0
113    // Horizontal timings.
114    unsigned hsync = 80, hpre = 80, hpost = 0
115
116    // One clock pulse per pixel.
117    unsigned cpp = 1
118    // Bits per pixel.
119    unsigned bpp = LCD_CTRL_BPP_16
120    // Configuration.
121    #define MODE_TFT_GEN 0
122    #define VSYNC_N (1 << 8)
123    unsigned cfg = MODE_TFT_GEN | VSYNC_N
124    #elif defined (NANONOTE)
125    // Note that the sync pulse is part of the pre-display region.
126    // Horizontal timings.
127    unsigned hsync = 1, hpre = 70, hpost = 273
128    // Vertical timings.
129    unsigned vsync = 1, vpre = 21, vpost = 2
130    // 3 clocks per pixel.
131    unsigned cpp = 3
132    // Bits per pixel.
133    unsigned bpp = LCD_CTRL_BPP_18_24
134    // Configuration.
135    unsigned cfg = LCD_CFG_MODE_SERIAL_TFT | LCD_CFG_HSP | LCD_CFG_VSP | LCD_CFG_PCP
136    // Set up SPI pins.
137    gpio_as_output (SP_PORT, (1 << SPEN) | (1 << SPCK) | (1 << SPDA))
138    gpio_set (SP_PORT, (1 << SPEN) | (1 << SPCK))
139    #else
140    #error unknown board
141    #endif
142
143    // Note that the sync pulse is part of the pre-display region.
144    unsigned vpe = vsync, vds = vpre, vde = vds + v, vt = vde + vpost
145    unsigned hpe = hsync, hds = hpre, hde = hds + h, ht = hde + hpost
146
147    cpm_stop_lcd ()
148
149    unsigned pixclock = fps * ht * vt
150
151    #if defined (TRENDTAC)
152    unsigned pllout = cpm_get_pllout ()
153    CPM_CFCR2 = pllout / pixclock - 1
154
155    unsigned val = pllout / (pixclock * 4) - 1
156    assert (pllout / (val + 1) <= 150000000)
157    assert (val <= 0xf)
158    cpm_set_lcdclk_div (val)
159    CPM_CFCR |= CPM_CFCR_UPE
160    #elif defined (NANONOTE)
161    unsigned val = cpm_get_pllout2 () / pixclock - 1
162    //assert (val < 0x400)
163    //cpm_set_pixdiv (val)
164    //cpm_set_pixdiv (12)
165
166    val = cpm_get_pllout2 () / (pixclock * 3) - 1
167    assert (val < 0x20)
168    //cpm_set_ldiv (val)
169    // Update dividers.
170    //CPM_CPCCR |= CPM_CPCCR_CE
171    #else
172    #error "Unknown board"
173    #endif
174
175    cpm_start_lcd ()
176
177    #ifdef NANONOTE
178    // Reset the controller.
179    write_reg (BACKLIGHT1, 0x1e)
180    // Enable display.
181    write_reg (BACKLIGHT1, 0x5e)
182    // Set data to rgbrgbrgb input, with a delta color filter.
183    write_reg (COLOR, 0x01)
184    #endif
185
186    LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM
187    LCD_CFG = cfg
188    LCD_HSYNC = hpe
189    LCD_VSYNC = vpe
190    LCD_VAT = (ht << 16) | vt
191    LCD_DAH = (hds << 16) | hde
192    LCD_DAV = (vds << 16) | vde
193    LCD_DA0 = physical_descriptor
194    LCD_STATE = 0
195    LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM | LCD_CTRL_ENA
196
197static void putchar (unsigned x, unsigned y, unsigned ch):
198    if ch < 32 || ch > 126:
199        ch = 127
200    ch -= 32
201    for unsigned k = 0; k < 6; ++k:
202        for unsigned r = 0; r < 8; ++r:
203            LCD_FRAMEBUFFER_BASE[(y * 8 + r) * h + x * 6 + k] = charset[ch][r][k] * 0x00010101
204
205
206static unsigned log_x = LOG_X_BASE, log_y = LOG_Y_BASE
207static void inc_logx ():
208    if ++log_x >= h / 6:
209        log_x = LOG_X_BASE
210        if ++log_y >= v / 8:
211            log_y = LOG_Y_BASE
212
213static void log_char (unsigned ch):
214    switch ch:
215        case '\n':
216            while log_x < h / 6:
217                putchar (log_x++, log_y, ' ')
218            inc_logx ()
219            break
220        default:
221            putchar (log_x, log_y, ch)
222            inc_logx ()
223
224static void log_str (char const *str):
225    while *str:
226        log_char (*str++)
227
228static void log_num (Iris::Num n):
229    char const *encode = "0123456789abcdef"
230    log_char ('[')
231    for unsigned i = 0; i < 8; ++i:
232        log_char (encode[(n.h >> (4 * (7 - i))) & 0xf])
233    log_char (' ')
234    for unsigned i = 0; i < 8; ++i:
235        log_char (encode[(n.l >> (4 * (7 - i))) & 0xf])
236    log_char (']')
237
238static void log_msg ():
239    log_str ("prot:")
240    log_num (Iris::recv.protected_data)
241    log_str ("data:")
242    for unsigned i = 0; i < 2; ++i:
243        log_num (Iris::recv.data[i])
244    log_char ('\n')
245
246enum captype:
247    LOG = 1
248    BACKLIGHT
249    LCD
250
251static unsigned spot (unsigned x, unsigned y, unsigned cx, unsigned cy):
252    unsigned dx2 = (x - cx) * (x - cx)
253    unsigned dy2 = (y - cy) * (y - cy)
254    unsigned d2 = dx2 + dy2
255    unsigned l = 120
256    if d2 >= l * l:
257        return 0
258    return ((l * l - d2 - 1) << 8) / (l * l)
259
260static unsigned pages
261static Descriptor descriptor __attribute__ ((aligned (16)))
262static bool is_on
263
264static unsigned create (Iris::Memory mem):
265    unsigned physical = mem.alloc_range (pages)
266    unsigned address = 0x15000
267    if physical & ~PAGE_MASK:
268        Iris::panic (0, "can't allocate framebuffer")
269    assert (physical & PAGE_MASK && ~physical)
270    for unsigned i = 0; i < pages; ++i:
271        Iris::Page p = mem.create_page ()
272        p.alloc_physical (physical + (i << PAGE_BITS), false, true)
273        if address != ~0:
274            mem.map (p, address + (i << PAGE_BITS))
275        Iris::free_cap (p)
276    return physical
277
278static void destroy (unsigned physical, Iris::Memory mem):
279    unsigned address = 0x15000
280    if physical == ~0:
281        Iris::panic (0, "unable to destroy framebuffer with wrong cap0")
282    if descriptor.frame == physical && is_on:
283        lcd_clr_ena ()
284        #ifdef NANONOTE
285        write_reg (BACKLIGHT1, 0x5e)
286        #endif
287    if address != ~0:
288        for unsigned i = 0; i < pages; ++i:
289            Iris::Page p = mem.mapping ((void *)(address + (i << PAGE_BITS)))
290            mem.destroy (p)
291            Iris::free_cap (p)
292
293static void use (unsigned physical):
294    if physical == ~0:
295        Iris::panic (0, "unable to use framebuffer with wrong cap0")
296    bool was_unused = descriptor.frame == 0
297    descriptor.frame = physical
298    unsigned dptr = (unsigned)&descriptor
299    __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
300    if was_unused && is_on:
301        lcd_set_ena ()
302        #ifdef NANONOTE:
303        write_reg (BACKLIGHT1, 0x5f)
304        #endif
305
306static void unuse (unsigned physical):
307    if physical == ~0:
308        Iris::panic (0, "unable to unuse framebuffer with wrong cap0")
309    if descriptor.frame == physical:
310        lcd_clr_ena ()
311        #ifdef NANONOTE
312        write_reg (BACKLIGHT1, 0x5e)
313        #endif
314        descriptor.frame = 0
315
316Iris::Num start ():
317    Iris::schedule ()
318    map_lcd ()
319    map_cpm ()
320    #ifdef NANONOTE
321    map_gpio ()
322    #endif
323
324    pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
325    unsigned physical = 0
326    Iris::Page p = Iris::my_memory.mapping (&descriptor)
327    unsigned paddr = p.physical_address ()
328    physical_descriptor = paddr + ((unsigned)&descriptor & ~PAGE_MASK)
329    Iris::free_cap (p)
330    descriptor.next = physical_descriptor
331    descriptor.frame = physical
332    descriptor.id = 0xdeadbeef
333    descriptor.cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT)
334    unsigned dptr = (unsigned)&descriptor
335    __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
336    reset ()
337
338    #if defined (TRENDTAC)
339    Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
340    __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
341    #endif
342
343    // Register the backlight device.
344    Iris::Setting backlight = Iris::my_receiver.create_capability (BACKLIGHT)
345    Iris::my_parent.provide_capability <Iris::Setting> (backlight.copy ())
346    Iris::free_cap (backlight)
347
348    // Register the display device.
349    Iris::Display display = Iris::my_receiver.create_capability (LCD)
350    Iris::my_parent.provide_capability <Iris::Display> (display.copy ())
351    Iris::free_cap (display)
352
353    Iris::my_parent.init_done ()
354
355    Iris::Cap eof_cb
356    bool have_eof = false
357    is_on = true
358    while true:
359        Iris::wait ()
360        //log_msg ()
361        switch Iris::recv.protected_data.l:
362            case 0:
363                have_eof = false
364                eof_cb.invoke ()
365                Iris::free_cap (eof_cb)
366                break
367            #if defined (TRENDTAC)
368            case LOG:
369                log_char (Iris::recv.data[0].l)
370                break
371            #endif
372            case BACKLIGHT:
373                switch Iris::recv.data[0].l:
374                    case Iris::Device::RESET:
375                        Iris::recv.reply.invoke ()
376                        break
377                    case Iris::Setting::SET:
378                        // TODO
379                        unsigned state = Iris::recv.data[1].l
380                        if !state:
381                            #if defined (NANONOTE)
382                            if is_on:
383                                write_reg (BACKLIGHT1, 0x5e)
384                                is_on = false
385                            #else
386                            #endif
387                        else:
388                            #if defined (NANONOTE)
389                            if !is_on:
390                                write_reg (BACKLIGHT1, 0x5f)
391                                is_on = true
392                            #else
393                            #endif
394                        Iris::recv.reply.invoke ()
395                        break
396                    case Iris::Setting::GET_RANGE:
397                        Iris::recv.reply.invoke (~0)
398                        break
399                    default:
400                        Iris::panic (0, "invalid operation for backlight")
401                        break
402                break
403            case LCD:
404                switch Iris::recv.data[0].l:
405                    case Iris::Device::RESET:
406                        Iris::recv.reply.invoke ()
407                        break
408                    case Iris::Display::SET_EOF_CB:
409                        Iris::Cap reply = Iris::get_reply ()
410                        Iris::Cap arg = Iris::get_arg ()
411                        if have_eof:
412                            Iris::free_cap (eof_cb)
413                            Iris::panic (0, "replacing eof_cb")
414                        else:
415                            lcd_clr_eof ()
416                            Iris::register_interrupt (IRQ_LCD)
417                            have_eof = true
418                        eof_cb = arg
419                        reply.invoke ()
420                        Iris::free_cap (reply)
421                        break
422                    case Iris::Display::MAP_FB:
423                        unsigned addr = Iris::recv.data[1].l
424                        unsigned use = Iris::recv.data[0].h
425                        Iris::Cap reply = Iris::get_reply ()
426                        Iris::Memory mem = Iris::get_arg ()
427                        unsigned physical = mem.alloc_range (pages)
428                        assert (physical & PAGE_MASK && ~physical)
429                        Iris::Caps ret = mem.create_caps (pages / 63 + 1)
430                        unsigned slot = ret.use ()
431                        for unsigned c = 0; c < pages / 63 + 1; ++c:
432                            Iris::Caps caps (Iris::Cap (slot, c))
433                            unsigned num = pages - 63 * c >= 63 ? 63 : pages - 63 * c
434                            Iris::set_recv_arg (caps)
435                            mem.create_caps (num)
436                            unsigned slot2 = caps.use ()
437                            for unsigned i = 0; i < num; ++i:
438                                Iris::Page p = Iris::Cap (slot2, i)
439                                Iris::set_recv_arg (p)
440                                mem.create_page ()
441                                p.alloc_physical (physical + ((63 * c + i) << PAGE_BITS), false, true)
442                                mem.map (p, addr + ((63 * c + i) << PAGE_BITS))
443                            Iris::free_slot (slot2)
444                        Iris::free_slot (slot)
445                        reply.invoke (0, 0, ret.copy ())
446                        Iris::free_cap (ret)
447                        Iris::free_cap (mem)
448                        Iris::free_cap (reply)
449                        if !use:
450                            break
451                        bool was_unused = descriptor.frame == 0
452                        descriptor.frame = physical
453                        unsigned dptr = (unsigned)&descriptor
454                        __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
455                        if was_unused && is_on:
456                            lcd_set_ena ()
457                            #ifdef NANONOTE:
458                            write_reg (BACKLIGHT1, 0x5f)
459                            #endif
460                        break
461                    case Iris::Display::UNMAP_FB:
462                        Iris::panic (0, "unmap_fb isn't implemented yet")
463                    case Iris::Display::GET_INFO:
464                        Iris::panic (0, "get_info isn't implemented yet.")
465                    default:
466                        Iris::panic (Iris::recv.data[0].l, "invalid operation for lcd")
467                break
468            default:
469                Iris::panic (0, "invalid operation type for lcd")
470                break
471

Archive Download this file

Branches:
master



interactive