Merge branch 'iu-boot/master' into 'u-boot-arm/master'
[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  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
11 #include <malloc.h>
12 #include <linux/err.h>
13 #include <asm/arch/dsim.h>
14 #include <asm/arch/mipi_dsim.h>
15 #include <asm/arch/power.h>
16 #include <asm/arch/cpu.h>
17 #include <asm/arch/clk.h>
18
19 #include "exynos_mipi_dsi_lowlevel.h"
20 #include "exynos_mipi_dsi_common.h"
21
22 #define master_to_driver(a)     (a->dsim_lcd_drv)
23 #define master_to_device(a)     (a->dsim_lcd_dev)
24
25 static struct exynos_platform_mipi_dsim *dsim_pd;
26
27 struct mipi_dsim_ddi {
28         int                             bus_id;
29         struct list_head                list;
30         struct mipi_dsim_lcd_device     *dsim_lcd_dev;
31         struct mipi_dsim_lcd_driver     *dsim_lcd_drv;
32 };
33
34 static LIST_HEAD(dsim_ddi_list);
35 static LIST_HEAD(dsim_lcd_dev_list);
36
37 int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
38 {
39         struct mipi_dsim_ddi *dsim_ddi;
40
41         if (!lcd_dev) {
42                 debug("mipi_dsim_lcd_device is NULL.\n");
43                 return -EFAULT;
44         }
45
46         if (!lcd_dev->name) {
47                 debug("dsim_lcd_device name is NULL.\n");
48                 return -EFAULT;
49         }
50
51         dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
52         if (!dsim_ddi) {
53                 debug("failed to allocate dsim_ddi object.\n");
54                 return -EFAULT;
55         }
56
57         dsim_ddi->dsim_lcd_dev = lcd_dev;
58
59         list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
60
61         return 0;
62 }
63
64 struct mipi_dsim_ddi
65         *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
66 {
67         struct mipi_dsim_ddi *dsim_ddi;
68         struct mipi_dsim_lcd_device *lcd_dev;
69
70         list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
71                 lcd_dev = dsim_ddi->dsim_lcd_dev;
72                 if (!lcd_dev)
73                         continue;
74
75                 if (lcd_drv->id >= 0) {
76                         if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 &&
77                                         lcd_drv->id == lcd_dev->id) {
78                                 /**
79                                  * bus_id would be used to identify
80                                  * connected bus.
81                                  */
82                                 dsim_ddi->bus_id = lcd_dev->bus_id;
83
84                                 return dsim_ddi;
85                         }
86                 } else {
87                         if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
88                                 /**
89                                  * bus_id would be used to identify
90                                  * connected bus.
91                                  */
92                                 dsim_ddi->bus_id = lcd_dev->bus_id;
93
94                                 return dsim_ddi;
95                         }
96                 }
97
98                 kfree(dsim_ddi);
99                 list_del(&dsim_ddi_list);
100         }
101
102         return NULL;
103 }
104
105 int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
106 {
107         struct mipi_dsim_ddi *dsim_ddi;
108
109         if (!lcd_drv) {
110                 debug("mipi_dsim_lcd_driver is NULL.\n");
111                 return -EFAULT;
112         }
113
114         if (!lcd_drv->name) {
115                 debug("dsim_lcd_driver name is NULL.\n");
116                 return -EFAULT;
117         }
118
119         dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
120         if (!dsim_ddi) {
121                 debug("mipi_dsim_ddi object not found.\n");
122                 return -EFAULT;
123         }
124
125         dsim_ddi->dsim_lcd_drv = lcd_drv;
126
127         debug("registered panel driver(%s) to mipi-dsi driver.\n",
128                 lcd_drv->name);
129
130         return 0;
131
132 }
133
134 struct mipi_dsim_ddi
135         *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
136                         const char *name)
137 {
138         struct mipi_dsim_ddi *dsim_ddi;
139         struct mipi_dsim_lcd_driver *lcd_drv;
140         struct mipi_dsim_lcd_device *lcd_dev;
141
142         list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
143                 lcd_drv = dsim_ddi->dsim_lcd_drv;
144                 lcd_dev = dsim_ddi->dsim_lcd_dev;
145                 if (!lcd_drv || !lcd_dev)
146                         continue;
147
148                 debug("lcd_drv->id = %d, lcd_dev->id = %d\n",
149                                         lcd_drv->id, lcd_dev->id);
150
151                 if ((strcmp(lcd_drv->name, name) == 0)) {
152                         lcd_dev->master = dsim;
153
154                         dsim->dsim_lcd_dev = lcd_dev;
155                         dsim->dsim_lcd_drv = lcd_drv;
156
157                         return dsim_ddi;
158                 }
159         }
160
161         return NULL;
162 }
163
164 /* define MIPI-DSI Master operations. */
165 static struct mipi_dsim_master_ops master_ops = {
166         .cmd_write                      = exynos_mipi_dsi_wr_data,
167         .get_dsim_frame_done            = exynos_mipi_dsi_get_frame_done_status,
168         .clear_dsim_frame_done          = exynos_mipi_dsi_clear_frame_done,
169 };
170
171 int exynos_mipi_dsi_init(void)
172 {
173         struct mipi_dsim_device *dsim;
174         struct mipi_dsim_config *dsim_config;
175         struct mipi_dsim_ddi *dsim_ddi;
176
177         dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
178         if (!dsim) {
179                 debug("failed to allocate dsim object.\n");
180                 return -EFAULT;
181         }
182
183         /* get mipi_dsim_config. */
184         dsim_config = dsim_pd->dsim_config;
185         if (dsim_config == NULL) {
186                 debug("failed to get dsim config data.\n");
187                 return -EFAULT;
188         }
189
190         dsim->pd = dsim_pd;
191         dsim->dsim_config = dsim_config;
192         dsim->master_ops = &master_ops;
193
194         /* bind lcd ddi matched with panel name. */
195         dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
196         if (!dsim_ddi) {
197                 debug("mipi_dsim_ddi object not found.\n");
198                 return -ENOSYS;
199         }
200         if (dsim_pd->lcd_power)
201                 dsim_pd->lcd_power();
202
203         if (dsim_pd->mipi_power)
204                 dsim_pd->mipi_power();
205
206         /* phy_enable(unsigned int dev_index, unsigned int enable) */
207         if (dsim_pd->phy_enable)
208                 dsim_pd->phy_enable(0, 1);
209
210         set_mipi_clk();
211
212         exynos_mipi_dsi_init_dsim(dsim);
213         exynos_mipi_dsi_init_link(dsim);
214         exynos_mipi_dsi_set_hs_enable(dsim);
215
216         /* set display timing. */
217         exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
218
219         /* initialize mipi-dsi client(lcd panel). */
220         if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) {
221                 dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim);
222                 dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim);
223         }
224
225         debug("mipi-dsi driver(%s mode) has been probed.\n",
226                 (dsim_config->e_interface == DSIM_COMMAND) ?
227                         "CPU" : "RGB");
228
229         return 0;
230 }
231
232 void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd)
233 {
234         if (pd == NULL) {
235                 debug("pd is NULL\n");
236                 return;
237         }
238
239         dsim_pd = pd;
240 }