NanoPayload

Annotated stage2/jzlcd.c

224:d41c05accd39
2017-07-09 Paul Boddie Parameterised LCD controller initialisation, allowing addresses to be passed in rather than being calculated within the function. Changed various descriptor structure member names.
paul@33 1
/*
paul@224 2
 * jz4740 LCD controller configuration.
paul@33 3
 *
paul@33 4
 * Copyright (C) Xiangfu Liu <xiangfu@sharism.cc>
paul@217 5
 * Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
paul@33 6
 *
paul@33 7
 * This program is free software; you can redistribute it and/or
paul@33 8
 * modify it under the terms of the GNU General Public License as
paul@33 9
 * published by the Free Software Foundation; either version 2 of
paul@33 10
 * the License, or (at your option) any later version.
paul@33 11
 *
paul@33 12
 * This program is distributed in the hope that it will be useful,
paul@33 13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@33 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
paul@33 15
 * GNU General Public License for more details.
paul@33 16
 *
paul@33 17
 * You should have received a copy of the GNU General Public License
paul@33 18
 * along with this program; if not, write to the Free Software
paul@42 19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@42 20
 * Boston, MA  02110-1301, USA
paul@33 21
 */
paul@33 22
paul@33 23
#include "sdram.h"
paul@33 24
#include "jzlcd.h"
paul@62 25
#include "cpu.h"
paul@33 26
#include "board.h"
paul@33 27
paul@223 28
extern vidinfo_t panel_info;
paul@223 29
paul@223 30
/* Useful alignment operations. */
paul@223 31
paul@223 32
static inline void align2(uint32_t *n)
paul@223 33
{
paul@223 34
	*n = (((*n)+1)>>1)<<1;
paul@223 35
}
paul@223 36
paul@223 37
static inline void align4(uint32_t *n)
paul@223 38
{
paul@223 39
	*n = (((*n)+3)>>2)<<2;
paul@223 40
}
paul@223 41
paul@223 42
static inline void align8(uint32_t *n)
paul@223 43
{
paul@223 44
	*n = (((*n)+7)>>3)<<3;
paul@223 45
}
paul@33 46
paul@223 47
paul@223 48
paul@223 49
/* Register operations. */
paul@223 50
paul@223 51
static inline uint32_t lcd_ctrl_get(vidinfo_t *vid, uint32_t reg)
paul@223 52
{
paul@223 53
	return REG32(vid->lcd + reg);
paul@223 54
}
paul@223 55
paul@223 56
static inline void lcd_ctrl_set(vidinfo_t *vid, uint32_t reg, uint32_t value)
paul@223 57
{
paul@223 58
	REG32(vid->lcd + reg) = value;
paul@223 59
}
paul@223 60
paul@223 61
paul@223 62
paul@223 63
/* Configuration operations. */
paul@223 64
paul@223 65
/* Return the number of panels available. */
paul@33 66
paul@224 67
static uint8_t lcd_get_panels(vidinfo_t *vid)
paul@100 68
{
paul@221 69
	struct jzfb_info *jzfb = vid->jz_fb;
paul@221 70
	return ((jzfb->cfg & MODE_MASK) == MODE_STN_MONO_DUAL) ||
paul@221 71
		((jzfb->cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ? 2 : 1;
paul@100 72
}
paul@100 73
paul@223 74
/* Calculate and return the pixel clock frequency. */
paul@223 75
paul@224 76
static uint32_t lcd_get_pixel_clock(vidinfo_t *vid)
paul@223 77
{
paul@223 78
	struct jzfb_info *jzfb = vid->jz_fb;
paul@223 79
	uint32_t pclk, width_cycles, mode = jzfb->cfg & MODE_MASK;
paul@223 80
paul@223 81
	/*
paul@223 82
	Serial mode: 3 pixel clock cycles per pixel (one per channel).
paul@223 83
	Parallel mode: 1 pixel clock cycle per pixel.
paul@223 84
	*/
paul@223 85
paul@223 86
	if (mode == MODE_8BIT_SERIAL_TFT)
paul@223 87
		width_cycles = jzfb->w * 3;
paul@223 88
	else
paul@223 89
		width_cycles = jzfb->w;
paul@223 90
paul@223 91
	/* Derive pixel clock from frame clock. */
paul@223 92
paul@223 93
	pclk = jzfb->fclk *
paul@223 94
		(width_cycles + jzfb->hsw + jzfb->elw + jzfb->blw) *
paul@223 95
		(jzfb->h + jzfb->vsw + jzfb->efw + jzfb->bfw);
paul@223 96
paul@223 97
	if ((mode == MODE_STN_COLOR_SINGLE) || (mode == MODE_STN_COLOR_DUAL))
paul@223 98
		pclk = (pclk * 3);
paul@223 99
paul@223 100
	if ((mode == MODE_STN_COLOR_SINGLE) || (mode == MODE_STN_COLOR_DUAL) ||
paul@223 101
	    (mode == MODE_STN_MONO_SINGLE) || (mode == MODE_STN_MONO_DUAL))
paul@223 102
		pclk = pclk >> ((jzfb->cfg & STN_DAT_PINMASK) >> 4);
paul@223 103
paul@223 104
	if ((mode == MODE_STN_COLOR_DUAL) || (mode == MODE_STN_MONO_DUAL))
paul@223 105
		pclk >>= 1;
paul@223 106
paul@223 107
	return pclk;
paul@223 108
}
paul@223 109
paul@102 110
paul@102 111
paul@102 112
/* Functions returning region sizes. */
paul@102 113
paul@217 114
static uint32_t lcd_get_size(vidinfo_t *vid)
paul@33 115
{
paul@100 116
	/* Lines must be aligned to a word boundary. */
paul@221 117
	uint32_t line_length = ALIGN((vid->jz_fb->w * vid->jz_fb->bpp) / 8, sizeof(uint32_t));
paul@221 118
        return line_length * vid->jz_fb->h;
paul@33 119
}
paul@33 120
paul@217 121
static uint32_t lcd_get_aligned_size(vidinfo_t *vid)
paul@100 122
{
paul@100 123
	/* LCD_CTRL_BST_16 requires 16-word alignment. */
paul@217 124
        return ALIGN(lcd_get_size(vid), 16 * sizeof(uint32_t));
paul@100 125
}
paul@100 126
paul@217 127
static uint32_t lcd_get_min_size(vidinfo_t *vid)
paul@100 128
{
paul@100 129
	/* Lines must be aligned to a word boundary. */
paul@221 130
	uint32_t line_length = ALIGN((vid->jz_fb->w * 32) / 8, sizeof(uint32_t));
paul@221 131
        return line_length * vid->jz_fb->h;
paul@100 132
}
paul@100 133
paul@217 134
static uint32_t lcd_get_aligned_min_size(vidinfo_t *vid)
paul@100 135
{
paul@100 136
	/* LCD_CTRL_BST_16 requires 16-word alignment. */
paul@217 137
        return ALIGN(lcd_get_min_size(vid), 16 * sizeof(uint32_t));
paul@100 138
}
paul@100 139
paul@217 140
static uint32_t lcd_get_palette_size(vidinfo_t *vid)
paul@97 141
{
paul@224 142
	/* Get a collection of two-byte entries, one per colour. */
paul@224 143
paul@221 144
	if (vid->jz_fb->bpp < 12)
paul@221 145
		return (1 << (vid->jz_fb->bpp)) * sizeof(uint16_t);
paul@102 146
	else
paul@102 147
		return 0;
paul@97 148
}
paul@97 149
paul@217 150
static uint32_t lcd_get_aligned_palette_size(vidinfo_t *vid)
paul@100 151
{
paul@100 152
	/* LCD_CTRL_BST_16 requires 16-word alignment. */
paul@217 153
	return ALIGN(lcd_get_palette_size(vid), 16 * sizeof(uint32_t));
paul@100 154
}
paul@100 155
paul@217 156
static uint32_t lcd_get_descriptors_size()
paul@98 157
{
paul@98 158
	return 3 * sizeof(struct jz_fb_dma_descriptor);
paul@98 159
}
paul@98 160
paul@217 161
static uint32_t lcd_get_total_size(vidinfo_t *vid)
paul@97 162
{
paul@221 163
	uint32_t size = lcd_get_aligned_size(vid) * lcd_get_panels(vid);
paul@217 164
	uint32_t min_size = lcd_get_aligned_min_size(vid);
paul@100 165
paul@100 166
        /* Round up to nearest full page, or MMU section if defined. */
paul@102 167
	return ALIGN((size >= min_size ? size : min_size) + lcd_get_aligned_palette_size(vid) + lcd_get_descriptors_size(), PAGE_SIZE);
paul@93 168
}
paul@48 169
paul@102 170
paul@102 171
paul@102 172
/* Functions returning addresses of each data region. */
paul@102 173
paul@224 174
static uint32_t lcd_get_palette(vidinfo_t *vid)
paul@93 175
{
paul@224 176
        /* Use memory at the end of the allocated region for the palette. */
paul@224 177
paul@224 178
	return get_memory_size() - lcd_get_aligned_palette_size(vid);
paul@98 179
}
paul@98 180
paul@224 181
static uint32_t lcd_get_descriptors(vidinfo_t *vid)
paul@98 182
{
paul@224 183
        /* Use memory before the palette for the descriptor array. */
paul@224 184
paul@224 185
	return lcd_get_palette(vid) - lcd_get_descriptors_size();
paul@48 186
}
paul@48 187
paul@224 188
static uint32_t lcd_get_framebuffer(uint16_t panel, vidinfo_t *vid)
paul@97 189
{
paul@224 190
        /* Framebuffers for panels are allocated at the start of the region. */
paul@224 191
paul@224 192
        return get_memory_size() - lcd_get_total_size(vid) + (panel * lcd_get_aligned_size(vid));
paul@97 193
}
paul@97 194
paul@102 195
paul@102 196
paul@102 197
/* Initialisation functions. */
paul@102 198
paul@221 199
static uint32_t jz_lcd_stn_init(uint32_t stnH, vidinfo_t *vid)
paul@96 200
{
paul@221 201
	struct jzfb_info *jzfb = vid->jz_fb;
paul@217 202
	uint32_t val = 0;
paul@96 203
paul@221 204
	switch (jzfb->bpp) {
paul@223 205
		case 1:
paul@96 206
		/* val |= LCD_CTRL_PEDN; */
paul@223 207
		case 2:
paul@96 208
		val |= LCD_CTRL_FRC_2;
paul@96 209
		break;
paul@223 210
paul@223 211
		case 4:
paul@96 212
		val |= LCD_CTRL_FRC_4;
paul@96 213
		break;
paul@223 214
paul@223 215
		case 8:
paul@223 216
		default:
paul@96 217
		val |= LCD_CTRL_FRC_16;
paul@96 218
		break;
paul@96 219
	}
paul@96 220
paul@221 221
	switch (jzfb->cfg & STN_DAT_PINMASK) {
paul@223 222
		case STN_DAT_PIN1:
paul@96 223
		/* Do not adjust the hori-param value. */
paul@96 224
		break;
paul@223 225
paul@223 226
		case STN_DAT_PIN2:
paul@223 227
		align2(&jzfb->hsw);
paul@223 228
		align2(&jzfb->elw);
paul@223 229
		align2(&jzfb->blw);
paul@96 230
		break;
paul@223 231
paul@223 232
		case STN_DAT_PIN4:
paul@223 233
		align4(&jzfb->hsw);
paul@223 234
		align4(&jzfb->elw);
paul@223 235
		align4(&jzfb->blw);
paul@96 236
		break;
paul@223 237
paul@223 238
		case STN_DAT_PIN8:
paul@223 239
		align8(&jzfb->hsw);
paul@223 240
		align8(&jzfb->elw);
paul@223 241
		align8(&jzfb->blw);
paul@96 242
		break;
paul@96 243
	}
paul@96 244
paul@223 245
	lcd_ctrl_set(vid, LCD_VSYNC, jzfb->vsw);
paul@224 246
	lcd_ctrl_set(vid, LCD_HSYNC, ((jzfb->blw + jzfb->w) << 16) | (jzfb->blw + jzfb->w + jzfb->hsw));
paul@96 247
paul@96 248
	/* Screen setting */
paul@223 249
	lcd_ctrl_set(vid, LCD_VAT, ((jzfb->blw + jzfb->w + jzfb->hsw + jzfb->elw) << 16) | (stnH + jzfb->vsw + jzfb->bfw + jzfb->efw));
paul@223 250
	lcd_ctrl_set(vid, LCD_DAH, (jzfb->blw << 16) | (jzfb->blw + jzfb->w));
paul@223 251
	lcd_ctrl_set(vid, LCD_DAV, stnH);
paul@96 252
paul@96 253
	/* AC BIAs signal */
paul@223 254
	lcd_ctrl_set(vid, LCD_PS, stnH+jzfb->vsw+jzfb->efw+jzfb->bfw);
paul@96 255
paul@96 256
	return val;
paul@96 257
}
paul@96 258
paul@221 259
static void jz_lcd_tft_init(vidinfo_t *vid)
paul@96 260
{
paul@221 261
	struct jzfb_info *jzfb = vid->jz_fb;
paul@224 262
paul@223 263
	lcd_ctrl_set(vid, LCD_VSYNC, jzfb->vsw);
paul@223 264
	lcd_ctrl_set(vid, LCD_HSYNC, jzfb->hsw);
paul@224 265
	lcd_ctrl_set(vid, LCD_DAV, ((jzfb->vsw + jzfb->bfw) << 16) | (jzfb->vsw + jzfb->bfw + jzfb->h));
paul@223 266
	lcd_ctrl_set(vid, LCD_DAH, ((jzfb->hsw + jzfb->blw) << 16) | (jzfb->hsw + jzfb->blw + jzfb->w));
paul@223 267
	lcd_ctrl_set(vid, LCD_VAT, (((jzfb->blw + jzfb->w + jzfb->elw + jzfb->hsw)) << 16) |
paul@223 268
		(jzfb->vsw + jzfb->bfw + jzfb->h + jzfb->efw));
paul@96 269
}
paul@96 270
paul@223 271
static void jz_lcd_samsung_init(vidinfo_t *vid)
paul@106 272
{
paul@221 273
	struct jzfb_info *jzfb = vid->jz_fb;
paul@224 274
	uint32_t pclk = lcd_get_pixel_clock(vid);
paul@217 275
	uint32_t total, tp_s, tp_e, ckv_s, ckv_e;
paul@217 276
	uint32_t rev_s, rev_e, inv_s, inv_e;
paul@106 277
paul@221 278
	jz_lcd_tft_init(vid);
paul@106 279
paul@221 280
	total = jzfb->blw + jzfb->w + jzfb->elw + jzfb->hsw;
paul@221 281
	tp_s = jzfb->blw + jzfb->w + 1;
paul@106 282
	tp_e = tp_s + 1;
paul@106 283
	/* ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); */
paul@106 284
	ckv_s = tp_s - pclk/(1000000000/4100);
paul@106 285
	ckv_e = tp_s + total;
paul@106 286
	rev_s = tp_s - 11;	/* -11.5 clk */
paul@106 287
	rev_e = rev_s + total;
paul@106 288
	inv_s = tp_s;
paul@106 289
	inv_e = inv_s + total;
paul@223 290
	lcd_ctrl_set(vid, LCD_CLS, (tp_s << 16) | tp_e);
paul@223 291
	lcd_ctrl_set(vid, LCD_PS, (ckv_s << 16) | ckv_e);
paul@223 292
	lcd_ctrl_set(vid, LCD_SPL, (rev_s << 16) | rev_e);
paul@223 293
	lcd_ctrl_set(vid, LCD_REV, (inv_s << 16) | inv_e);
paul@221 294
	jzfb->cfg |= STFT_REVHI | STFT_SPLHI;
paul@106 295
}
paul@106 296
paul@221 297
static void jz_lcd_sharp_init(vidinfo_t *vid)
paul@106 298
{
paul@221 299
	struct jzfb_info *jzfb = vid->jz_fb;
paul@217 300
	uint32_t total, cls_s, cls_e, ps_s, ps_e;
paul@217 301
	uint32_t spl_s, spl_e, rev_s, rev_e;
paul@106 302
paul@221 303
	jz_lcd_tft_init(vid);
paul@106 304
paul@221 305
	total = jzfb->blw + jzfb->w + jzfb->elw + jzfb->hsw;
paul@106 306
	spl_s = 1;
paul@106 307
	spl_e = spl_s + 1;
paul@106 308
	cls_s = 0;
paul@106 309
	cls_e = total - 60;	/* > 4us (pclk = 80ns) */
paul@106 310
	ps_s = cls_s;
paul@106 311
	ps_e = cls_e;
paul@106 312
	rev_s = total - 40;	/* > 3us (pclk = 80ns) */
paul@106 313
	rev_e = rev_s + total;
paul@221 314
	jzfb->cfg |= STFT_PSHI; 
paul@223 315
	lcd_ctrl_set(vid, LCD_SPL, (spl_s << 16) | spl_e);
paul@223 316
	lcd_ctrl_set(vid, LCD_CLS, (cls_s << 16) | cls_e);
paul@223 317
	lcd_ctrl_set(vid, LCD_PS, (ps_s << 16) | ps_e);
paul@223 318
	lcd_ctrl_set(vid, LCD_REV, (rev_s << 16) | rev_e);
paul@98 319
}
paul@98 320
paul@33 321
paul@96 322
paul@223 323
/* Palette initialisation. */
paul@102 324
paul@217 325
static inline uint16_t rgb8_to_rgb16(uint8_t rgb)
paul@102 326
{
paul@103 327
	return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10);
paul@103 328
}
paul@103 329
paul@217 330
static inline uint16_t rgb4_to_rgb16(uint8_t rgb)
paul@103 331
{
paul@103 332
	return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f);
paul@102 333
}
paul@102 334
paul@102 335
static void lcd_init_palette(vidinfo_t *vid)
paul@102 336
{
paul@223 337
	uint16_t *palette = (uint16_t *) vid->jz_mem.palette;
paul@221 338
	uint16_t *end = (uint16_t *) palette + (1 << (vid->jz_fb->bpp));
paul@217 339
	uint8_t value = 0;
paul@102 340
paul@102 341
	while (palette < end)
paul@102 342
	{
paul@221 343
		switch (vid->jz_fb->bpp)
paul@103 344
		{
paul@221 345
			case 4:
paul@103 346
			*palette = rgb4_to_rgb16(value);
paul@103 347
			break;
paul@103 348
paul@221 349
			case 8:
paul@103 350
			default:
paul@103 351
			*palette = rgb8_to_rgb16(value);
paul@103 352
			break;
paul@103 353
		}
paul@103 354
paul@102 355
		value++;
paul@102 356
		palette++;
paul@102 357
	}
paul@33 358
}
paul@33 359
paul@223 360
paul@223 361
paul@223 362
static void jz_lcd_set_timing(vidinfo_t *vid)
paul@223 363
{
paul@224 364
	uint32_t pclk = lcd_get_pixel_clock(vid);
paul@223 365
	uint32_t val;
paul@223 366
paul@223 367
#ifdef CONFIG_CPU_JZ4730
paul@223 368
        val = __cpm_get_pllout() / pclk;
paul@223 369
        lcd_ctrl_set(vid, CPM_CFCR2, val - 1);
paul@223 370
        val = pclk * 4 ;
paul@223 371
        if ( val > 150000000 ) {
paul@223 372
                val = 150000000;
paul@223 373
        }
paul@223 374
        val = __cpm_get_pllout() / val;
paul@223 375
        val--;
paul@223 376
        if ( val > 0xF )
paul@223 377
                val = 0xF;
paul@223 378
#else
paul@223 379
	int pll_div;
paul@223 380
paul@223 381
	pll_div = lcd_ctrl_get(vid, CPM_CPCCR) & lcd_ctrl_get(vid, CPM_CPCCR_PCS); /* clock source,0:pllout/2 1: pllout */
paul@223 382
	pll_div = pll_div ? 1 : 2 ;
paul@223 383
	val = ( __cpm_get_pllout()/pll_div ) / pclk;
paul@223 384
	val--;
paul@223 385
	if ( val > 0x1ff ) {
paul@223 386
		val = 0x1ff;
paul@223 387
	}
paul@223 388
	__cpm_set_pixdiv(val);
paul@223 389
paul@223 390
	val = pclk * 3 ;	/* LCDClock > 2.5*Pixclock */
paul@223 391
	if ( val > 150000000 ) {
paul@223 392
		val = 150000000;
paul@223 393
	}
paul@223 394
	val = ( __cpm_get_pllout()/pll_div ) / val;
paul@223 395
	val--;
paul@223 396
	if ( val > 0x1f ) {
paul@223 397
		val = 0x1f;
paul@223 398
	}
paul@223 399
#endif
paul@223 400
	__cpm_set_ldiv( val );
paul@223 401
	lcd_ctrl_set(vid, CPM_CPCCR, lcd_ctrl_get(vid, CPM_CPCCR) | CPM_CPCCR_CE); /* update divide */
paul@223 402
}
paul@223 403
paul@224 404
/* Initialise the LCD controller with the memory, panel and framebuffer details.
paul@224 405
   Return the pixel clock frequency. */
