blob: a5d9b5921868c00bf32543ac493f601be6398ec5 [file] [log] [blame]
Donghwa Leed84f7832012-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 Denkbd8ec7e2013-10-07 13:07:26 +02007 * SPDX-License-Identifier: GPL-2.0+
Donghwa Leed84f7832012-04-05 19:36:21 +00008 */
9
10#include <common.h>
11#include <malloc.h>
Piotr Wilczek24e368a2014-03-07 14:59:39 +010012#include <fdtdec.h>
13#include <libfdt.h>
Heiko Schocher4f7a9a32014-06-24 10:10:03 +020014#include <linux/compat.h>
Donghwa Leed84f7832012-04-05 19:36:21 +000015#include <linux/err.h>
16#include <asm/arch/dsim.h>
17#include <asm/arch/mipi_dsim.h>
18#include <asm/arch/power.h>
19#include <asm/arch/cpu.h>
20#include <asm/arch/clk.h>
21
22#include "exynos_mipi_dsi_lowlevel.h"
23#include "exynos_mipi_dsi_common.h"
24
25#define master_to_driver(a) (a->dsim_lcd_drv)
26#define master_to_device(a) (a->dsim_lcd_dev)
27
Piotr Wilczek24e368a2014-03-07 14:59:39 +010028DECLARE_GLOBAL_DATA_PTR;
29
Donghwa Leed84f7832012-04-05 19:36:21 +000030struct mipi_dsim_ddi {
31 int bus_id;
32 struct list_head list;
33 struct mipi_dsim_lcd_device *dsim_lcd_dev;
34 struct mipi_dsim_lcd_driver *dsim_lcd_drv;
35};
36
37static LIST_HEAD(dsim_ddi_list);
38static LIST_HEAD(dsim_lcd_dev_list);
39
40int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
41{
42 struct mipi_dsim_ddi *dsim_ddi;
43
44 if (!lcd_dev) {
45 debug("mipi_dsim_lcd_device is NULL.\n");
46 return -EFAULT;
47 }
48
49 if (!lcd_dev->name) {
50 debug("dsim_lcd_device name is NULL.\n");
51 return -EFAULT;
52 }
53
54 dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
55 if (!dsim_ddi) {
56 debug("failed to allocate dsim_ddi object.\n");
57 return -EFAULT;
58 }
59
60 dsim_ddi->dsim_lcd_dev = lcd_dev;
61
62 list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
63
64 return 0;
65}
66
67struct mipi_dsim_ddi
68 *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
69{
70 struct mipi_dsim_ddi *dsim_ddi;
71 struct mipi_dsim_lcd_device *lcd_dev;
72
73 list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
74 lcd_dev = dsim_ddi->dsim_lcd_dev;
75 if (!lcd_dev)
76 continue;
77
78 if (lcd_drv->id >= 0) {
79 if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 &&
80 lcd_drv->id == lcd_dev->id) {
81 /**
82 * bus_id would be used to identify
83 * connected bus.
84 */
85 dsim_ddi->bus_id = lcd_dev->bus_id;
86
87 return dsim_ddi;
88 }
89 } else {
90 if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
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 }
100
101 kfree(dsim_ddi);
102 list_del(&dsim_ddi_list);
103 }
104
105 return NULL;
106}
107
108int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
109{
110 struct mipi_dsim_ddi *dsim_ddi;
111
112 if (!lcd_drv) {
113 debug("mipi_dsim_lcd_driver is NULL.\n");
114 return -EFAULT;
115 }
116
117 if (!lcd_drv->name) {
118 debug("dsim_lcd_driver name is NULL.\n");
119 return -EFAULT;
120 }
121
122 dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
123 if (!dsim_ddi) {
124 debug("mipi_dsim_ddi object not found.\n");
125 return -EFAULT;
126 }
127
128 dsim_ddi->dsim_lcd_drv = lcd_drv;
129
130 debug("registered panel driver(%s) to mipi-dsi driver.\n",
131 lcd_drv->name);
132
133 return 0;
134
135}
136
137struct mipi_dsim_ddi
138 *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
139 const char *name)
140{
141 struct mipi_dsim_ddi *dsim_ddi;
142 struct mipi_dsim_lcd_driver *lcd_drv;
143 struct mipi_dsim_lcd_device *lcd_dev;
144
145 list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
146 lcd_drv = dsim_ddi->dsim_lcd_drv;
147 lcd_dev = dsim_ddi->dsim_lcd_dev;
148 if (!lcd_drv || !lcd_dev)
149 continue;
150
151 debug("lcd_drv->id = %d, lcd_dev->id = %d\n",
152 lcd_drv->id, lcd_dev->id);
153
154 if ((strcmp(lcd_drv->name, name) == 0)) {
155 lcd_dev->master = dsim;
156
157 dsim->dsim_lcd_dev = lcd_dev;
158 dsim->dsim_lcd_drv = lcd_drv;
159
160 return dsim_ddi;
161 }
162 }
163
164 return NULL;
165}
166
167/* define MIPI-DSI Master operations. */
168static struct mipi_dsim_master_ops master_ops = {
169 .cmd_write = exynos_mipi_dsi_wr_data,
170 .get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status,
171 .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done,
172};
173
Simon Glassef4e7792016-02-21 21:08:46 -0700174int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd)
Donghwa Leed84f7832012-04-05 19:36:21 +0000175{
176 struct mipi_dsim_device *dsim;
177 struct mipi_dsim_config *dsim_config;
178 struct mipi_dsim_ddi *dsim_ddi;
179
180 dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
181 if (!dsim) {
182 debug("failed to allocate dsim object.\n");
183 return -EFAULT;
184 }
185
186 /* get mipi_dsim_config. */
187 dsim_config = dsim_pd->dsim_config;
188 if (dsim_config == NULL) {
189 debug("failed to get dsim config data.\n");
190 return -EFAULT;
191 }
192
193 dsim->pd = dsim_pd;
194 dsim->dsim_config = dsim_config;
195 dsim->master_ops = &master_ops;
196
197 /* bind lcd ddi matched with panel name. */
198 dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
199 if (!dsim_ddi) {
200 debug("mipi_dsim_ddi object not found.\n");
201 return -ENOSYS;
202 }
203 if (dsim_pd->lcd_power)
204 dsim_pd->lcd_power();
205
206 if (dsim_pd->mipi_power)
207 dsim_pd->mipi_power();
208
209 /* phy_enable(unsigned int dev_index, unsigned int enable) */
210 if (dsim_pd->phy_enable)
211 dsim_pd->phy_enable(0, 1);
212
213 set_mipi_clk();
214
215 exynos_mipi_dsi_init_dsim(dsim);
216 exynos_mipi_dsi_init_link(dsim);
217 exynos_mipi_dsi_set_hs_enable(dsim);
218
219 /* set display timing. */
220 exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
221
222 /* initialize mipi-dsi client(lcd panel). */
223 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) {
224 dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim);
225 dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim);
226 }
227
228 debug("mipi-dsi driver(%s mode) has been probed.\n",
229 (dsim_config->e_interface == DSIM_COMMAND) ?
230 "CPU" : "RGB");
231
232 return 0;
233}
234
Simon Glass6d237092016-02-21 21:08:47 -0700235int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt,
236 struct mipi_dsim_lcd_device *lcd_dt)
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100237{
238 int node;
239
240 node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_MIPI_DSI);
241 if (node <= 0) {
242 printf("exynos_mipi_dsi: Can't get device node for mipi dsi\n");
243 return -ENODEV;
244 }
245
Simon Glassf013e7a2016-02-21 21:08:45 -0700246 dt->e_interface = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100247 "samsung,dsim-config-e-interface", 0);
248
Simon Glassf013e7a2016-02-21 21:08:45 -0700249 dt->e_virtual_ch = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100250 "samsung,dsim-config-e-virtual-ch", 0);
251
Simon Glassf013e7a2016-02-21 21:08:45 -0700252 dt->e_pixel_format = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100253 "samsung,dsim-config-e-pixel-format", 0);
254
Simon Glassf013e7a2016-02-21 21:08:45 -0700255 dt->e_burst_mode = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100256 "samsung,dsim-config-e-burst-mode", 0);
257
Simon Glassf013e7a2016-02-21 21:08:45 -0700258 dt->e_no_data_lane = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100259 "samsung,dsim-config-e-no-data-lane", 0);
260
Simon Glassf013e7a2016-02-21 21:08:45 -0700261 dt->e_byte_clk = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100262 "samsung,dsim-config-e-byte-clk", 0);
263
Simon Glassf013e7a2016-02-21 21:08:45 -0700264 dt->hfp = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100265 "samsung,dsim-config-hfp", 0);
266
Simon Glassf013e7a2016-02-21 21:08:45 -0700267 dt->p = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100268 "samsung,dsim-config-p", 0);
Simon Glassf013e7a2016-02-21 21:08:45 -0700269 dt->m = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100270 "samsung,dsim-config-m", 0);
Simon Glassf013e7a2016-02-21 21:08:45 -0700271 dt->s = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100272 "samsung,dsim-config-s", 0);
273
Simon Glassf013e7a2016-02-21 21:08:45 -0700274 dt->pll_stable_time = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100275 "samsung,dsim-config-pll-stable-time", 0);
276
Simon Glassf013e7a2016-02-21 21:08:45 -0700277 dt->esc_clk = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100278 "samsung,dsim-config-esc-clk", 0);
279
Simon Glassf013e7a2016-02-21 21:08:45 -0700280 dt->stop_holding_cnt = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100281 "samsung,dsim-config-stop-holding-cnt", 0);
282
Simon Glassf013e7a2016-02-21 21:08:45 -0700283 dt->bta_timeout = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100284 "samsung,dsim-config-bta-timeout", 0);
285
Simon Glassf013e7a2016-02-21 21:08:45 -0700286 dt->rx_timeout = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100287 "samsung,dsim-config-rx-timeout", 0);
288
Simon Glass6d237092016-02-21 21:08:47 -0700289 lcd_dt->name = fdtdec_get_config_string(blob,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100290 "samsung,dsim-device-name");
291
Simon Glass6d237092016-02-21 21:08:47 -0700292 lcd_dt->id = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100293 "samsung,dsim-device-id", 0);
294
Simon Glass6d237092016-02-21 21:08:47 -0700295 lcd_dt->bus_id = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100296 "samsung,dsim-device-bus_id", 0);
297
Simon Glass6d237092016-02-21 21:08:47 -0700298 lcd_dt->reverse_panel = fdtdec_get_int(blob, node,
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100299 "samsung,dsim-device-reverse-panel", 0);
300
301 return 0;
302}
303
304void exynos_init_dsim_platform_data(vidinfo_t *vid)
305{
Simon Glassef4e7792016-02-21 21:08:46 -0700306 static struct mipi_dsim_config dsim_config_dt;
307 static struct exynos_platform_mipi_dsim dsim_platform_data_dt;
Simon Glass6d237092016-02-21 21:08:47 -0700308 static struct mipi_dsim_lcd_device mipi_lcd_device_dt;
Simon Glassf013e7a2016-02-21 21:08:45 -0700309
Simon Glass6d237092016-02-21 21:08:47 -0700310 if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt,
311 &mipi_lcd_device_dt))
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100312 debug("Can't get proper dsim config.\n");
313
314 strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name);
315 dsim_platform_data_dt.dsim_config = &dsim_config_dt;
316 dsim_platform_data_dt.mipi_power = mipi_power;
317 dsim_platform_data_dt.phy_enable = set_mipi_phy_ctrl;
318 dsim_platform_data_dt.lcd_panel_info = (void *)vid;
319
320 mipi_lcd_device_dt.platform_data = (void *)&dsim_platform_data_dt;
321 exynos_mipi_dsi_register_lcd_device(&mipi_lcd_device_dt);
322
Simon Glassef4e7792016-02-21 21:08:46 -0700323 vid->dsim_platform_data_dt = &dsim_platform_data_dt;
Piotr Wilczek24e368a2014-03-07 14:59:39 +0100324}