Merge branch 'master' of git://git.denx.de/u-boot-spi
[oweals/u-boot.git] / drivers / video / exynos_mipi_dsi.c
1 /*
2  * Copyright (C) 2012 Samsung Electronics
3  *
4  * Author: InKi Dae <inki.dae@samsung.com>
5  * Author: Donghwa Lee <dh09.lee@samsung.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22
23 #include <common.h>
24 #include <malloc.h>
25 #include <linux/err.h>
26 #include <asm/arch/dsim.h>
27 #include <asm/arch/mipi_dsim.h>
28 #include <asm/arch/power.h>
29 #include <asm/arch/cpu.h>
30 #include <asm/arch/clk.h>
31
32 #include "exynos_mipi_dsi_lowlevel.h"
33 #include "exynos_mipi_dsi_common.h"
34
35 #define master_to_driver(a)     (a->dsim_lcd_drv)
36 #define master_to_device(a)     (a->dsim_lcd_dev)
37
38 static struct exynos_platform_mipi_dsim *dsim_pd;
39
40 struct mipi_dsim_ddi {
41         int                             bus_id;
42         struct list_head                list;
43         struct mipi_dsim_lcd_device     *dsim_lcd_dev;
44         struct mipi_dsim_lcd_driver     *dsim_lcd_drv;
45 };
46
47 static LIST_HEAD(dsim_ddi_list);
48 static LIST_HEAD(dsim_lcd_dev_list);
49
50 int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
51 {
52         struct mipi_dsim_ddi *dsim_ddi;
53
54         if (!lcd_dev) {
55                 debug("mipi_dsim_lcd_device is NULL.\n");
56                 return -EFAULT;
57         }
58
59         if (!lcd_dev->name) {
60                 debug("dsim_lcd_device name is NULL.\n");
61                 return -EFAULT;
62         }
63
64         dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
65         if (!dsim_ddi) {
66                 debug("failed to allocate dsim_ddi object.\n");
67                 return -EFAULT;
68         }
69
70         dsim_ddi->dsim_lcd_dev = lcd_dev;
71
72         list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
73
74         return 0;
75 }
76
77 struct mipi_dsim_ddi
78         *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
79 {
80         struct mipi_dsim_ddi *dsim_ddi;
81         struct mipi_dsim_lcd_device *lcd_dev;
82
83         list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
84                 lcd_dev = dsim_ddi->dsim_lcd_dev;
85                 if (!lcd_dev)
86                         continue;
87
88                 if (lcd_drv->id >= 0) {
89                         if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 &&
90                                         lcd_drv->id == lcd_dev->id) {
91                                 /**
92                                  * bus_id would be used to identify
93                                  * connected bus.
94                                  */
95                                 dsim_ddi->bus_id = lcd_dev->bus_id;
96
97                                 return dsim_ddi;
98                         }
99                 } else {
100                         if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
101                                 /**
102                                  * bus_id would be used to identify
103                                  * connected bus.
104                                  */
105                                 dsim_ddi->bus_id = lcd_dev->bus_id;
106
107                                 return dsim_ddi;
108                         }
109                 }
110
111                 kfree(dsim_ddi);
112                 list_del(&dsim_ddi_list);
113         }
114
115         return NULL;
116 }
117
118 int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
119 {
120         struct mipi_dsim_ddi *dsim_ddi;
121
122         if (!lcd_drv) {
123                 debug("mipi_dsim_lcd_driver is NULL.\n");
124                 return -EFAULT;
125         }
126
127         if (!lcd_drv->name) {
128                 debug("dsim_lcd_driver name is NULL.\n");
129                 return -EFAULT;
130         }
131
132         dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
133         if (!dsim_ddi) {
134                 debug("mipi_dsim_ddi object not found.\n");
135                 return -EFAULT;
136         }
137
138         dsim_ddi->dsim_lcd_drv = lcd_drv;
139
140         debug("registered panel driver(%s) to mipi-dsi driver.\n",
141                 lcd_drv->name);
142
143         return 0;
144
145 }
146
147 struct mipi_dsim_ddi
148         *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
149                         const char *name)
150 {
151         struct mipi_dsim_ddi *dsim_ddi;
152         struct mipi_dsim_lcd_driver *lcd_drv;
153         struct mipi_dsim_lcd_device *lcd_dev;
154
155         list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
156                 lcd_drv = dsim_ddi->dsim_lcd_drv;
157                 lcd_dev = dsim_ddi->dsim_lcd_dev;
158                 if (!lcd_drv || !lcd_dev)
159                         continue;
160
161                 debug("lcd_drv->id = %d, lcd_dev->id = %d\n",
162                                         lcd_drv->id, lcd_dev->id);
163
164                 if ((strcmp(lcd_drv->name, name) == 0)) {
165                         lcd_dev->master = dsim;
166
167                         dsim->dsim_lcd_dev = lcd_dev;
168                         dsim->dsim_lcd_drv = lcd_drv;
169
170                         return dsim_ddi;
171                 }
172         }
173
174         return NULL;
175 }
176
177 /* define MIPI-DSI Master operations. */
178 static struct mipi_dsim_master_ops master_ops = {
179         .cmd_write                      = exynos_mipi_dsi_wr_data,
180         .get_dsim_frame_done            = exynos_mipi_dsi_get_frame_done_status,
181         .clear_dsim_frame_done          = exynos_mipi_dsi_clear_frame_done,
182 };
183
184 int exynos_mipi_dsi_init(void)
185 {
186         struct mipi_dsim_device *dsim;
187         struct mipi_dsim_config *dsim_config;
188         struct mipi_dsim_ddi *dsim_ddi;
189
190         dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
191         if (!dsim) {
192                 debug("failed to allocate dsim object.\n");
193                 return -EFAULT;
194         }
195
196         /* get mipi_dsim_config. */
197         dsim_config = dsim_pd->dsim_config;
198         if (dsim_config == NULL) {
199                 debug("failed to get dsim config data.\n");
200                 return -EFAULT;
201         }
202
203         dsim->pd = dsim_pd;
204         dsim->dsim_config = dsim_config;
205         dsim->master_ops = &master_ops;
206
207         /* bind lcd ddi matched with panel name. */
208         dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
209         if (!dsim_ddi) {
210                 debug("mipi_dsim_ddi object not found.\n");
211                 return -ENOSYS;
212         }
213         if (dsim_pd->lcd_power)
214                 dsim_pd->lcd_power();
215
216         if (dsim_pd->mipi_power)
217                 dsim_pd->mipi_power();
218
219         /* phy_enable(unsigned int dev_index, unsigned int enable) */
220         if (dsim_pd->phy_enable)
221                 dsim_pd->phy_enable(0, 1);
222
223         set_mipi_clk();
224
225         exynos_mipi_dsi_init_dsim(dsim);
226         exynos_mipi_dsi_init_link(dsim);
227         exynos_mipi_dsi_set_hs_enable(dsim);
228
229         /* set display timing. */
230         exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
231
232         /* initialize mipi-dsi client(lcd panel). */
233         if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) {
234                 dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim);
235                 dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim);
236         }
237
238         debug("mipi-dsi driver(%s mode) has been probed.\n",
239                 (dsim_config->e_interface == DSIM_COMMAND) ?
240                         "CPU" : "RGB");
241
242         return 0;
243 }
244
245 void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd)
246 {
247         if (pd == NULL) {
248                 debug("pd is NULL\n");
249                 return;
250         }
251
252         dsim_pd = pd;
253 }