/*
 * linux/drivers/video/psionwfb.h
 */

#define CMAP_SIZE	16

static struct psionwfb_info {
	struct fb_info fb;
	int currcon;
} *cfb;

void psionw_lcd_disable(void);
void psionw_lcd_enable(void);
void psionw_lcd_init_hw(void);

#ifdef DEBUG
extern void serial_printf(char *fmt, ...);
#endif

struct display_switch fbcon_mfb_psionw;
struct display_switch fbcon_cfb2_psionw;
struct display_switch fbcon_cfb4_psionw;

/* 1bpp functions */
extern void fbcon_mfb_setup(struct display *p);
extern void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
			    int height, int width);
void fbcon_mfb_clear_psionw(struct vc_data *conp, struct display *p,
			    int sy, int sx, int height, int width);
void fbcon_mfb_putc_psionw(struct vc_data *conp, struct display *p,
			   int c, int yy, int xx);
void fbcon_mfb_putcs_psionw(struct vc_data *conp, struct display *p,
			    const unsigned short *s, int count, int yy, int xx);
extern void fbcon_mfb_revc(struct display *p, int xx, int yy);
extern void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
				    int bottom_only);

/* 2bpp functions */
extern void fbcon_cfb2_setup(struct display *p);
extern void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
			     int height, int width);
void fbcon_cfb2_clear_psionw(struct vc_data *conp, struct display *p,
			     int sy, int sx, int height, int width);
void fbcon_cfb2_putc_psionw(struct vc_data *conp, struct display *p,
			    int c, int yy, int xx);
void fbcon_cfb2_putcs_psionw(struct vc_data *conp, struct display *p,
			     const unsigned short *s, int count, int yy,
			     int xx);
extern void fbcon_cfb2_revc(struct display *p, int xx, int yy);

/* 4bpp functions */
extern void fbcon_cfb4_setup(struct display *p);
extern void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
			     int height, int width);
void fbcon_cfb4_clear_psionw(struct vc_data *conp, struct display *p, int sy,
			     int sx, int height, int width);
void fbcon_cfb4_putc_psionw(struct vc_data *conp, struct display *p, int c,
			    int yy, int xx);
void fbcon_cfb4_putcs_psionw(struct vc_data *conp, struct display *p,
			     const unsigned short *s, int count, int yy,
			     int xx);
extern void fbcon_cfb4_revc(struct display *p, int xx, int yy);

static u_char nibbletab_cfb2_psionw[] = {
#if defined(__BIG_ENDIAN)
	0x00, 0x03, 0x0c, 0x0f,
	0x30, 0x33, 0x3c, 0x3f,
	0xc0, 0xc3, 0xcc, 0xcf,
	0xf0, 0xf3, 0xfc, 0xff
#elif defined(__LITTLE_ENDIAN)
	0x00, 0xc0, 0x30, 0xf0,
	0x0c, 0xcc, 0x3c, 0xfc,
	0x03, 0xc3, 0x33, 0xf3,
	0x0f, 0xcf, 0x3f, 0xff
#else
#error FIXME: No endianness??
#endif
};

static u16 nibbletab_cfb4_psionw[] = {

#if defined(__BIG_ENDIAN)
	0x0000, 0x000f, 0x00f0, 0x00ff,
	0x0f00, 0x0f0f, 0x0ff0, 0x0fff,
	0xf000, 0xf00f, 0xf0f0, 0xf0ff,
	0xff00, 0xff0f, 0xfff0, 0xffff
#elif defined(__LITTLE_ENDIAN)
	0x0000, 0xf000, 0x0f00, 0xff00,
	0x00f0, 0xf0f0, 0x0ff0, 0xfff0,
	0x000f, 0xf00f, 0x0f0f, 0xff0f,
	0x00ff, 0xf0ff, 0x0fff, 0xffff
#else
#error FIXME: No endianness??
#endif
};

static inline unsigned
bi_reverse(unsigned code, int len)
{
	register unsigned res = 0;
	do {
		res |= code & 1;
		code >>= 1, res <<= 1;
	} while (--len > 0);
	return res >> 1;
}

#ifdef DEBUG
/*
 * Dumps the color palette to serial terminal
 */
void
dump_pal()
{
	int i, val, phys;
	serial_printf("*** Dumping color palette ***\n");
	for (i = 0; i < LCDPAL; i += 4) {
		val = *(volatile unsigned int *) (LCD_PAL_START + i);
		if (i == 0) {
			switch ((val >> 12) & 0x7) {
			case 0:
				serial_printf("Mode: 1bpp\n");
				break;
			case 1:
				serial_printf("Mode: 2bpp\n");
				break;
			case 2:
				serial_printf("Mode: 4bpp\n");
				break;
			case 3:
				serial_printf("Mode: 8bpp\n");
				break;
			default:
				serial_printf("Mode: Unknown\n");
			}
		}
		serial_printf("0x%04x  ", val & 0xffff);
		serial_printf("0x%04x  ", (val >> 16));
		if ((i & 0x7) == 0x4) {
			serial_printf("\n");
		}
	}
	serial_printf("\n");
}
#endif
