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
static void lcdctrl_init(void)
{
    /* alpha b111
     * stop at current frame complete
     * MCU mode
     * 24b RGB
     */

    LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU;
    MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS;
    HOR_BP = LCD_WIDTH + 3;
    VERT_BP = LCD_HEIGHT;

    LINE0_YADDR = 0;
    LINE1_YADDR = (1 * LCD_WIDTH/2);
    LINE2_YADDR = (2 * LCD_WIDTH/2);
    LINE3_YADDR = (3 * LCD_WIDTH/2);

    LINE0_UVADDR = 1;
    LINE1_UVADDR = (1 * LCD_WIDTH/2) + 1;
    LINE2_UVADDR = (2 * LCD_WIDTH/2) + 1;
    LINE3_UVADDR = (3 * LCD_WIDTH/2) + 1;



    LCDC_INTR_MASK = 0;//INTR_MASK_LINE; /* INTR_MASK_EVENLINE; */
}
static void dwdma_init(void)
{
    DWDMA_DMA_CHEN = 0xf00;
    DWDMA_CLEAR_BLOCK = 0x0f;
    DWDMA_DMA_CFG = 1; /* global enable */
}


static void iomux_lcd(enum lcdif_mode_t mode)
{
    unsigned long muxa;

    muxa = SCU_IOMUXA_CON & ~(IOMUX_LCD_VSYNC|IOMUX_LCD_DEN|0xff);

    if (mode == LCDIF_18BIT)
    {
        muxa |= IOMUX_LCD_D18|IOMUX_LCD_D20|IOMUX_LCD_D22|IOMUX_LCD_D17|IOMUX_LCD_D16;
    }

    SCU_IOMUXA_CON = muxa;
    SCU_IOMUXB_CON |= IOMUX_LCD_D815;
}

void lcdif_init(enum lcdif_mode_t mode)
{
    iomux_lcd(mode);   /* setup pins for lcd interface */
    dwdma_init();
    lcdctrl_init();    /* basic lcdc module configuration */
    create_llp();
    lcdctrl_bypass(1); /* run in bypass mode - all writes goes directly to lcd controller */
}

/* This is ugly hack. We drive lcd in bypass mode
 * where all writes goes directly to lcd controller.
 * This is suboptimal at best. IF module povides
 * FIFO, internal sram buffer, hardware scaller,
 * DMA signals, hardware alpha blending and more.
 * BUT the fact is that I have no idea how to use
 * this modes. Datasheet floating around is very
 * unclean in this regard and OF uses ackward
 * lcd update routines which are hard to understand.
 * Moreover OF sets some bits in IF module registers
 * which are referred as reseved in datasheet.
 */

/* dwdma linked list struct */
struct llp_t {
    uint32_t sar;
    uint32_t dar;
    struct llp_t *llp;
    uint32_t ctl_l;
    uint32_t ctl_h;
    uint32_t dstat;
};


/* structs which describe full screen update */
struct llp_t scr_llp[LCD_HEIGHT];


static void llp_setup(void *src, void *dst, struct llp_t *llp, uint32_t size)
{
    llp->sar = (uint32_t)src;
    llp->dar = (uint32_t)dst;
    llp->llp = llp + 1;
    llp->ctl_h = size;
    llp->ctl_l = (1<<20) |
                 (1<<23) |
                 (1<<17) |
                 (2<<1)  |
                 (2<<4)  |
                 (3<<11) |
                 (3<<14) |
                 (1<<27) |
                 (1<<28);
}

static void llp_end(struct llp_t *llp)
{
    llp->ctl_l &= ~((1<<27)|(1<<28));
}


static void dwdma_start(uint8_t ch, struct llp_t *llp, uint8_t handshake)
{
    DWDMA_SAR(ch) = 0;
    DWDMA_DAR(ch) = 0;
    DWDMA_LLP(ch) = (uint32_t)llp;
    DWDMA_CTL_L(ch) = (1<<20) |
                      (1<<23) |
                      (1<<17) |
                      (2<<1)  |
                      (2<<4)  |
                      (3<<11) |
                      (3<<14) |
                      (1<<27) |
                      (1<<28);

   DWDMA_CTL_H(ch) = 1;
   DWDMA_CFG_L(ch) = (7<<5);
   DWDMA_CFG_H(ch) = (handshake<<11)|(1<<2);
   DWDMA_SGR(ch) = (13<<20);
   DWDMA_DMA_CHEN = (0x101<<ch);

}


void create_llp(void)
{
    int i = 0;

    /* build LLPs */
    for (i=0; i<LCD_HEIGHT; i++)
        llp_setup(FBADDR(0,i), &LCD_BUFF+(i%4)*LCD_WIDTH/2, &scr_llp[i], LCD_WIDTH/2);
    llp_end(&scr_llp[LCD_HEIGHT-1]);
}

void lcd_update()
{
    lcdctrl_bypass(0);
    //memset((void *)&LCD_BUFF, 0x00, 2048*4);
    while (!(LCDC_STA & LCDC_MCU_IDLE));
    dwdma_start(0, scr_llp, 6);
    udelay(100);

    MCU_CTRL=(1<<1)|(1<<2)|(1<<5);
}