1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2012 Samsung Electronics 4 * 5 * Author: InKi Dae <inki.dae@samsung.com> 6 * Author: Donghwa Lee <dh09.lee@samsung.com> 7 */ 8 9 #include <common.h> 10 #include <malloc.h> 11 #include <fdtdec.h> 12 #include <linux/libfdt.h> 13 #include <linux/compat.h> 14 #include <linux/err.h> 15 #include <asm/arch/dsim.h> 16 #include <asm/arch/mipi_dsim.h> 17 #include <asm/arch/power.h> 18 #include <asm/arch/cpu.h> 19 #include <asm/arch/clk.h> 20 21 #include "exynos_mipi_dsi_lowlevel.h" 22 #include "exynos_mipi_dsi_common.h" 23 24 #define master_to_driver(a) (a->dsim_lcd_drv) 25 #define master_to_device(a) (a->dsim_lcd_dev) 26 27 DECLARE_GLOBAL_DATA_PTR; 28 29 struct mipi_dsim_ddi { 30 int bus_id; 31 struct list_head list; 32 struct mipi_dsim_lcd_device *dsim_lcd_dev; 33 struct mipi_dsim_lcd_driver *dsim_lcd_drv; 34 }; 35 36 static LIST_HEAD(dsim_ddi_list); 37 static LIST_HEAD(dsim_lcd_dev_list); 38 39 int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) 40 { 41 struct mipi_dsim_ddi *dsim_ddi; 42 43 if (!lcd_dev) { 44 debug("mipi_dsim_lcd_device is NULL.\n"); 45 return -EFAULT; 46 } 47 48 if (!lcd_dev->name) { 49 debug("dsim_lcd_device name is NULL.\n"); 50 return -EFAULT; 51 } 52 53 dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); 54 if (!dsim_ddi) { 55 debug("failed to allocate dsim_ddi object.\n"); 56 return -EFAULT; 57 } 58 59 dsim_ddi->dsim_lcd_dev = lcd_dev; 60 61 list_add_tail(&dsim_ddi->list, &dsim_ddi_list); 62 63 return 0; 64 } 65 66 struct mipi_dsim_ddi 67 *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) 68 { 69 struct mipi_dsim_ddi *dsim_ddi; 70 struct mipi_dsim_lcd_device *lcd_dev; 71 72 list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { 73 lcd_dev = dsim_ddi->dsim_lcd_dev; 74 if (!lcd_dev) 75 continue; 76 77 if (lcd_drv->id >= 0) { 78 if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 && 79 lcd_drv->id == lcd_dev->id) { 80 /** 81 * bus_id would be used to identify 82 * connected bus. 83 */ 84 dsim_ddi->bus_id = lcd_dev->bus_id; 85 86 return dsim_ddi; 87 } 88 } else { 89 if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { 90 /** 91 * bus_id would be used to identify 92 * connected bus. 93 */ 94 dsim_ddi->bus_id = lcd_dev->bus_id; 95 96 return dsim_ddi; 97 } 98 } 99 100 kfree(dsim_ddi); 101 list_del(&dsim_ddi_list); 102 } 103 104 return NULL; 105 } 106 107 int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) 108 { 109 struct mipi_dsim_ddi *dsim_ddi; 110 111 if (!lcd_drv) { 112 debug("mipi_dsim_lcd_driver is NULL.\n"); 113 return -EFAULT; 114 } 115 116 if (!lcd_drv->name) { 117 debug("dsim_lcd_driver name is NULL.\n"); 118 return -EFAULT; 119 } 120 121 dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv); 122 if (!dsim_ddi) { 123 debug("mipi_dsim_ddi object not found.\n"); 124 return -EFAULT; 125 } 126 127 dsim_ddi->dsim_lcd_drv = lcd_drv; 128 129 debug("registered panel driver(%s) to mipi-dsi driver.\n", 130 lcd_drv->name); 131 132 return 0; 133 134 } 135 136 struct mipi_dsim_ddi 137 *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, 138 const char *name) 139 { 140 struct mipi_dsim_ddi *dsim_ddi; 141 struct mipi_dsim_lcd_driver *lcd_drv; 142 struct mipi_dsim_lcd_device *lcd_dev; 143 144 list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { 145 lcd_drv = dsim_ddi->dsim_lcd_drv; 146 lcd_dev = dsim_ddi->dsim_lcd_dev; 147 if (!lcd_drv || !lcd_dev) 148 continue; 149 150 debug("lcd_drv->id = %d, lcd_dev->id = %d\n", 151 lcd_drv->id, lcd_dev->id); 152 153 if ((strcmp(lcd_drv->name, name) == 0)) { 154 lcd_dev->master = dsim; 155 156 dsim->dsim_lcd_dev = lcd_dev; 157 dsim->dsim_lcd_drv = lcd_drv; 158 159 return dsim_ddi; 160 } 161 } 162 163 return NULL; 164 } 165 166 /* define MIPI-DSI Master operations. */ 167 static struct mipi_dsim_master_ops master_ops = { 168 .cmd_write = exynos_mipi_dsi_wr_data, 169 .get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status, 170 .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done, 171 }; 172 173 int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd) 174 { 175 struct mipi_dsim_device *dsim; 176 struct mipi_dsim_config *dsim_config; 177 struct mipi_dsim_ddi *dsim_ddi; 178 179 dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); 180 if (!dsim) { 181 debug("failed to allocate dsim object.\n"); 182 return -EFAULT; 183 } 184 185 /* get mipi_dsim_config. */ 186 dsim_config = dsim_pd->dsim_config; 187 if (dsim_config == NULL) { 188 debug("failed to get dsim config data.\n"); 189 return -EFAULT; 190 } 191 192 dsim->pd = dsim_pd; 193 dsim->dsim_config = dsim_config; 194 dsim->master_ops = &master_ops; 195 196 /* bind lcd ddi matched with panel name. */ 197 dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); 198 if (!dsim_ddi) { 199 debug("mipi_dsim_ddi object not found.\n"); 200 return -ENOSYS; 201 } 202 if (dsim_pd->lcd_power) 203 dsim_pd->lcd_power(); 204 205 if (dsim_pd->mipi_power) 206 dsim_pd->mipi_power(); 207 208 /* phy_enable(unsigned int dev_index, unsigned int enable) */ 209 if (dsim_pd->phy_enable) 210 dsim_pd->phy_enable(0, 1); 211 212 set_mipi_clk(); 213 214 exynos_mipi_dsi_init_dsim(dsim); 215 exynos_mipi_dsi_init_link(dsim); 216 exynos_mipi_dsi_set_hs_enable(dsim); 217 218 /* set display timing. */ 219 exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); 220 221 /* initialize mipi-dsi client(lcd panel). */ 222 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) { 223 dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim); 224 dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim); 225 } 226 227 debug("mipi-dsi driver(%s mode) has been probed.\n", 228 (dsim_config->e_interface == DSIM_COMMAND) ? 229 "CPU" : "RGB"); 230 231 return 0; 232 } 233 234 int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt, 235 struct mipi_dsim_lcd_device *lcd_dt) 236 { 237 int node; 238 239 node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_MIPI_DSI); 240 if (node <= 0) { 241 printf("exynos_mipi_dsi: Can't get device node for mipi dsi\n"); 242 return -ENODEV; 243 } 244 245 dt->e_interface = fdtdec_get_int(blob, node, 246 "samsung,dsim-config-e-interface", 0); 247 248 dt->e_virtual_ch = fdtdec_get_int(blob, node, 249 "samsung,dsim-config-e-virtual-ch", 0); 250 251 dt->e_pixel_format = fdtdec_get_int(blob, node, 252 "samsung,dsim-config-e-pixel-format", 0); 253 254 dt->e_burst_mode = fdtdec_get_int(blob, node, 255 "samsung,dsim-config-e-burst-mode", 0); 256 257 dt->e_no_data_lane = fdtdec_get_int(blob, node, 258 "samsung,dsim-config-e-no-data-lane", 0); 259 260 dt->e_byte_clk = fdtdec_get_int(blob, node, 261 "samsung,dsim-config-e-byte-clk", 0); 262 263 dt->hfp = fdtdec_get_int(blob, node, 264 "samsung,dsim-config-hfp", 0); 265 266 dt->p = fdtdec_get_int(blob, node, 267 "samsung,dsim-config-p", 0); 268 dt->m = fdtdec_get_int(blob, node, 269 "samsung,dsim-config-m", 0); 270 dt->s = fdtdec_get_int(blob, node, 271 "samsung,dsim-config-s", 0); 272 273 dt->pll_stable_time = fdtdec_get_int(blob, node, 274 "samsung,dsim-config-pll-stable-time", 0); 275 276 dt->esc_clk = fdtdec_get_int(blob, node, 277 "samsung,dsim-config-esc-clk", 0); 278 279 dt->stop_holding_cnt = fdtdec_get_int(blob, node, 280 "samsung,dsim-config-stop-holding-cnt", 0); 281 282 dt->bta_timeout = fdtdec_get_int(blob, node, 283 "samsung,dsim-config-bta-timeout", 0); 284 285 dt->rx_timeout = fdtdec_get_int(blob, node, 286 "samsung,dsim-config-rx-timeout", 0); 287 288 lcd_dt->name = fdtdec_get_config_string(blob, 289 "samsung,dsim-device-name"); 290 291 lcd_dt->id = fdtdec_get_int(blob, node, 292 "samsung,dsim-device-id", 0); 293 294 lcd_dt->bus_id = fdtdec_get_int(blob, node, 295 "samsung,dsim-device-bus_id", 0); 296 297 lcd_dt->reverse_panel = fdtdec_get_int(blob, node, 298 "samsung,dsim-device-reverse-panel", 0); 299 300 return 0; 301 } 302 303 void exynos_init_dsim_platform_data(vidinfo_t *vid) 304 { 305 static struct mipi_dsim_config dsim_config_dt; 306 static struct exynos_platform_mipi_dsim dsim_platform_data_dt; 307 static struct mipi_dsim_lcd_device mipi_lcd_device_dt; 308 309 if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt, 310 &mipi_lcd_device_dt)) 311 debug("Can't get proper dsim config.\n"); 312 313 strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name); 314 dsim_platform_data_dt.dsim_config = &dsim_config_dt; 315 dsim_platform_data_dt.mipi_power = mipi_power; 316 dsim_platform_data_dt.phy_enable = set_mipi_phy_ctrl; 317 dsim_platform_data_dt.lcd_panel_info = (void *)vid; 318 319 mipi_lcd_device_dt.platform_data = (void *)&dsim_platform_data_dt; 320 exynos_mipi_dsi_register_lcd_device(&mipi_lcd_device_dt); 321 322 vid->dsim_platform_data_dt = &dsim_platform_data_dt; 323 } 324