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 <fdtdec.h> 13 #include <linux/libfdt.h> 14 #include <linux/compat.h> 15 #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 28 DECLARE_GLOBAL_DATA_PTR; 29 30 struct 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 37 static LIST_HEAD(dsim_ddi_list); 38 static LIST_HEAD(dsim_lcd_dev_list); 39 40 int 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 67 struct 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 108 int 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 137 struct 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. */ 168 static 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 174 int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd) 175 { 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 235 int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt, 236 struct mipi_dsim_lcd_device *lcd_dt) 237 { 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 246 dt->e_interface = fdtdec_get_int(blob, node, 247 "samsung,dsim-config-e-interface", 0); 248 249 dt->e_virtual_ch = fdtdec_get_int(blob, node, 250 "samsung,dsim-config-e-virtual-ch", 0); 251 252 dt->e_pixel_format = fdtdec_get_int(blob, node, 253 "samsung,dsim-config-e-pixel-format", 0); 254 255 dt->e_burst_mode = fdtdec_get_int(blob, node, 256 "samsung,dsim-config-e-burst-mode", 0); 257 258 dt->e_no_data_lane = fdtdec_get_int(blob, node, 259 "samsung,dsim-config-e-no-data-lane", 0); 260 261 dt->e_byte_clk = fdtdec_get_int(blob, node, 262 "samsung,dsim-config-e-byte-clk", 0); 263 264 dt->hfp = fdtdec_get_int(blob, node, 265 "samsung,dsim-config-hfp", 0); 266 267 dt->p = fdtdec_get_int(blob, node, 268 "samsung,dsim-config-p", 0); 269 dt->m = fdtdec_get_int(blob, node, 270 "samsung,dsim-config-m", 0); 271 dt->s = fdtdec_get_int(blob, node, 272 "samsung,dsim-config-s", 0); 273 274 dt->pll_stable_time = fdtdec_get_int(blob, node, 275 "samsung,dsim-config-pll-stable-time", 0); 276 277 dt->esc_clk = fdtdec_get_int(blob, node, 278 "samsung,dsim-config-esc-clk", 0); 279 280 dt->stop_holding_cnt = fdtdec_get_int(blob, node, 281 "samsung,dsim-config-stop-holding-cnt", 0); 282 283 dt->bta_timeout = fdtdec_get_int(blob, node, 284 "samsung,dsim-config-bta-timeout", 0); 285 286 dt->rx_timeout = fdtdec_get_int(blob, node, 287 "samsung,dsim-config-rx-timeout", 0); 288 289 lcd_dt->name = fdtdec_get_config_string(blob, 290 "samsung,dsim-device-name"); 291 292 lcd_dt->id = fdtdec_get_int(blob, node, 293 "samsung,dsim-device-id", 0); 294 295 lcd_dt->bus_id = fdtdec_get_int(blob, node, 296 "samsung,dsim-device-bus_id", 0); 297 298 lcd_dt->reverse_panel = fdtdec_get_int(blob, node, 299 "samsung,dsim-device-reverse-panel", 0); 300 301 return 0; 302 } 303 304 void exynos_init_dsim_platform_data(vidinfo_t *vid) 305 { 306 static struct mipi_dsim_config dsim_config_dt; 307 static struct exynos_platform_mipi_dsim dsim_platform_data_dt; 308 static struct mipi_dsim_lcd_device mipi_lcd_device_dt; 309 310 if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt, 311 &mipi_lcd_device_dt)) 312 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 323 vid->dsim_platform_data_dt = &dsim_platform_data_dt; 324 } 325