FreeCalypso > hg > freecalypso-tools
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]; +}