cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel-dsi-cm.c (14498B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Generic DSI Command Mode panel driver
      4 *
      5 * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/
      6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
      7 */
      8
      9#include <linux/backlight.h>
     10#include <linux/delay.h>
     11#include <linux/gpio/consumer.h>
     12#include <linux/jiffies.h>
     13#include <linux/module.h>
     14#include <linux/of_device.h>
     15#include <linux/regulator/consumer.h>
     16
     17#include <drm/drm_connector.h>
     18#include <drm/drm_mipi_dsi.h>
     19#include <drm/drm_modes.h>
     20#include <drm/drm_panel.h>
     21
     22#include <video/mipi_display.h>
     23
     24#define DCS_GET_ID1		0xda
     25#define DCS_GET_ID2		0xdb
     26#define DCS_GET_ID3		0xdc
     27
     28#define DCS_REGULATOR_SUPPLY_NUM 2
     29
     30static const struct of_device_id dsicm_of_match[];
     31
     32struct dsic_panel_data {
     33	u32 xres;
     34	u32 yres;
     35	u32 refresh;
     36	u32 width_mm;
     37	u32 height_mm;
     38	u32 max_hs_rate;
     39	u32 max_lp_rate;
     40	bool te_support;
     41};
     42
     43struct panel_drv_data {
     44	struct mipi_dsi_device *dsi;
     45	struct drm_panel panel;
     46	struct drm_display_mode mode;
     47
     48	struct mutex lock;
     49
     50	struct backlight_device *bldev;
     51	struct backlight_device *extbldev;
     52
     53	unsigned long	hw_guard_end;	/* next value of jiffies when we can
     54					 * issue the next sleep in/out command
     55					 */
     56	unsigned long	hw_guard_wait;	/* max guard time in jiffies */
     57
     58	const struct dsic_panel_data *panel_data;
     59
     60	struct gpio_desc *reset_gpio;
     61
     62	struct regulator_bulk_data supplies[DCS_REGULATOR_SUPPLY_NUM];
     63
     64	bool use_dsi_backlight;
     65
     66	/* runtime variables */
     67	bool enabled;
     68
     69	bool intro_printed;
     70};
     71
     72static inline struct panel_drv_data *panel_to_ddata(struct drm_panel *panel)
     73{
     74	return container_of(panel, struct panel_drv_data, panel);
     75}
     76
     77static void dsicm_bl_power(struct panel_drv_data *ddata, bool enable)
     78{
     79	struct backlight_device *backlight;
     80
     81	if (ddata->bldev)
     82		backlight = ddata->bldev;
     83	else if (ddata->extbldev)
     84		backlight = ddata->extbldev;
     85	else
     86		return;
     87
     88	if (enable) {
     89		backlight->props.fb_blank = FB_BLANK_UNBLANK;
     90		backlight->props.state = ~(BL_CORE_FBBLANK | BL_CORE_SUSPENDED);
     91		backlight->props.power = FB_BLANK_UNBLANK;
     92	} else {
     93		backlight->props.fb_blank = FB_BLANK_NORMAL;
     94		backlight->props.power = FB_BLANK_POWERDOWN;
     95		backlight->props.state |= BL_CORE_FBBLANK | BL_CORE_SUSPENDED;
     96	}
     97
     98	backlight_update_status(backlight);
     99}
    100
    101static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
    102{
    103	ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
    104	ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
    105}
    106
    107static void hw_guard_wait(struct panel_drv_data *ddata)
    108{
    109	unsigned long wait = ddata->hw_guard_end - jiffies;
    110
    111	if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
    112		set_current_state(TASK_UNINTERRUPTIBLE);
    113		schedule_timeout(wait);
    114	}
    115}
    116
    117static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
    118{
    119	return mipi_dsi_dcs_read(ddata->dsi, dcs_cmd, data, 1);
    120}
    121
    122static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
    123{
    124	return mipi_dsi_dcs_write(ddata->dsi, dcs_cmd, &param, 1);
    125}
    126
    127static int dsicm_sleep_in(struct panel_drv_data *ddata)
    128
    129{
    130	int r;
    131
    132	hw_guard_wait(ddata);
    133
    134	r = mipi_dsi_dcs_enter_sleep_mode(ddata->dsi);
    135	if (r)
    136		return r;
    137
    138	hw_guard_start(ddata, 120);
    139
    140	usleep_range(5000, 10000);
    141
    142	return 0;
    143}
    144
    145static int dsicm_sleep_out(struct panel_drv_data *ddata)
    146{
    147	int r;
    148
    149	hw_guard_wait(ddata);
    150
    151	r = mipi_dsi_dcs_exit_sleep_mode(ddata->dsi);
    152	if (r)
    153		return r;
    154
    155	hw_guard_start(ddata, 120);
    156
    157	usleep_range(5000, 10000);
    158
    159	return 0;
    160}
    161
    162static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
    163{
    164	int r;
    165
    166	r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);
    167	if (r)
    168		return r;
    169	r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);
    170	if (r)
    171		return r;
    172	r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);
    173	if (r)
    174		return r;
    175
    176	return 0;
    177}
    178
    179static int dsicm_set_update_window(struct panel_drv_data *ddata)
    180{
    181	struct mipi_dsi_device *dsi = ddata->dsi;
    182	int r;
    183
    184	r = mipi_dsi_dcs_set_column_address(dsi, 0, ddata->mode.hdisplay - 1);
    185	if (r < 0)
    186		return r;
    187
    188	r = mipi_dsi_dcs_set_page_address(dsi, 0, ddata->mode.vdisplay - 1);
    189	if (r < 0)
    190		return r;
    191
    192	return 0;
    193}
    194
    195static int dsicm_bl_update_status(struct backlight_device *dev)
    196{
    197	struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
    198	int r = 0;
    199	int level;
    200
    201	if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
    202			dev->props.power == FB_BLANK_UNBLANK)
    203		level = dev->props.brightness;
    204	else
    205		level = 0;
    206
    207	dev_dbg(&ddata->dsi->dev, "update brightness to %d\n", level);
    208
    209	mutex_lock(&ddata->lock);
    210
    211	if (ddata->enabled)
    212		r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
    213				      level);
    214
    215	mutex_unlock(&ddata->lock);
    216
    217	return r;
    218}
    219
    220static int dsicm_bl_get_intensity(struct backlight_device *dev)
    221{
    222	if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
    223			dev->props.power == FB_BLANK_UNBLANK)
    224		return dev->props.brightness;
    225
    226	return 0;
    227}
    228
    229static const struct backlight_ops dsicm_bl_ops = {
    230	.get_brightness = dsicm_bl_get_intensity,
    231	.update_status  = dsicm_bl_update_status,
    232};
    233
    234static ssize_t num_dsi_errors_show(struct device *dev,
    235		struct device_attribute *attr, char *buf)
    236{
    237	struct panel_drv_data *ddata = dev_get_drvdata(dev);
    238	u8 errors = 0;
    239	int r = -ENODEV;
    240
    241	mutex_lock(&ddata->lock);
    242
    243	if (ddata->enabled)
    244		r = dsicm_dcs_read_1(ddata, MIPI_DCS_GET_ERROR_COUNT_ON_DSI, &errors);
    245
    246	mutex_unlock(&ddata->lock);
    247
    248	if (r)
    249		return r;
    250
    251	return sysfs_emit(buf, "%d\n", errors);
    252}
    253
    254static ssize_t hw_revision_show(struct device *dev,
    255		struct device_attribute *attr, char *buf)
    256{
    257	struct panel_drv_data *ddata = dev_get_drvdata(dev);
    258	u8 id1, id2, id3;
    259	int r = -ENODEV;
    260
    261	mutex_lock(&ddata->lock);
    262
    263	if (ddata->enabled)
    264		r = dsicm_get_id(ddata, &id1, &id2, &id3);
    265
    266	mutex_unlock(&ddata->lock);
    267
    268	if (r)
    269		return r;
    270
    271	return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3);
    272}
    273
    274static DEVICE_ATTR_RO(num_dsi_errors);
    275static DEVICE_ATTR_RO(hw_revision);
    276
    277static struct attribute *dsicm_attrs[] = {
    278	&dev_attr_num_dsi_errors.attr,
    279	&dev_attr_hw_revision.attr,
    280	NULL,
    281};
    282
    283static const struct attribute_group dsicm_attr_group = {
    284	.attrs = dsicm_attrs,
    285};
    286
    287static void dsicm_hw_reset(struct panel_drv_data *ddata)
    288{
    289	gpiod_set_value(ddata->reset_gpio, 1);
    290	udelay(10);
    291	/* reset the panel */
    292	gpiod_set_value(ddata->reset_gpio, 0);
    293	/* assert reset */
    294	udelay(10);
    295	gpiod_set_value(ddata->reset_gpio, 1);
    296	/* wait after releasing reset */
    297	usleep_range(5000, 10000);
    298}
    299
    300static int dsicm_power_on(struct panel_drv_data *ddata)
    301{
    302	u8 id1, id2, id3;
    303	int r;
    304
    305	dsicm_hw_reset(ddata);
    306
    307	ddata->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
    308
    309	r = dsicm_sleep_out(ddata);
    310	if (r)
    311		goto err;
    312
    313	r = dsicm_get_id(ddata, &id1, &id2, &id3);
    314	if (r)
    315		goto err;
    316
    317	r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0xff);
    318	if (r)
    319		goto err;
    320
    321	r = dsicm_dcs_write_1(ddata, MIPI_DCS_WRITE_CONTROL_DISPLAY,
    322			(1<<2) | (1<<5));	/* BL | BCTRL */
    323	if (r)
    324		goto err;
    325
    326	r = mipi_dsi_dcs_set_pixel_format(ddata->dsi, MIPI_DCS_PIXEL_FMT_24BIT);
    327	if (r)
    328		goto err;
    329
    330	r = dsicm_set_update_window(ddata);
    331	if (r)
    332		goto err;
    333
    334	r = mipi_dsi_dcs_set_display_on(ddata->dsi);
    335	if (r)
    336		goto err;
    337
    338	if (ddata->panel_data->te_support) {
    339		r = mipi_dsi_dcs_set_tear_on(ddata->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
    340		if (r)
    341			goto err;
    342	}
    343
    344	/* possible panel bug */
    345	msleep(100);
    346
    347	ddata->enabled = true;
    348
    349	if (!ddata->intro_printed) {
    350		dev_info(&ddata->dsi->dev, "panel revision %02x.%02x.%02x\n",
    351			id1, id2, id3);
    352		ddata->intro_printed = true;
    353	}
    354
    355	ddata->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    356
    357	return 0;
    358err:
    359	dev_err(&ddata->dsi->dev, "error while enabling panel, issuing HW reset\n");
    360
    361	dsicm_hw_reset(ddata);
    362
    363	return r;
    364}
    365
    366static int dsicm_power_off(struct panel_drv_data *ddata)
    367{
    368	int r;
    369
    370	ddata->enabled = false;
    371
    372	r = mipi_dsi_dcs_set_display_off(ddata->dsi);
    373	if (!r)
    374		r = dsicm_sleep_in(ddata);
    375
    376	if (r) {
    377		dev_err(&ddata->dsi->dev,
    378				"error disabling panel, issuing HW reset\n");
    379		dsicm_hw_reset(ddata);
    380	}
    381
    382	return r;
    383}
    384
    385static int dsicm_prepare(struct drm_panel *panel)
    386{
    387	struct panel_drv_data *ddata = panel_to_ddata(panel);
    388	int r;
    389
    390	r = regulator_bulk_enable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
    391	if (r)
    392		dev_err(&ddata->dsi->dev, "failed to enable supplies: %d\n", r);
    393
    394	return r;
    395}
    396
    397static int dsicm_enable(struct drm_panel *panel)
    398{
    399	struct panel_drv_data *ddata = panel_to_ddata(panel);
    400	int r;
    401
    402	mutex_lock(&ddata->lock);
    403
    404	r = dsicm_power_on(ddata);
    405	if (r)
    406		goto err;
    407
    408	mutex_unlock(&ddata->lock);
    409
    410	dsicm_bl_power(ddata, true);
    411
    412	return 0;
    413err:
    414	dev_err(&ddata->dsi->dev, "enable failed (%d)\n", r);
    415	mutex_unlock(&ddata->lock);
    416	return r;
    417}
    418
    419static int dsicm_unprepare(struct drm_panel *panel)
    420{
    421	struct panel_drv_data *ddata = panel_to_ddata(panel);
    422	int r;
    423
    424	r = regulator_bulk_disable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
    425	if (r)
    426		dev_err(&ddata->dsi->dev, "failed to disable supplies: %d\n", r);
    427
    428	return r;
    429}
    430
    431static int dsicm_disable(struct drm_panel *panel)
    432{
    433	struct panel_drv_data *ddata = panel_to_ddata(panel);
    434	int r;
    435
    436	dsicm_bl_power(ddata, false);
    437
    438	mutex_lock(&ddata->lock);
    439
    440	r = dsicm_power_off(ddata);
    441
    442	mutex_unlock(&ddata->lock);
    443
    444	return r;
    445}
    446
    447static int dsicm_get_modes(struct drm_panel *panel,
    448			   struct drm_connector *connector)
    449{
    450	struct panel_drv_data *ddata = panel_to_ddata(panel);
    451	struct drm_display_mode *mode;
    452
    453	mode = drm_mode_duplicate(connector->dev, &ddata->mode);
    454	if (!mode) {
    455		dev_err(&ddata->dsi->dev, "failed to add mode %ux%ux@%u kHz\n",
    456			ddata->mode.hdisplay, ddata->mode.vdisplay,
    457			ddata->mode.clock);
    458		return -ENOMEM;
    459	}
    460
    461	connector->display_info.width_mm = ddata->panel_data->width_mm;
    462	connector->display_info.height_mm = ddata->panel_data->height_mm;
    463
    464	drm_mode_probed_add(connector, mode);
    465
    466	return 1;
    467}
    468
    469static const struct drm_panel_funcs dsicm_panel_funcs = {
    470	.unprepare = dsicm_unprepare,
    471	.disable = dsicm_disable,
    472	.prepare = dsicm_prepare,
    473	.enable = dsicm_enable,
    474	.get_modes = dsicm_get_modes,
    475};
    476
    477static int dsicm_probe_of(struct mipi_dsi_device *dsi)
    478{
    479	struct backlight_device *backlight;
    480	struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
    481	int err;
    482	struct drm_display_mode *mode = &ddata->mode;
    483
    484	ddata->reset_gpio = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
    485	if (IS_ERR(ddata->reset_gpio)) {
    486		err = PTR_ERR(ddata->reset_gpio);
    487		dev_err(&dsi->dev, "reset gpio request failed: %d", err);
    488		return err;
    489	}
    490
    491	mode->hdisplay = mode->hsync_start = mode->hsync_end = mode->htotal =
    492		ddata->panel_data->xres;
    493	mode->vdisplay = mode->vsync_start = mode->vsync_end = mode->vtotal =
    494		ddata->panel_data->yres;
    495	mode->clock = ddata->panel_data->xres * ddata->panel_data->yres *
    496		ddata->panel_data->refresh / 1000;
    497	mode->width_mm = ddata->panel_data->width_mm;
    498	mode->height_mm = ddata->panel_data->height_mm;
    499	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    500	drm_mode_set_name(mode);
    501
    502	ddata->supplies[0].supply = "vpnl";
    503	ddata->supplies[1].supply = "vddi";
    504	err = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ddata->supplies),
    505				      ddata->supplies);
    506	if (err)
    507		return err;
    508
    509	backlight = devm_of_find_backlight(&dsi->dev);
    510	if (IS_ERR(backlight))
    511		return PTR_ERR(backlight);
    512
    513	/* If no backlight device is found assume native backlight support */
    514	if (backlight)
    515		ddata->extbldev = backlight;
    516	else
    517		ddata->use_dsi_backlight = true;
    518
    519	return 0;
    520}
    521
    522static int dsicm_probe(struct mipi_dsi_device *dsi)
    523{
    524	struct panel_drv_data *ddata;
    525	struct backlight_device *bldev = NULL;
    526	struct device *dev = &dsi->dev;
    527	int r;
    528
    529	dev_dbg(dev, "probe\n");
    530
    531	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
    532	if (!ddata)
    533		return -ENOMEM;
    534
    535	mipi_dsi_set_drvdata(dsi, ddata);
    536	ddata->dsi = dsi;
    537
    538	ddata->panel_data = of_device_get_match_data(dev);
    539	if (!ddata->panel_data)
    540		return -ENODEV;
    541
    542	r = dsicm_probe_of(dsi);
    543	if (r)
    544		return r;
    545
    546	mutex_init(&ddata->lock);
    547
    548	dsicm_hw_reset(ddata);
    549
    550	drm_panel_init(&ddata->panel, dev, &dsicm_panel_funcs,
    551		       DRM_MODE_CONNECTOR_DSI);
    552
    553	if (ddata->use_dsi_backlight) {
    554		struct backlight_properties props = { 0 };
    555		props.max_brightness = 255;
    556		props.type = BACKLIGHT_RAW;
    557
    558		bldev = devm_backlight_device_register(dev, dev_name(dev),
    559			dev, ddata, &dsicm_bl_ops, &props);
    560		if (IS_ERR(bldev)) {
    561			r = PTR_ERR(bldev);
    562			goto err_bl;
    563		}
    564
    565		ddata->bldev = bldev;
    566	}
    567
    568	r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);
    569	if (r) {
    570		dev_err(dev, "failed to create sysfs files\n");
    571		goto err_bl;
    572	}
    573
    574	dsi->lanes = 2;
    575	dsi->format = MIPI_DSI_FMT_RGB888;
    576	dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
    577			  MIPI_DSI_MODE_NO_EOT_PACKET;
    578	dsi->hs_rate = ddata->panel_data->max_hs_rate;
    579	dsi->lp_rate = ddata->panel_data->max_lp_rate;
    580
    581	drm_panel_add(&ddata->panel);
    582
    583	r = mipi_dsi_attach(dsi);
    584	if (r < 0)
    585		goto err_dsi_attach;
    586
    587	return 0;
    588
    589err_dsi_attach:
    590	drm_panel_remove(&ddata->panel);
    591	sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);
    592err_bl:
    593	if (ddata->extbldev)
    594		put_device(&ddata->extbldev->dev);
    595
    596	return r;
    597}
    598
    599static int dsicm_remove(struct mipi_dsi_device *dsi)
    600{
    601	struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
    602
    603	dev_dbg(&dsi->dev, "remove\n");
    604
    605	mipi_dsi_detach(dsi);
    606
    607	drm_panel_remove(&ddata->panel);
    608
    609	sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);
    610
    611	if (ddata->extbldev)
    612		put_device(&ddata->extbldev->dev);
    613
    614	return 0;
    615}
    616
    617static const struct dsic_panel_data taal_data = {
    618	.xres = 864,
    619	.yres = 480,
    620	.refresh = 60,
    621	.width_mm = 0,
    622	.height_mm = 0,
    623	.max_hs_rate = 300000000,
    624	.max_lp_rate = 10000000,
    625	.te_support = true,
    626};
    627
    628static const struct dsic_panel_data himalaya_data = {
    629	.xres = 480,
    630	.yres = 864,
    631	.refresh = 60,
    632	.width_mm = 49,
    633	.height_mm = 88,
    634	.max_hs_rate = 300000000,
    635	.max_lp_rate = 10000000,
    636	.te_support = false,
    637};
    638
    639static const struct dsic_panel_data droid4_data = {
    640	.xres = 540,
    641	.yres = 960,
    642	.refresh = 60,
    643	.width_mm = 50,
    644	.height_mm = 89,
    645	.max_hs_rate = 300000000,
    646	.max_lp_rate = 10000000,
    647	.te_support = false,
    648};
    649
    650static const struct of_device_id dsicm_of_match[] = {
    651	{ .compatible = "tpo,taal", .data = &taal_data },
    652	{ .compatible = "nokia,himalaya", &himalaya_data },
    653	{ .compatible = "motorola,droid4-panel", &droid4_data },
    654	{},
    655};
    656
    657MODULE_DEVICE_TABLE(of, dsicm_of_match);
    658
    659static struct mipi_dsi_driver dsicm_driver = {
    660	.probe = dsicm_probe,
    661	.remove = dsicm_remove,
    662	.driver = {
    663		.name = "panel-dsi-cm",
    664		.of_match_table = dsicm_of_match,
    665	},
    666};
    667module_mipi_dsi_driver(dsicm_driver);
    668
    669MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
    670MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");
    671MODULE_LICENSE("GPL");