xref: /openbmc/linux/arch/sh/boards/mach-migor/lcd_qvga.c (revision 597473720f4dc69749542bfcfed4a927a43d935e)
1*aaf9128aSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
2da2014a2SPaul Mundt /*
3da2014a2SPaul Mundt  * Support for SuperH MigoR Quarter VGA LCD Panel
4da2014a2SPaul Mundt  *
5da2014a2SPaul Mundt  * Copyright (C) 2008 Magnus Damm
6da2014a2SPaul Mundt  *
7da2014a2SPaul Mundt  * Based on lcd_powertip.c from Kenati Technologies Pvt Ltd.
8da2014a2SPaul Mundt  * Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>,
9da2014a2SPaul Mundt  */
10da2014a2SPaul Mundt 
11da2014a2SPaul Mundt #include <linux/delay.h>
12da2014a2SPaul Mundt #include <linux/err.h>
13da2014a2SPaul Mundt #include <linux/fb.h>
14da2014a2SPaul Mundt #include <linux/init.h>
15da2014a2SPaul Mundt #include <linux/kernel.h>
16da2014a2SPaul Mundt #include <linux/module.h>
1791b6f3c5SMagnus Damm #include <linux/gpio.h>
18225c9a8dSPaul Mundt #include <video/sh_mobile_lcdc.h>
19f7275650SPaul Mundt #include <cpu/sh7722.h>
207639a454SPaul Mundt #include <mach/migor.h>
21da2014a2SPaul Mundt 
22da2014a2SPaul Mundt /* LCD Module is a PH240320T according to board schematics. This module
23da2014a2SPaul Mundt  * is made up of a 240x320 LCD hooked up to a R61505U (or HX8347-A01?)
24da2014a2SPaul Mundt  * Driver IC. This IC is connected to the SH7722 built-in LCDC using a
25da2014a2SPaul Mundt  * SYS-80 interface configured in 16 bit mode.
26da2014a2SPaul Mundt  *
27da2014a2SPaul Mundt  * Index 0: "Device Code Read" returns 0x1505.
28da2014a2SPaul Mundt  */
29da2014a2SPaul Mundt 
reset_lcd_module(void)30da2014a2SPaul Mundt static void reset_lcd_module(void)
31da2014a2SPaul Mundt {
3291b6f3c5SMagnus Damm 	gpio_set_value(GPIO_PTH2, 0);
33da2014a2SPaul Mundt 	mdelay(2);
3491b6f3c5SMagnus Damm 	gpio_set_value(GPIO_PTH2, 1);
35da2014a2SPaul Mundt 	mdelay(1);
36da2014a2SPaul Mundt }
37da2014a2SPaul Mundt 
38da2014a2SPaul Mundt /* DB0-DB7 are connected to D1-D8, and DB8-DB15 to D10-D17 */
39da2014a2SPaul Mundt 
adjust_reg18(unsigned short data)40da2014a2SPaul Mundt static unsigned long adjust_reg18(unsigned short data)
41da2014a2SPaul Mundt {
42da2014a2SPaul Mundt 	unsigned long tmp1, tmp2;
43da2014a2SPaul Mundt 
44da2014a2SPaul Mundt 	tmp1 = (data<<1 | 0x00000001) & 0x000001FF;
45da2014a2SPaul Mundt 	tmp2 = (data<<2 | 0x00000200) & 0x0003FE00;
46da2014a2SPaul Mundt 	return tmp1 | tmp2;
47da2014a2SPaul Mundt }
48da2014a2SPaul Mundt 
write_reg(void * sys_ops_handle,struct sh_mobile_lcdc_sys_bus_ops * sys_ops,unsigned short reg,unsigned short data)49da2014a2SPaul Mundt static void write_reg(void *sys_ops_handle,
50da2014a2SPaul Mundt 		       struct sh_mobile_lcdc_sys_bus_ops *sys_ops,
51da2014a2SPaul Mundt 		       unsigned short reg, unsigned short data)
52da2014a2SPaul Mundt {
53da2014a2SPaul Mundt 	sys_ops->write_index(sys_ops_handle, adjust_reg18(reg << 8 | data));
54da2014a2SPaul Mundt }
55da2014a2SPaul Mundt 
write_reg16(void * sys_ops_handle,struct sh_mobile_lcdc_sys_bus_ops * sys_ops,unsigned short reg,unsigned short data)56da2014a2SPaul Mundt static void write_reg16(void *sys_ops_handle,
57da2014a2SPaul Mundt 			struct sh_mobile_lcdc_sys_bus_ops *sys_ops,
58da2014a2SPaul Mundt 			unsigned short reg, unsigned short data)
59da2014a2SPaul Mundt {
60da2014a2SPaul Mundt 	sys_ops->write_index(sys_ops_handle, adjust_reg18(reg));
61da2014a2SPaul Mundt 	sys_ops->write_data(sys_ops_handle, adjust_reg18(data));
62da2014a2SPaul Mundt }
63da2014a2SPaul Mundt 
read_reg16(void * sys_ops_handle,struct sh_mobile_lcdc_sys_bus_ops * sys_ops,unsigned short reg)64da2014a2SPaul Mundt static unsigned long read_reg16(void *sys_ops_handle,
65da2014a2SPaul Mundt 				struct sh_mobile_lcdc_sys_bus_ops *sys_ops,
66da2014a2SPaul Mundt 				unsigned short reg)
67da2014a2SPaul Mundt {
68da2014a2SPaul Mundt 	unsigned long data;
69da2014a2SPaul Mundt 
70da2014a2SPaul Mundt 	sys_ops->write_index(sys_ops_handle, adjust_reg18(reg));
71da2014a2SPaul Mundt 	data = sys_ops->read_data(sys_ops_handle);
72da2014a2SPaul Mundt 	return ((data >> 1) & 0xff) | ((data >> 2) & 0xff00);
73da2014a2SPaul Mundt }
74da2014a2SPaul Mundt 
migor_lcd_qvga_seq(void * sys_ops_handle,struct sh_mobile_lcdc_sys_bus_ops * sys_ops,unsigned short const * data,int no_data)75da2014a2SPaul Mundt static void migor_lcd_qvga_seq(void *sys_ops_handle,
76da2014a2SPaul Mundt 			       struct sh_mobile_lcdc_sys_bus_ops *sys_ops,
77da2014a2SPaul Mundt 			       unsigned short const *data, int no_data)
78da2014a2SPaul Mundt {
79da2014a2SPaul Mundt 	int i;
80da2014a2SPaul Mundt 
81da2014a2SPaul Mundt 	for (i = 0; i < no_data; i += 2)
82da2014a2SPaul Mundt 		write_reg16(sys_ops_handle, sys_ops, data[i], data[i + 1]);
83da2014a2SPaul Mundt }
84da2014a2SPaul Mundt 
85da2014a2SPaul Mundt static const unsigned short sync_data[] = {
86da2014a2SPaul Mundt 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
87da2014a2SPaul Mundt };
88da2014a2SPaul Mundt 
89da2014a2SPaul Mundt static const unsigned short magic0_data[] = {
90da2014a2SPaul Mundt 	0x0060, 0x2700, 0x0008, 0x0808, 0x0090, 0x001A, 0x0007, 0x0001,
91da2014a2SPaul Mundt 	0x0017, 0x0001, 0x0019, 0x0000, 0x0010, 0x17B0, 0x0011, 0x0116,
92da2014a2SPaul Mundt 	0x0012, 0x0198, 0x0013, 0x1400, 0x0029, 0x000C, 0x0012, 0x01B8,
93da2014a2SPaul Mundt };
94da2014a2SPaul Mundt 
95da2014a2SPaul Mundt static const unsigned short magic1_data[] = {
96da2014a2SPaul Mundt 	0x0030, 0x0307, 0x0031, 0x0303, 0x0032, 0x0603, 0x0033, 0x0202,
97da2014a2SPaul Mundt 	0x0034, 0x0202, 0x0035, 0x0202, 0x0036, 0x1F1F, 0x0037, 0x0303,
98da2014a2SPaul Mundt 	0x0038, 0x0303, 0x0039, 0x0603, 0x003A, 0x0202, 0x003B, 0x0102,
99da2014a2SPaul Mundt 	0x003C, 0x0204, 0x003D, 0x0000, 0x0001, 0x0100, 0x0002, 0x0300,
100da2014a2SPaul Mundt 	0x0003, 0x5028, 0x0020, 0x00ef, 0x0021, 0x0000, 0x0004, 0x0000,
101da2014a2SPaul Mundt 	0x0009, 0x0000, 0x000A, 0x0008, 0x000C, 0x0000, 0x000D, 0x0000,
102da2014a2SPaul Mundt 	0x0015, 0x8000,
103da2014a2SPaul Mundt };
104da2014a2SPaul Mundt 
105da2014a2SPaul Mundt static const unsigned short magic2_data[] = {
106da2014a2SPaul Mundt 	0x0061, 0x0001, 0x0092, 0x0100, 0x0093, 0x0001, 0x0007, 0x0021,
107da2014a2SPaul Mundt };
108da2014a2SPaul Mundt 
109da2014a2SPaul Mundt static const unsigned short magic3_data[] = {
110da2014a2SPaul Mundt 	0x0010, 0x16B0, 0x0011, 0x0111, 0x0007, 0x0061,
111da2014a2SPaul Mundt };
112da2014a2SPaul Mundt 
migor_lcd_qvga_setup(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)113018882aaSLaurent Pinchart int migor_lcd_qvga_setup(void *sohandle, struct sh_mobile_lcdc_sys_bus_ops *so)
114da2014a2SPaul Mundt {
115da2014a2SPaul Mundt 	unsigned long xres = 320;
116da2014a2SPaul Mundt 	unsigned long yres = 240;
117da2014a2SPaul Mundt 	int k;
118da2014a2SPaul Mundt 
119da2014a2SPaul Mundt 	reset_lcd_module();
120da2014a2SPaul Mundt 	migor_lcd_qvga_seq(sohandle, so, sync_data, ARRAY_SIZE(sync_data));
121da2014a2SPaul Mundt 
122da2014a2SPaul Mundt 	if (read_reg16(sohandle, so, 0) != 0x1505)
123da2014a2SPaul Mundt 		return -ENODEV;
124da2014a2SPaul Mundt 
125da2014a2SPaul Mundt 	pr_info("Migo-R QVGA LCD Module detected.\n");
126da2014a2SPaul Mundt 
127da2014a2SPaul Mundt 	migor_lcd_qvga_seq(sohandle, so, sync_data, ARRAY_SIZE(sync_data));
128da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x00A4, 0x0001);
129da2014a2SPaul Mundt 	mdelay(10);
130da2014a2SPaul Mundt 
131da2014a2SPaul Mundt 	migor_lcd_qvga_seq(sohandle, so, magic0_data, ARRAY_SIZE(magic0_data));
132da2014a2SPaul Mundt 	mdelay(100);
133da2014a2SPaul Mundt 
134da2014a2SPaul Mundt 	migor_lcd_qvga_seq(sohandle, so, magic1_data, ARRAY_SIZE(magic1_data));
135da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0050, 0xef - (yres - 1));
136da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0051, 0x00ef);
137da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0052, 0x0000);
138da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0053, xres - 1);
139da2014a2SPaul Mundt 
140da2014a2SPaul Mundt 	migor_lcd_qvga_seq(sohandle, so, magic2_data, ARRAY_SIZE(magic2_data));
141da2014a2SPaul Mundt 	mdelay(10);
142da2014a2SPaul Mundt 
143da2014a2SPaul Mundt 	migor_lcd_qvga_seq(sohandle, so, magic3_data, ARRAY_SIZE(magic3_data));
144da2014a2SPaul Mundt 	mdelay(40);
145da2014a2SPaul Mundt 
146da2014a2SPaul Mundt 	/* clear GRAM to avoid displaying garbage */
147da2014a2SPaul Mundt 
148da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0020, 0x0000); /* horiz addr */
149da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0021, 0x0000); /* vert addr */
150da2014a2SPaul Mundt 
151da2014a2SPaul Mundt 	for (k = 0; k < (xres * 256); k++) /* yes, 256 words per line */
152da2014a2SPaul Mundt 		write_reg16(sohandle, so, 0x0022, 0x0000);
153da2014a2SPaul Mundt 
154da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0020, 0x0000); /* reset horiz addr */
155da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0021, 0x0000); /* reset vert addr */
156da2014a2SPaul Mundt 	write_reg16(sohandle, so, 0x0007, 0x0173);
157da2014a2SPaul Mundt 	mdelay(40);
158da2014a2SPaul Mundt 
159da2014a2SPaul Mundt 	/* enable display */
160da2014a2SPaul Mundt 	write_reg(sohandle, so, 0x00, 0x22);
161da2014a2SPaul Mundt 	mdelay(100);
162da2014a2SPaul Mundt 	return 0;
163da2014a2SPaul Mundt }
164