mirror of
https://github.com/gwenhael-le-moine/x49gp.git
synced 2024-12-25 21:58:49 +01:00
416 lines
9.6 KiB
C
416 lines
9.6 KiB
C
/* $Id: s3c2410_lcd.c,v 1.4 2008/12/11 12:18:17 ecd Exp $
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <errno.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <x49gp.h>
|
|
#include <x49gp_ui.h>
|
|
#include <s3c2410.h>
|
|
|
|
|
|
typedef struct {
|
|
uint32_t lcdcon1;
|
|
uint32_t lcdcon2;
|
|
uint32_t lcdcon3;
|
|
uint32_t lcdcon4;
|
|
uint32_t lcdcon5;
|
|
uint32_t lcdsaddr1;
|
|
uint32_t lcdsaddr2;
|
|
uint32_t lcdsaddr3;
|
|
uint32_t redlut;
|
|
uint32_t greenlut;
|
|
uint32_t bluelut;
|
|
uint32_t dithmode;
|
|
uint32_t tpal;
|
|
uint32_t lcdintpnd;
|
|
uint32_t lcdsrcpnd;
|
|
uint32_t lcdintmsk;
|
|
uint32_t lpcsel;
|
|
uint32_t __unknown_68;
|
|
|
|
unsigned int nr_regs;
|
|
s3c2410_offset_t *regs;
|
|
|
|
x49gp_t *x49gp;
|
|
} s3c2410_lcd_t;
|
|
|
|
static int
|
|
s3c2410_lcd_data_init(s3c2410_lcd_t *lcd)
|
|
{
|
|
s3c2410_offset_t regs[] = {
|
|
S3C2410_OFFSET(LCD, LCDCON1, 0x00000000, lcd->lcdcon1),
|
|
S3C2410_OFFSET(LCD, LCDCON2, 0x00000000, lcd->lcdcon2),
|
|
S3C2410_OFFSET(LCD, LCDCON3, 0x00000000, lcd->lcdcon3),
|
|
S3C2410_OFFSET(LCD, LCDCON4, 0x00000000, lcd->lcdcon4),
|
|
S3C2410_OFFSET(LCD, LCDCON5, 0x00000000, lcd->lcdcon5),
|
|
S3C2410_OFFSET(LCD, LCDSADDR1, 0x00000000, lcd->lcdsaddr1),
|
|
S3C2410_OFFSET(LCD, LCDSADDR2, 0x00000000, lcd->lcdsaddr2),
|
|
S3C2410_OFFSET(LCD, LCDSADDR3, 0x00000000, lcd->lcdsaddr3),
|
|
S3C2410_OFFSET(LCD, REDLUT, 0x00000000, lcd->redlut),
|
|
S3C2410_OFFSET(LCD, GREENLUT, 0x00000000, lcd->greenlut),
|
|
S3C2410_OFFSET(LCD, BLUELUT, 0x00000000, lcd->bluelut),
|
|
S3C2410_OFFSET(LCD, DITHMODE, 0x00000000, lcd->dithmode),
|
|
S3C2410_OFFSET(LCD, TPAL, 0x00000000, lcd->tpal),
|
|
S3C2410_OFFSET(LCD, LCDINTPND, 0x00000000, lcd->lcdintpnd),
|
|
S3C2410_OFFSET(LCD, LCDSRCPND, 0x00000000, lcd->lcdsrcpnd),
|
|
S3C2410_OFFSET(LCD, LCDINTMSK, 0x00000003, lcd->lcdintmsk),
|
|
S3C2410_OFFSET(LCD, LPCSEL, 0x00000004, lcd->lpcsel),
|
|
S3C2410_OFFSET(LCD, UNKNOWN_68, 0x00000000, lcd->__unknown_68)
|
|
};
|
|
|
|
memset(lcd, 0, sizeof(s3c2410_lcd_t));
|
|
|
|
lcd->regs = malloc(sizeof(regs));
|
|
if (NULL == lcd->regs) {
|
|
fprintf(stderr, "%s:%u: Out of memory\n",
|
|
__FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(lcd->regs, regs, sizeof(regs));
|
|
lcd->nr_regs = sizeof(regs) / sizeof(regs[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
x49gp_schedule_lcd_update(x49gp_t *x49gp)
|
|
{
|
|
if (! x49gp_timer_pending(x49gp->lcd_timer)) {
|
|
x49gp_mod_timer(x49gp->lcd_timer,
|
|
x49gp_get_clock() + X49GP_LCD_REFRESH_INTERVAL);
|
|
}
|
|
}
|
|
|
|
static int
|
|
x49gp_get_pixel_color(s3c2410_lcd_t *lcd, int x, int y)
|
|
{
|
|
uint32_t bank, addr, data, offset, pixel_offset;
|
|
int bits_per_pixel = lcd->lcdcon5 > 2 ? 1 : 4 >> lcd->lcdcon5;
|
|
|
|
bank = (lcd->lcdsaddr1 << 1) & 0x7fc00000;
|
|
addr = bank | ((lcd->lcdsaddr1 << 1) & 0x003ffffe);
|
|
|
|
pixel_offset = (160 * y + x) * bits_per_pixel;
|
|
offset = (pixel_offset >> 3) & 0xfffffffc;
|
|
|
|
data = ldl_phys(addr + offset);
|
|
data >>= pixel_offset & 31;
|
|
data &= (1 << bits_per_pixel) - 1;
|
|
|
|
switch (bits_per_pixel) {
|
|
case 1:
|
|
return 15 * data;
|
|
case 2:
|
|
return 15 & (lcd->bluelut >> (4 * data));
|
|
default:
|
|
return data;
|
|
}
|
|
}
|
|
|
|
void
|
|
x49gp_lcd_update(x49gp_t *x49gp)
|
|
{
|
|
x49gp_ui_t *ui = x49gp->ui;
|
|
s3c2410_lcd_t *lcd = x49gp->s3c2410_lcd;
|
|
GdkRectangle rect;
|
|
GdkGC *gc;
|
|
int color, x, y;
|
|
|
|
if (!(lcd->lcdcon1 & 1)) {
|
|
gdk_draw_drawable(ui->lcd_pixmap, ui->window->style->bg_gc[0],
|
|
ui->bg_pixmap,
|
|
ui->lcd_x_offset, ui->lcd_y_offset,
|
|
0, 0, ui->lcd_width, ui->lcd_height);
|
|
goto done;
|
|
}
|
|
|
|
gdk_draw_drawable(ui->lcd_pixmap, ui->window->style->bg_gc[0],
|
|
ui->bg_pixmap,
|
|
ui->lcd_x_offset, ui->lcd_y_offset,
|
|
0, 0, ui->lcd_width, ui->lcd_height);
|
|
|
|
color = x49gp_get_pixel_color(lcd, 131, 0);
|
|
gdk_gc_set_rgb_fg_color(ui->ann_io_gc, &(ui->colors[UI_COLOR_GRAYSCALE_0 + color]));
|
|
gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_io_gc, TRUE, 236, 0, 15, 12);
|
|
|
|
color = x49gp_get_pixel_color(lcd, 131, 1);
|
|
gdk_gc_set_rgb_fg_color(ui->ann_left_gc, &(ui->colors[UI_COLOR_GRAYSCALE_0 + color]));
|
|
gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_left_gc, TRUE, 11, 0, 15, 12);
|
|
|
|
color = x49gp_get_pixel_color(lcd, 131, 2);
|
|
gdk_gc_set_rgb_fg_color(ui->ann_right_gc, &(ui->colors[UI_COLOR_GRAYSCALE_0 + color]));
|
|
gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_right_gc, TRUE, 56, 0, 15, 12);
|
|
|
|
color = x49gp_get_pixel_color(lcd, 131, 3);
|
|
gdk_gc_set_rgb_fg_color(ui->ann_alpha_gc, &(ui->colors[UI_COLOR_GRAYSCALE_0 + color]));
|
|
gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_alpha_gc, TRUE, 101, 0, 15, 12);
|
|
|
|
color = x49gp_get_pixel_color(lcd, 131, 4);
|
|
gdk_gc_set_rgb_fg_color(ui->ann_battery_gc, &(ui->colors[UI_COLOR_GRAYSCALE_0 + color]));
|
|
gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_battery_gc, TRUE, 146, 0, 15, 12);
|
|
|
|
color = x49gp_get_pixel_color(lcd, 131, 5);
|
|
gdk_gc_set_rgb_fg_color(ui->ann_busy_gc, &(ui->colors[UI_COLOR_GRAYSCALE_0 + color]));
|
|
gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_busy_gc, TRUE, 191, 0, 15, 12);
|
|
|
|
gc = gdk_gc_new(ui->lcd_canvas->window);
|
|
|
|
for (y = 0; y < (ui->lcd_height - ui->lcd_top_margin) / 2; y++) {
|
|
for (x = 0; x < ui->lcd_width / 2; x++) {
|
|
color = x49gp_get_pixel_color(lcd, x, y);
|
|
gdk_gc_set_rgb_fg_color(gc, &(ui->colors[UI_COLOR_GRAYSCALE_0 + color]));
|
|
gdk_draw_rectangle(ui->lcd_pixmap, gc, TRUE,
|
|
2 * x, 2 * y + ui->lcd_top_margin, 2, 2);
|
|
}
|
|
}
|
|
|
|
g_object_unref(gc);
|
|
|
|
done:
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
rect.width = ui->lcd_width;
|
|
rect.height = ui->lcd_height;
|
|
|
|
gdk_window_invalidate_rect(ui->lcd_canvas->window, &rect, FALSE);
|
|
}
|
|
|
|
|
|
static uint32_t
|
|
s3c2410_lcd_read(void *opaque, target_phys_addr_t offset)
|
|
{
|
|
s3c2410_lcd_t *lcd = opaque;
|
|
s3c2410_offset_t *reg;
|
|
uint32_t linecnt;
|
|
|
|
if (! S3C2410_OFFSET_OK(lcd, offset)) {
|
|
return ~(0);
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(lcd, offset);
|
|
|
|
switch (offset) {
|
|
case S3C2410_LCD_LCDCON1:
|
|
linecnt = (lcd->lcdcon1 >> 18) & 0x3ff;
|
|
if (linecnt > 0) {
|
|
linecnt--;
|
|
} else {
|
|
linecnt = (lcd->lcdcon2 >> 14) & 0x3ff;
|
|
}
|
|
|
|
lcd->lcdcon1 &= ~(0x3ff << 18);
|
|
lcd->lcdcon1 |= (linecnt << 18);
|
|
}
|
|
|
|
#ifdef DEBUG_S3C2410_LCD
|
|
printf("read %s [%08x] %s [%08lx] data %08x\n",
|
|
"s3c2410-lcd", S3C2410_LCD_BASE,
|
|
reg->name, (unsigned long) offset, *(reg->datap));
|
|
#endif
|
|
|
|
return *(reg->datap);
|
|
}
|
|
|
|
static void
|
|
s3c2410_lcd_write(void *opaque, target_phys_addr_t offset, uint32_t data)
|
|
{
|
|
s3c2410_lcd_t *lcd = opaque;
|
|
x49gp_t *x49gp = lcd->x49gp;
|
|
s3c2410_offset_t *reg;
|
|
|
|
if (! S3C2410_OFFSET_OK(lcd, offset)) {
|
|
return;
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(lcd, offset);
|
|
|
|
#ifdef DEBUG_S3C2410_LCD
|
|
printf("write %s [%08x] %s [%08lx] data %08x\n",
|
|
"s3c2410-lcd", S3C2410_LCD_BASE,
|
|
reg->name, (unsigned long) offset, data);
|
|
#endif
|
|
|
|
switch (offset) {
|
|
case S3C2410_LCD_LCDCON1:
|
|
if ((lcd->lcdcon1 ^ data) & 1) {
|
|
x49gp_schedule_lcd_update(x49gp);
|
|
}
|
|
|
|
lcd->lcdcon1 = (lcd->lcdcon1 & (0x3ff << 18)) |
|
|
(data & ~(0x3ff << 18));
|
|
break;
|
|
default:
|
|
*(reg->datap) = data;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
s3c2410_lcd_load(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
s3c2410_lcd_t *lcd = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int error = 0;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < lcd->nr_regs; i++) {
|
|
reg = &lcd->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
if (x49gp_module_get_u32(module, key, reg->name,
|
|
reg->reset, reg->datap))
|
|
error = -EAGAIN;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static int
|
|
s3c2410_lcd_save(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
s3c2410_lcd_t *lcd = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < lcd->nr_regs; i++) {
|
|
reg = &lcd->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
x49gp_module_set_u32(module, key, reg->name, *(reg->datap));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_lcd_reset(x49gp_module_t *module, x49gp_reset_t reset)
|
|
{
|
|
s3c2410_lcd_t *lcd = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < lcd->nr_regs; i++) {
|
|
reg = &lcd->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
*(reg->datap) = reg->reset;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static CPUReadMemoryFunc *s3c2410_lcd_readfn[] =
|
|
{
|
|
s3c2410_lcd_read,
|
|
s3c2410_lcd_read,
|
|
s3c2410_lcd_read
|
|
};
|
|
|
|
static CPUWriteMemoryFunc *s3c2410_lcd_writefn[] =
|
|
{
|
|
s3c2410_lcd_write,
|
|
s3c2410_lcd_write,
|
|
s3c2410_lcd_write
|
|
};
|
|
|
|
static int
|
|
s3c2410_lcd_init(x49gp_module_t *module)
|
|
{
|
|
s3c2410_lcd_t *lcd;
|
|
int iotype;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
lcd = malloc(sizeof(s3c2410_lcd_t));
|
|
if (NULL == lcd) {
|
|
fprintf(stderr, "%s:%u: Out of memory\n",
|
|
__FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
if (s3c2410_lcd_data_init(lcd)) {
|
|
free(lcd);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
module->user_data = lcd;
|
|
module->x49gp->s3c2410_lcd = lcd;
|
|
lcd->x49gp = module->x49gp;
|
|
|
|
iotype = cpu_register_io_memory(s3c2410_lcd_readfn,
|
|
s3c2410_lcd_writefn, lcd);
|
|
#ifdef DEBUG_S3C2410_LCD
|
|
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
|
|
#endif
|
|
cpu_register_physical_memory(S3C2410_LCD_BASE, S3C2410_MAP_SIZE, iotype);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_lcd_exit(x49gp_module_t *module)
|
|
{
|
|
s3c2410_lcd_t *lcd;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
if (module->user_data) {
|
|
lcd = module->user_data;
|
|
if (lcd->regs)
|
|
free(lcd->regs);
|
|
free(lcd);
|
|
}
|
|
|
|
x49gp_module_unregister(module);
|
|
free(module);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
x49gp_s3c2410_lcd_init(x49gp_t *x49gp)
|
|
{
|
|
x49gp_module_t *module;
|
|
|
|
if (x49gp_module_init(x49gp, "s3c2410-lcd",
|
|
s3c2410_lcd_init,
|
|
s3c2410_lcd_exit,
|
|
s3c2410_lcd_reset,
|
|
s3c2410_lcd_load,
|
|
s3c2410_lcd_save,
|
|
NULL, &module)) {
|
|
return -1;
|
|
}
|
|
|
|
return x49gp_module_register(module);
|
|
}
|