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