blob: 8bb8feaa9cb23584a20eb60ddc711802f7be3c21 [file] [log] [blame]
Donghwa Lee2c7396c2012-04-05 19:36:21 +00001/*
2 * Copyright (C) 2012 Samsung Electronics
3 *
4 * Author: InKi Dae <inki.dae@samsung.com>
5 * Author: Donghwa Lee <dh09.lee@samsung.com>
6 *
Wolfgang Denk3765b3e2013-10-07 13:07:26 +02007 * SPDX-License-Identifier: GPL-2.0+
Donghwa Lee2c7396c2012-04-05 19:36:21 +00008 */
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
25static struct exynos_platform_mipi_dsim *dsim_pd;
26
27struct 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
34static LIST_HEAD(dsim_ddi_list);
35static LIST_HEAD(dsim_lcd_dev_list);
36
37int 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
64struct 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
105int 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
134struct 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. */
165static 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
171int 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
232void 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}