paul@224 406
paul@224 407
static void jz_lcd_ctrl_init(void *lcd_base, void *fb_vaddr, vidinfo_t *vid)
paul@224 408
{
paul@224 409
	struct jz_mem_info *fbi = &vid->jz_mem;
paul@224 410
	struct jz_fb_dma_descriptor *descriptors = (struct jz_fb_dma_descriptor *) lcd_get_descriptors(vid);
paul@224 411
paul@224 412
	/* Set the LCD controller address. */
paul@224 413
paul@224 414
	vid->lcd = lcd_base;
paul@224 415
paul@224 416
	/* Position framebuffer regions at the given address. */
paul@224 417
paul@224 418
	fbi->screen = (uint32_t) fb_vaddr;
paul@224 419
paul@224 420
	/* Obtain the palette address. */
paul@224 421
paul@224 422
	fbi->palette = lcd_get_palette(vid);
paul@224 423
paul@224 424
	/* Initialise a palette for lower colour depths. */
paul@224 425
paul@224 426
	if (vid->jz_fb->bpp < 12)
paul@224 427
		lcd_init_palette(vid);
paul@224 428
paul@224 429
	/* Reference the descriptors in memory. */
paul@224 430
paul@224 431
	fbi->dmadesc_fb0 = &descriptors[0];
paul@224 432
	fbi->dmadesc_fb1 = &descriptors[1];
paul@224 433
	fbi->dmadesc_palette = &descriptors[2];
paul@224 434
paul@224 435
	/* Populate descriptors. */
paul@224 436
paul@224 437
	/* Provide the first framebuffer descriptor in single and dual modes. */
paul@224 438
paul@224 439
	fbi->dmadesc_fb0->fsadr = lcd_get_framebuffer(0, vid);
paul@224 440
	fbi->dmadesc_fb0->fidr = 0;
paul@224 441
	fbi->dmadesc_fb0->ldcmd = lcd_get_size(vid) / 4; /* length in words */
paul@224 442
paul@224 443
	/* Provide the second framebuffer descriptor only in dual-panel mode. */
paul@224 444
paul@224 445
	if (lcd_get_panels(vid) == 2)
paul@224 446
	{
paul@224 447
		fbi->dmadesc_fb1->fdadr = fbi->dmadesc_fb1;
paul@224 448
		fbi->dmadesc_fb1->fsadr = lcd_get_framebuffer(1, vid);
paul@224 449
		fbi->dmadesc_fb1->fidr = 0;
paul@224 450
		fbi->dmadesc_fb1->ldcmd = lcd_get_size(vid) / 4;
paul@224 451
paul@224 452
		/* Note the address to be provided for the second channel. */
paul@224 453
paul@224 454
		fbi->fdadr1 = fbi->dmadesc_fb1;
paul@224 455
	}
paul@224 456
paul@224 457
	/* Initialise palette descriptor details if a palette is to be used. */
paul@224 458
paul@224 459
	/* Assume any mode with <12 bpp is palette driven. */
paul@224 460
paul@224 461
	if (vid->jz_fb->bpp < 12)
paul@224 462
	{
paul@224 463
		fbi->dmadesc_palette->fsadr = fbi->palette;
paul@224 464
		fbi->dmadesc_palette->fidr = 0;
paul@224 465
		fbi->dmadesc_palette->ldcmd = (lcd_get_palette_size(vid) / 4) | LCD_CMD_PAL;
paul@224 466
paul@224 467
		/* Flip back and forth between the palette and framebuffer. */
paul@224 468
paul@224 469
		fbi->dmadesc_palette->fdadr = fbi->dmadesc_fb0;
paul@224 470
		fbi->dmadesc_fb0->fdadr = fbi->dmadesc_palette;
paul@224 471
paul@224 472
		/* Provide the palette descriptor address first. */
paul@224 473
paul@224 474
		fbi->fdadr0 = fbi->dmadesc_palette;
paul@224 475
	}
paul@224 476
	else
paul@224 477
	{
paul@224 478
		/* No palette: always use the framebuffer descriptor. */
paul@224 479
paul@224 480
		fbi->dmadesc_fb0->fdadr = fbi->dmadesc_fb0;
paul@224 481
		fbi->fdadr0 = fbi->dmadesc_fb0;
paul@224 482
	}
paul@224 483
}
paul@224 484
paul@224 485
/* Initialise the LCD registers. */
paul@224 486
paul@223 487
static void jz_lcd_hw_init(vidinfo_t *vid)
paul@223 488
{
paul@223 489
	struct jzfb_info *jzfb = vid->jz_fb;
paul@223 490
	uint32_t val = 0;
paul@223 491
paul@223 492
	/* Compute control register flags. */
paul@223 493
paul@223 494
	switch (jzfb->bpp) {
paul@223 495
		case 1:
paul@223 496
		val |= LCD_CTRL_BPP_1;
paul@223 497
		break;
paul@223 498
paul@223 499
		case 2:
paul@223 500
		val |= LCD_CTRL_BPP_2;
paul@223 501
		break;
paul@223 502
paul@223 503
		case 4:
paul@223 504
		val |= LCD_CTRL_BPP_4;
paul@223 505
		break;
paul@223 506
paul@223 507
		case 8:
paul@223 508
		val |= LCD_CTRL_BPP_8;
paul@223 509
		break;
paul@223 510
paul@223 511
		case 15:
paul@223 512
		val |= LCD_CTRL_RGB555;
paul@223 513
		case 16:
paul@223 514
		val |= LCD_CTRL_BPP_16;
paul@223 515
		break;
paul@223 516
paul@223 517
		case 17 ... 32:
paul@223 518
		val |= LCD_CTRL_BPP_18_24;	/* target is 4bytes/pixel */
paul@223 519
		break;
paul@223 520
paul@223 521
		default:
paul@223 522
		val |= LCD_CTRL_BPP_16;		/* default to 16bpp */
paul@223 523
		break;
paul@223 524
	}
paul@223 525
paul@223 526
	/* Set various configuration registers for the panel. */
paul@223 527
paul@223 528
	switch (jzfb->cfg & MODE_MASK) {
paul@223 529
		case MODE_STN_MONO_DUAL:
paul@223 530
		case MODE_STN_COLOR_DUAL:
paul@223 531
		val |= jz_lcd_stn_init(jzfb->h >> 1, vid);
paul@223 532
		break;
paul@223 533
paul@223 534
		case MODE_STN_MONO_SINGLE:
paul@223 535
		case MODE_STN_COLOR_SINGLE:
paul@223 536
		val |= jz_lcd_stn_init(jzfb->h, vid);
paul@223 537
		break;
paul@223 538
paul@223 539
		case MODE_TFT_GEN:
paul@223 540
		case MODE_TFT_CASIO:
paul@223 541
		case MODE_8BIT_SERIAL_TFT:
paul@223 542
		case MODE_TFT_18BIT:
paul@223 543
		jz_lcd_tft_init(vid);
paul@223 544
		break;
paul@223 545
paul@223 546
		case MODE_TFT_SAMSUNG:
paul@223 547
		jz_lcd_samsung_init(vid);
paul@223 548
		break;
paul@223 549
paul@223 550
		case MODE_TFT_SHARP:
paul@223 551
		jz_lcd_sharp_init(vid);
paul@223 552
		break;
paul@223 553
paul@223 554
		default:
paul@223 555
		break;
paul@223 556
	}
paul@223 557
paul@224 558
	/* Further control register and panel configuration. */
paul@223 559
paul@223 560
	val |= LCD_CTRL_BST_16;		/* Burst Length is 16WORD=64Byte */
paul@223 561
	val |= LCD_CTRL_OFUP;		/* OutFIFO underrun protect */
paul@223 562
paul@223 563
	lcd_ctrl_set(vid, LCD_CTRL, val);
paul@223 564
	lcd_ctrl_set(vid, LCD_CFG, jzfb->cfg);
paul@223 565
}
paul@223 566
paul@223 567
static void jz_lcd_timing_init(vidinfo_t *vid)
paul@223 568
{
paul@223 569
	__cpm_stop_lcd();
paul@223 570
	jz_lcd_set_timing(vid);
paul@223 571
	__cpm_start_lcd();
paul@223 572
	udelay(1000);
paul@223 573
}
paul@223 574
paul@223 575
/* Initialise DMA for the driver. */
paul@223 576
paul@223 577
static void jz_lcd_dma_init(vidinfo_t *vid)
paul@223 578
{
paul@224 579
	struct jz_mem_info *fbi = &vid->jz_mem;
paul@224 580
	uint32_t mode = vid->jz_fb->cfg & MODE_MASK;
paul@223 581
paul@224 582
	/* Configure DMA by setting frame descriptor addresses. */
paul@223 583
paul@223 584
	lcd_ctrl_set(vid, LCD_DA0, (uint32_t) fbi->fdadr0);
paul@223 585
paul@223 586
	if ((mode == MODE_STN_COLOR_DUAL) || (mode == MODE_STN_MONO_DUAL))
paul@223 587
		lcd_ctrl_set(vid, LCD_DA1, (uint32_t) fbi->fdadr1);
paul@223 588
}
paul@223 589
paul@224 590
/* Set the colour depth. */
paul@223 591
paul@223 592
void lcd_set_bpp(uint8_t bpp)
paul@223 593
{
paul@223 594
	vidinfo_t *vid = &panel_info;
paul@224 595
	vid->jz_fb->bpp = bpp;
paul@223 596
}
paul@223 597
paul@223 598
void lcd_enable()
paul@223 599
{
paul@223 600
	vidinfo_t *vid = &panel_info;
paul@223 601
paul@223 602
	/* Clear the disable bit (DIS) and set the enable bit (ENA). */
paul@223 603
paul@223 604
	lcd_ctrl_set(vid, LCD_CTRL, (lcd_ctrl_get(vid, LCD_CTRL) & ~LCD_CTRL_DIS) | LCD_CTRL_ENA);
paul@223 605
}
paul@223 606
paul@223 607
void lcd_disable()
paul@223 608
{
paul@223 609
	vidinfo_t *vid = &panel_info;
paul@223 610
paul@223 611
	/* Set the disable bit (DIS). */
paul@223 612
paul@223 613
	lcd_ctrl_set(vid, LCD_CTRL, lcd_ctrl_get(vid, LCD_CTRL) | LCD_CTRL_DIS);
paul@223 614
}
paul@223 615
paul@223 616
void lcd_quick_disable()
paul@223 617
{
paul@223 618
	vidinfo_t *vid = &panel_info;
paul@223 619
paul@223 620
	/* Clear the enable bit (ENA) for quick disable. */
paul@223 621
paul@223 622
	lcd_ctrl_set(vid, LCD_CTRL, lcd_ctrl_get(vid, LCD_CTRL) & ~LCD_CTRL_ENA);
paul@223 623
}
paul@223 624
paul@217 625
uint32_t lcd_ctrl_init()
paul@33 626
{
paul@221 627
	vidinfo_t *vid = &panel_info;
paul@221 628
	struct jz_mem_info *fbi = &vid->jz_mem;
paul@224 629
	void *fb_vaddr;
paul@101 630
paul@224 631
	/* Start from the top of memory and obtain the framebuffer region. */
paul@101 632
paul@224 633
	fb_vaddr = (void *) lcd_get_framebuffer(0, vid);
paul@101 634
paul@224 635
	jz_lcd_ctrl_init(0, fb_vaddr, vid);
paul@224 636
	flush_cache_all();
paul@221 637
	jz_lcd_hw_init(vid);
paul@223 638
	jz_lcd_timing_init(vid);
paul@223 639
	jz_lcd_dma_init(vid);
paul@101 640
paul@101 641
	return fbi->screen;
paul@33 642
}