Landfall

Annotated pkg/landfall-examples/qi_lb60_lcd/jzlcd.c

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