diff target-utils/pirexplore/lcd.c @ 0:e7502631a0f9

initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 11 Jun 2016 00:13:35 +0000
parents
children 87cb03b35f77
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/pirexplore/lcd.c	Sat Jun 11 00:13:35 2016 +0000
@@ -0,0 +1,276 @@
+/*
+ * Almost all of this Pirelli LCD black magic has been lifted from OsmocomBB.
+ */
+
+#include <sys/types.h>
+#include "types.h"
+
+#define	GPIO_OUT_REG	(*(volatile u16 *)0xFFFE4802)
+#define	nCS4_ADDR0	(*(volatile u16 *)0x02800000)
+#define	nCS4_ADDR2	(*(volatile u16 *)0x02800002)
+
+fb_spca_write(addr, data)
+{
+	GPIO_OUT_REG &= 0xFF7F;
+	nCS4_ADDR0 = addr;
+	nCS4_ADDR2 = data;
+}
+
+void
+cmd_spca(argbulk)
+	char *argbulk;
+{
+	char *argv[3];
+	u_long addr, data;
+
+	if (parse_args(argbulk, 2, 2, argv, 0) < 0)
+		return;
+	if (parse_hexarg(argv[0], 4, &addr) < 0) {
+		printf("ERROR: arg1 must be a valid 16-bit hex value\n");
+		return;
+	}
+	if (parse_hexarg(argv[1], 4, &data) < 0) {
+		printf("ERROR: arg2 must be a valid 16-bit hex value\n");
+		return;
+	}
+	fb_spca_write(addr, data);
+}
+
+void
+cmd_spcainit()
+{
+	/*
+	 * Apparently we have to give it a reset pulse, then immediately
+	 * do the black magic register write sequence.
+	 */
+	GPIO_OUT_REG = 0x0000;
+	GPIO_OUT_REG = 0x0012;
+	/* non-understandable voodoo copied from OsmocomBB */
+	fb_spca_write(0x7e, 0x00);	/* internal register access */
+	osmo_delay_ms(10);
+	fb_spca_write(0x7a, 0x00);	/* keep CPU in reset state */
+	osmo_delay_ms(10);
+	fb_spca_write(0x7f, 0x00);	/* select main page */
+	osmo_delay_ms(5);
+	fb_spca_write(0x72, 0x07);	/* don't reshape timing, 16 bit mode */
+	fb_spca_write(0x14, 0x03);
+	fb_spca_write(0x7f, 0x00);	/* select main page */
+	osmo_delay_ms(5);
+	fb_spca_write(0x06, 0xff);
+	fb_spca_write(0x7f, 0x09);
+	fb_spca_write(0x19, 0x08);	/* backlight: 0x08 is on, 0x0c is off */
+	fb_spca_write(0x23, 0x18);
+}
+
+enum s6b33b1x_cmdflag { CMD, DATA, END };
+
+struct s6b33b1x_cmdlist {
+	enum s6b33b1x_cmdflag is_cmd:8;	/* 1: is a command, 0: is data, 2: end marker! */
+	u_char data;			/* 8 bit to send to LC display */
+};
+
+static const struct s6b33b1x_cmdlist
+s6b33b1x_initdata[] = {
+	{ CMD,  0x26 }, /* CMD   DCDC and AMP ON/OFF set */
+	{ DATA, 0x00 }, /* DATA: everything off */
+	{ CMD,  0x02 }, /* CMD   Oscillation Mode Set */
+	{ DATA, 0x00 }, /* DATA: oscillator off */
+	{ CMD,  0x2c }, /* CMD   Standby Mode off */
+	{ CMD,  0x50 }, /* CMD   Display off */
+	{ CMD,  0x02 }, /* CMD   Oscillation Mode Set */
+	{ DATA, 0x01 }, /* DATA: oscillator on */
+	{ CMD,  0x26 }, /* CMD   DCDC and AMP ON/OFF set */
+	{ DATA, 0x01 }, /* DATA: Booster 1 on */
+	{ CMD,  0x26 }, /* CMD   DCDC and AMP ON/OFF set */
+	{ DATA, 0x09 }, /* DATA: Booster 1 on, OP-AMP on */
+	{ CMD,  0x26 }, /* CMD   DCDC and AMP ON/OFF set */
+	{ DATA, 0x0b }, /* DATA: Booster 1 + 2 on, OP-AMP on */
+	{ CMD,  0x26 }, /* CMD   DCDC and AMP ON/OFF set */
+	{ DATA, 0x0f }, /* DATA: Booster 1 + 2 + 3 on, OP-AMP on */
+	{ CMD,  0x20 }, /* CMD   DC-DC Select */
+	{ DATA, 0x01 }, /* DATA: step up x1.5 */
+	{ CMD,  0x24 }, /* CMD   DCDC Clock Division Set */
+	{ DATA, 0x0a }, /* DATA: fPCK = fOSC/6 */
+	{ CMD,  0x2a }, /* CMD   Contrast Control */
+	{ DATA, 0x2d }, /* DATA: default contrast */
+	{ CMD,  0x30 }, /* CMD   Adressing mode set */
+	{ DATA, 0x0b }, /* DATA: 65536 color mode */
+	{ CMD,  0x10 }, /* CMD   Driver output mode set */
+	{ DATA, 0x03 }, /* DATA: Display duty: 1/132 */
+	{ CMD,  0x34 }, /* CMD   N-line inversion set */
+	{ DATA, 0x88 }, /* DATA: inversion on, one frame, every 8 blocks */
+	{ CMD,  0x40 }, /* CMD   Entry mode set */
+	{ DATA, 0x00 }, /* DATA: Y address counter mode */
+	{ CMD,  0x28 }, /* CMD   Temperature Compensation set */
+	{ DATA, 0x01 }, /* DATA: slope -0.05%/degC */
+	{ CMD,  0x32 }, /* CMD   ROW vector mode set */
+	{ DATA, 0x01 }, /* DATA: every 2 subgroup */
+	{ CMD,  0x51 }, /* CMD   Display on */
+	{ END,  0x00 }, /* MARKER: end of list */
+};
+
+static void
+fb_s6b33b1x_send_cmdlist(p)
+	struct s6b33b1x_cmdlist *p;
+{
+	while(p->is_cmd != END) {
+		nCS4_ADDR0 = p->data;
+		p++;
+	}
+}
+
+void
+cmd_lcdinit()
+{
+	GPIO_OUT_REG |= 0x0080;
+	fb_s6b33b1x_send_cmdlist(s6b33b1x_initdata);
+}
+
+set_lcd_addr_region(xstart, xend, ystart, yend)
+{
+	GPIO_OUT_REG |= 0x0080;
+	nCS4_ADDR0 = 0x42;
+	nCS4_ADDR0 = ystart + 4;
+	nCS4_ADDR0 = yend + 4;
+	nCS4_ADDR0 = 0x43;
+	nCS4_ADDR0 = xstart;
+	nCS4_ADDR0 = xend;
+}
+
+void
+cmd_lcdfill(argbulk)
+	char *argbulk;
+{
+	int argc;
+	char *argv[6];
+	u_long pixval;
+	int xstart, xend, ystart, yend;
+	int npix;
+
+	if (parse_args(argbulk, 1, 5, argv, &argc) < 0)
+		return;
+	if (parse_hexarg(argv[0], 4, &pixval) < 0) {
+		printf("ERROR: arg1 must be a valid 16-bit hex value\n");
+		return;
+	}
+	switch (argc) {
+	case 1:
+		xstart = ystart = 0;
+		xend = yend = 127;
+		break;
+	case 5:
+		xstart = atoi(argv[1]);
+		if (xstart < 0 || xstart > 127) {
+range_err:		printf("ERROR: coordinate arg out of range\n");
+			return;
+		}
+		xend = atoi(argv[2]);
+		if (xend < 0 || xend > 127)
+			goto range_err;
+		ystart = atoi(argv[3]);
+		if (ystart < 0 || ystart > 127)
+			goto range_err;
+		yend = atoi(argv[4]);
+		if (yend < 0 || yend > 127)
+			goto range_err;
+		if (xend < xstart || yend < ystart) {
+			printf("ERROR: negative range\n");
+			return;
+		}
+		break;
+	default:
+		printf("ERROR: wrong number of arguments\n");
+		return;
+	}
+	set_lcd_addr_region(xstart, xend, ystart, yend);
+	npix = (xend + 1 - xstart) * (yend + 1 - ystart);
+	while (npix--)
+		nCS4_ADDR2 = pixval;
+}
+
+void
+cmd_lcdtest()
+{
+	int i, j, k, p;
+
+	/*
+	 * The result of this command should be 8 vertical bars
+	 * in the natural RGB order.
+	 */
+	set_lcd_addr_region(10, 89, 10, 89);
+	for (i = 0; i < 80; i++) {
+		for (j = 0; j < 8; j++) {
+			p = 0;
+			if (j & 4)
+				p |= 0xF800;
+			if (j & 2)
+				p |= 0x07E0;
+			if (j & 1)
+				p |= 0x001F;
+			for (k = 0; k < 10; k++)
+				nCS4_ADDR2 = p;
+		}
+	}
+}
+
+void
+cmd_blit(argbulk)
+	char *argbulk;
+{
+	int argc;
+	char *argv[6];
+	u16 imgbuf[16384];
+	size_t img_file_size;
+	int xstart, ystart, width, height;
+	int npix, i;
+
+	if (parse_args(argbulk, 1, 5, argv, &argc) < 0)
+		return;
+	if (mpffs_read_into_ram(argv[0], imgbuf, 32768, &img_file_size) < 0)
+		return;
+	switch (argc) {
+	case 1:
+		xstart = ystart = 0;
+		width = height = 128;
+		break;
+	case 3:
+		xstart = ystart = 0;
+		goto widthheight;
+	case 5:
+		xstart = atoi(argv[3]);
+		if (xstart < 0 || xstart > 127) {
+range_err:		printf("ERROR: coordinate arg out of range\n");
+			return;
+		}
+		ystart = atoi(argv[4]);
+		if (ystart < 0 || ystart > 127)
+			goto range_err;
+		/* FALL THRU */
+	widthheight:
+		width = atoi(argv[1]);
+		if (width < 1 || width > 128)
+			goto range_err;
+		height = atoi(argv[2]);
+		if (height < 1 || height > 128)
+			goto range_err;
+		if (xstart + width > 128)
+			goto range_err;
+		if (ystart + height > 128)
+			goto range_err;
+		break;
+	default:
+		printf("ERROR: wrong number of arguments\n");
+		return;
+	}
+	npix = width * height;
+	if (img_file_size != npix * 2) {
+		printf("ERROR: image file size (%u bytes) does not match WxH\n",
+			img_file_size);
+		return;
+	}
+	set_lcd_addr_region(xstart, xstart + width - 1,
+				ystart, ystart + height - 1);
+	/* the artwork images in Pirelli's FFS appear to be inverted */
+	for (i = 0; i < npix; i++)
+		nCS4_ADDR2 = ~imgbuf[i];
+}