diff --git a/sys/include/gpanel.h b/sys/include/gpanel.h index cf3d637..96b1f00 100644 --- a/sys/include/gpanel.h +++ b/sys/include/gpanel.h @@ -158,6 +158,7 @@ struct gpanel_hw { extern void st7781_init_display(struct gpanel_hw *hw); extern void nt35702_init_display(struct gpanel_hw *hw); extern void ili9341_init_display(struct gpanel_hw *hw); +extern void s6d04h0_init_display(struct gpanel_hw *hw); #endif /* KERNEL */ diff --git a/sys/pic32/files.kconf b/sys/pic32/files.kconf index 6a319aa..d22476c 100644 --- a/sys/pic32/files.kconf +++ b/sys/pic32/files.kconf @@ -73,6 +73,7 @@ pic32/glcd.c optional glcd pic32/gpanel.c optional gpanel pic32/gpanel-ili9341.c optional gpanel pic32/gpanel-nt35702.c optional gpanel +pic32/gpanel-s6d04h0.c optional gpanel pic32/gpanel-st7781.c optional gpanel pic32/gpio.c optional gpio pic32/hx8357.c optional hxtft diff --git a/sys/pic32/gpanel-s6d04h0.c b/sys/pic32/gpanel-s6d04h0.c new file mode 100644 index 0000000..cf43019 --- /dev/null +++ b/sys/pic32/gpanel-s6d04h0.c @@ -0,0 +1,419 @@ +/* + * Display driver for Samsung S6D04H0 LCD controller. + * + * Copyright (C) 2015 Serge Vakulenko + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author be liable for any + * special, indirect or consequential damages or any damages + * whatsoever resulting from loss of use, data or profits, whether + * in an action of contract, negligence or other tortious action, + * arising out of or in connection with the use or performance of + * this software. + */ +#include +#include + +/* + * Display size. + */ +static int _width, _height; + +/* + * Level 1 Commands + */ +#define S6D04H0_No_Operation 0x00 /* C 0 */ +#define S6D04H0_Software_Reset 0x01 /* C 0 */ +#define S6D04H0_Read_Display_Identification_Information 0x04 /* R 4 */ +#define S6D04H0_Read_Display_Status 0x09 /* R 5 */ +#define S6D04H0_Read_Display_Power_Mode 0x0A /* R 2 */ +#define S6D04H0_Read_Display_MADCTL 0x0B /* R 2 */ +#define S6D04H0_Read_Display_Pixel_Format 0x0C /* R 2 */ +#define S6D04H0_Read_Display_Image_Mode 0x0D /* R 2 */ +#define S6D04H0_Read_Display_Signal_Mode 0x0E /* R 2 */ +#define S6D04H0_Read_Display_Self_Diagnostic_Result 0x0F /* R 2 */ +#define S6D04H0_Sleep_In 0x10 /* C 0 */ +#define S6D04H0_Sleep_Out 0x11 /* C 0 */ +#define S6D04H0_Partial_Mode_On 0x12 /* C 0 */ +#define S6D04H0_Normal_Display_Mode_On 0x13 /* C 0 */ +#define S6D04H0_Display_Inversion_Off 0x20 /* C 0 */ +#define S6D04H0_Display_Inversion_On 0x21 /* C 0 */ +#define S6D04H0_Gamma_Set 0x26 /* W 1 */ +#define S6D04H0_Display_Off 0x28 /* C 0 */ +#define S6D04H0_Display_On 0x29 /* C 0 */ +#define S6D04H0_Column_Address_Set 0x2A /* W 4 */ +#define S6D04H0_Page_Address_Set 0x2B /* W 4 */ +#define S6D04H0_Memory_Write 0x2C /* W n */ +#define S6D04H0_Memory_Read 0x2E /* R n */ +#define S6D04H0_Partial_Area 0x30 /* W 4 */ +#define S6D04H0_Vertical_Scrolling_Definition 0x33 /* W 6 */ +#define S6D04H0_Tearing_Effect_Line_Off 0x34 /* C 0 */ +#define S6D04H0_Tearing_Effect_Line_On 0x35 /* W 1 */ +#define S6D04H0_Memory_Data_Access_Control 0x36 /* W 1 */ +#define S6D04H0_Vertical_Scrolling_Start_Address 0x37 /* W 2 */ +#define S6D04H0_Idle_Mode_Off 0x38 /* C 0 */ +#define S6D04H0_Idle_Mode_On 0x39 /* C 0 */ +#define S6D04H0_Interface_Pixel_Format 0x3A /* W 1 */ +#define S6D04H0_Memory_Write_Continue 0x3C /* W n */ +#define S6D04H0_Memory_Read_Continue 0x3E /* R n */ +#define S6D04H0_Set_Tear_Scanline 0x44 /* W 2 */ +#define S6D04H0_Get_Scanline 0x45 /* R 2 */ +#define S6D04H0_Write_Manual_Brightness 0x51 /* W 1 */ +#define S6D04H0_Read_Display_Brightness 0x52 /* R 2 */ +#define S6D04H0_Write_BL_Control 0x53 /* W 1 */ +#define S6D04H0_Read_BL_Control 0x54 /* R 2 */ +#define S6D04H0_Write_MIE_Mode 0x55 /* W 1 */ +#define S6D04H0_Read_MIE_Mode 0x56 /* R 2 */ +#define S6D04H0_Write_Minimum_Brightness 0x5E /* W 1 */ +#define S6D04H0_Read_Minimum_Brightness 0x5F /* R 2 */ +#define S6D04H0_Read_DDB_Start 0xA1 /* R n */ +#define S6D04H0_Read_DDB_Continue 0xA8 /* R n */ +#define S6D04H0_Read_ID1 0xDA /* R 2 */ +#define S6D04H0_Read_ID2 0xDB /* R 2 */ +#define S6D04H0_Read_ID3 0xDC /* R 2 */ + +/* + * Level 2 Commands + */ +#define S6D04H0_MIECTL 0xC0 /* W(3) MIE control */ +#define S6D04H0_BCMODE 0xC1 /* W(1) MIE control */ +#define S6D04H0_WRMIECTL 0xC2 /* W(9) MIE control */ +#define S6D04H0_WRBLCTL 0xC3 /* W(2) MIE control */ +#define S6D04H0_MTPCTL 0xD0 /* W(1) MTP control */ +#define S6D04H0_MTPACCS 0xD2 /* W(2) MTP control */ +#define S6D04H0_MTPRD 0xD3 /* R(8) MTP control */ +#define S6D04H0_DSTB 0xDF /* W(1) Deep Standby */ +#define S6D04H0_PASSWD1 0xF0 /* W(2) Test Key */ +#define S6D04H0_PASSWD2 0xF1 /* W(2) Test Key */ +#define S6D04H0_DISCTL 0xF2 /* W(17) Display control */ +#define S6D04H0_MANPWRSEQ 0xF3 /* W(5) Power sequence control */ +#define S6D04H0_PWRCTL 0xF4 /* W(20) Power control */ +#define S6D04H0_VCMCTL 0xF5 /* W(12) VCOM control */ +#define S6D04H0_SRCCTL 0xF6 /* W(9) Source control */ +#define S6D04H0_IFCTL 0xF7 /* W(4) Interface control */ +#define S6D04H0_PANELCTL 0xF8 /* W(3) Gate control */ +#define S6D04H0_GAMMASEL 0xF9 /* W(1) Gamma selection */ +#define S6D04H0_PGAMMACTL 0xFA /* W(12) Positive gamma control */ +#define S6D04H0_NGAMMACTL 0xFB /* W(12) Negative gamma control */ + +/* + * Memory Access Control register + */ +#define MADCTL_MY 0x80 +#define MADCTL_MX 0x40 +#define MADCTL_MV 0x20 +#define MADCTL_ML 0x10 +#define MADCTL_BGR 0x08 +#define MADCTL_MH 0x04 +#define MADCTL_RGB 0x00 + +/* + * Write a 8-bit value to the S6D04H0 Command register. + */ +static void write_command(int cmd) +{ + gpanel_rs_command(); + gpanel_write_byte(cmd); +} + +/* + * Write a 8-bit value to the S6D04H0 Data register. + */ +static void write_data(int cmd) +{ + gpanel_rs_data(); + gpanel_write_byte(cmd); +} + +/* + * Set address window. + */ +static void set_window(int x0, int y0, int x1, int y1) +{ + write_command(S6D04H0_Column_Address_Set); + write_data(x0 >> 8); + gpanel_write_byte(x0); + gpanel_write_byte(x1 >> 8); + gpanel_write_byte(x1); + + write_command(S6D04H0_Page_Address_Set); + write_data(y0 >> 8); + gpanel_write_byte(y0); + gpanel_write_byte(y1 >> 8); + gpanel_write_byte(y1); + + write_command(S6D04H0_Memory_Write); +} + +/* + * Draw a pixel. + */ +static void s6d04h0_set_pixel(int x, int y, int color) +{ + if (x < 0 || x >= _width || y < 0 || y >= _height) + return; + gpanel_cs_active(); + set_window(x, y, x, y); + write_data(color >> 8); + write_data(color); + gpanel_cs_idle(); +} + +/* + * Fast block fill operation. + * Requires set_window() has previously been called to set + * the fill bounds. + * 'npixels' is inclusive, MUST be >= 1. + */ +static void flood(int color, int npixels) +{ + unsigned blocks, i; + unsigned hi = color >> 8, + lo = color; + + /* Write first pixel normally, decrement counter by 1. */ + gpanel_rs_data(); + gpanel_write_byte(hi); + gpanel_write_byte(lo); + npixels--; + + /* 64 pixels/block. */ + blocks = npixels >> 6; + if (hi == lo) { + /* High and low bytes are identical. Leave prior data + * on the port(s) and just toggle the write strobe. */ + while (blocks--) { + /* 64 pixels/block / 4 pixels/pass. */ + for (i = 16; i > 0; i--) { + /* 2 bytes/pixel x 4 pixels. */ + gpanel_wr_strobe(); + gpanel_wr_strobe(); + gpanel_wr_strobe(); + gpanel_wr_strobe(); + gpanel_wr_strobe(); + gpanel_wr_strobe(); + gpanel_wr_strobe(); + gpanel_wr_strobe(); + } + } + /* Fill any remaining pixels (1 to 64). */ + for (i = npixels & 63; i > 0; i--) { + gpanel_wr_strobe(); + gpanel_wr_strobe(); + } + } else { + while (blocks--) { + /* 64 pixels/block / 4 pixels/pass. */ + for (i = 16; i > 0; i--) { + gpanel_write_byte(hi); gpanel_write_byte(lo); + gpanel_write_byte(hi); gpanel_write_byte(lo); + gpanel_write_byte(hi); gpanel_write_byte(lo); + gpanel_write_byte(hi); gpanel_write_byte(lo); + } + } + for (i = npixels & 63; i > 0; i--) { + gpanel_write_byte(hi); + gpanel_write_byte(lo); + } + } +} + +/* + * Switch the screen orientation. + */ +static void set_rotation(int rotation) +{ + write_command(S6D04H0_Memory_Data_Access_Control); + switch (rotation & 3) { + case 0: /* Portrait */ + write_data(MADCTL_MY | MADCTL_BGR); + _width = 240; + _height = 320; + break; + case 1: /* Landscape */ + write_data(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); + _width = 320; + _height = 240; + break; + case 2: /* Upside down portrait */ + write_data(MADCTL_MX | MADCTL_BGR); + _width = 240; + _height = 320; + break; + case 3: /* Upside down landscape */ + write_data(MADCTL_MV | MADCTL_BGR); + _width = 320; + _height = 240; + break; + } +} + +static void s6d04h0_clear(struct gpanel_hw *h, int color, int width, int height) +{ + gpanel_cs_active(); + + /* Switch screen orientaation. */ + if (width > height) + set_rotation(1); /* Landscape */ + else if (width < height) + set_rotation(0); /* Portrait */ + + /* Fill the screen with a color. */ + set_window(0, 0, _width-1, _height-1); + flood(color, _width * _height); + gpanel_cs_idle(); +} + +/* + * Fill a rectangle with specified color. + */ +static void s6d04h0_fill_rectangle(int x0, int y0, int x1, int y1, int color) +{ + if (x0 < 0) x0 = 0; + if (y0 < 0) x0 = 0; + if (x1 < 0) x1 = 0; + if (y1 < 0) x1 = 0; + if (x0 >= _width) x0 = _width-1; + if (x1 >= _width) x1 = _width-1; + if (y0 >= _height) y0 = _height-1; + if (y1 >= _height) y1 = _height-1; + + if (x1 < x0) { + int t = x0; + x0 = x1; + x1 = t; + } + if (y1 < y0) { + int t = y0; + y0 = y1; + y1 = t; + } + gpanel_cs_active(); + set_window(x0, y0, x1, y1); + flood(color, (x1 - x0 + 1) * (y1 - y0 + 1)); + gpanel_cs_idle(); +} + +/* + * Fill a rectangle with user data. + */ +static void s6d04h0_draw_image(int x, int y, int width, int height, + const unsigned short *data) +{ + unsigned cnt = width * height; + int color; + + gpanel_cs_active(); + set_window(x, y, x + width - 1, y + height - 1); + gpanel_rs_data(); + while (cnt--) { + color = *data++; + gpanel_write_byte(color >> 8); + gpanel_write_byte(color); + } + gpanel_cs_idle(); +} + +/* + * Draw a glyph of one symbol. + */ +static void s6d04h0_draw_glyph(const struct gpanel_font_t *font, + int color, int background, int x, int y, int width, + const unsigned short *bits) +{ + int h, w, c; + unsigned bitmask = 0; + + if (background >= 0) { + /* + * Clear background. + */ + gpanel_cs_active(); + set_window(x, y, x + width - 1, y + font->height - 1); + gpanel_rs_data(); + + /* Loop on each glyph row. */ + for (h=0; hheight; h++) { + /* Loop on every pixel in the row (left to right). */ + for (w=0; w> 8); + gpanel_write_byte(c); + } + } + gpanel_cs_idle(); + } else { + /* + * Transparent background. + */ + /* Loop on each glyph row. */ + for (h=0; hheight; h++) { + /* Loop on every pixel in the row (left to right). */ + for (w=0; wname = "Samsung S6D04H0"; + h->width = _width; + h->height = _height; + h->clear = s6d04h0_clear; + h->set_pixel = s6d04h0_set_pixel; + h->fill_rectangle = s6d04h0_fill_rectangle; + h->draw_image = s6d04h0_draw_image; + h->draw_glyph = s6d04h0_draw_glyph; +} diff --git a/sys/pic32/gpanel.c b/sys/pic32/gpanel.c index 76ccc52..f87ed44 100644 --- a/sys/pic32/gpanel.c +++ b/sys/pic32/gpanel.c @@ -598,8 +598,7 @@ static int probe(config) break; case 0: - /* Register #0 is zero. - * In this case the ID is available in register #4. */ + /* Try ID from register #4. */ _chip_id = read_reg32(4) & 0xffffff; switch (_chip_id) { default: @@ -615,6 +614,22 @@ static int probe(config) /* Novatek NT35702. */ nt35702_init_display(&hw); break; + + case 0: + /* Try ID from register #D3. + * Samsung controller needs 120us to finish the reset. */ + udelay(120000); + _chip_id = read_reg32(0xD3) & 0xffffff; + switch (_chip_id) { + default: + printf("gpanel0: Unknown chip ID_D3 = 0x%06x\n", _chip_id); + goto failed; + + case 0x009341: + /* Samsung S6D04H0. */ + s6d04h0_init_display(&hw); + break; + } } break; } diff --git a/sys/pic32/wf32/Makefile b/sys/pic32/wf32/Makefile index fdb15ba..fe394e7 100644 --- a/sys/pic32/wf32/Makefile +++ b/sys/pic32/wf32/Makefile @@ -79,8 +79,8 @@ OBJS = exec_aout.o exec_conf.o exec_elf.o exec_script.o exec_subr.o \ ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o \ vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o clock.o cons.o devsw.o \ exception.o machdep.o mem.o signal.o swap.o sysctl.o adc.o \ - gpanel.o gpanel-ili9341.o gpanel-nt35702.o gpanel-st7781.o \ - gpio.o pwm.o sd.o spi.o spi_bus.o uart.o + gpanel.o gpanel-ili9341.o gpanel-nt35702.o gpanel-s6d04h0.o \ + gpanel-st7781.o gpio.o pwm.o sd.o spi.o spi_bus.o uart.o CFILES = $S/kernel/exec_aout.c $S/kernel/exec_conf.c $S/kernel/exec_elf.c \ $S/kernel/exec_script.c $S/kernel/exec_subr.c \ @@ -107,9 +107,9 @@ CFILES = $S/kernel/exec_aout.c $S/kernel/exec_conf.c $S/kernel/exec_elf.c \ $S/pic32/mem.c $S/pic32/signal.c $S/pic32/swap.c \ $S/pic32/sysctl.c $S/pic32/adc.c $S/pic32/gpanel.c \ $S/pic32/gpanel-ili9341.c $S/pic32/gpanel-nt35702.c \ - $S/pic32/gpanel-st7781.c $S/pic32/gpio.c $S/pic32/pwm.c \ - $S/pic32/sd.c $S/pic32/spi.c $S/pic32/spi_bus.c $S/pic32/uart.c \ - swapunix.c + $S/pic32/gpanel-s6d04h0.c $S/pic32/gpanel-st7781.c \ + $S/pic32/gpio.c $S/pic32/pwm.c $S/pic32/sd.c $S/pic32/spi.c \ + $S/pic32/spi_bus.c $S/pic32/uart.c swapunix.c # load lines for config "xxx" will be emitted as: # xxx: ${SYSTEM_DEP} swapxxx.o @@ -353,6 +353,9 @@ gpanel-ili9341.o: $S/pic32/gpanel-ili9341.c gpanel-nt35702.o: $S/pic32/gpanel-nt35702.c ${COMPILE_C} +gpanel-s6d04h0.o: $S/pic32/gpanel-s6d04h0.c + ${COMPILE_C} + gpanel-st7781.o: $S/pic32/gpanel-st7781.c ${COMPILE_C}