Home | History | Annotate | Download | only in exynos
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2012 Samsung Electronics
      4  *
      5  * Author: InKi Dae <inki.dae (at) samsung.com>
      6  * Author: Donghwa Lee <dh09.lee (at) 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