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-panasonic-vvx10f034n00.c (6676B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2015 Red Hat
      4 * Copyright (C) 2015 Sony Mobile Communications Inc.
      5 * Author: Werner Johansson <werner.johansson@sonymobile.com>
      6 *
      7 * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
      8 */
      9
     10#include <linux/delay.h>
     11#include <linux/module.h>
     12#include <linux/of.h>
     13#include <linux/regulator/consumer.h>
     14
     15#include <video/mipi_display.h>
     16
     17#include <drm/drm_crtc.h>
     18#include <drm/drm_device.h>
     19#include <drm/drm_mipi_dsi.h>
     20#include <drm/drm_panel.h>
     21
     22/*
     23 * When power is turned off to this panel a minimum off time of 500ms has to be
     24 * observed before powering back on as there's no external reset pin. Keep
     25 * track of earliest wakeup time and delay subsequent prepare call accordingly
     26 */
     27#define MIN_POFF_MS (500)
     28
     29struct wuxga_nt_panel {
     30	struct drm_panel base;
     31	struct mipi_dsi_device *dsi;
     32
     33	struct regulator *supply;
     34
     35	bool prepared;
     36	bool enabled;
     37
     38	ktime_t earliest_wake;
     39
     40	const struct drm_display_mode *mode;
     41};
     42
     43static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)
     44{
     45	return container_of(panel, struct wuxga_nt_panel, base);
     46}
     47
     48static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)
     49{
     50	return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi);
     51}
     52
     53static int wuxga_nt_panel_disable(struct drm_panel *panel)
     54{
     55	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
     56	int mipi_ret, bl_ret = 0;
     57
     58	if (!wuxga_nt->enabled)
     59		return 0;
     60
     61	mipi_ret = mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
     62
     63	wuxga_nt->enabled = false;
     64
     65	return mipi_ret ? mipi_ret : bl_ret;
     66}
     67
     68static int wuxga_nt_panel_unprepare(struct drm_panel *panel)
     69{
     70	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
     71
     72	if (!wuxga_nt->prepared)
     73		return 0;
     74
     75	regulator_disable(wuxga_nt->supply);
     76	wuxga_nt->earliest_wake = ktime_add_ms(ktime_get_real(), MIN_POFF_MS);
     77	wuxga_nt->prepared = false;
     78
     79	return 0;
     80}
     81
     82static int wuxga_nt_panel_prepare(struct drm_panel *panel)
     83{
     84	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
     85	int ret;
     86	s64 enablewait;
     87
     88	if (wuxga_nt->prepared)
     89		return 0;
     90
     91	/*
     92	 * If the user re-enabled the panel before the required off-time then
     93	 * we need to wait the remaining period before re-enabling regulator
     94	 */
     95	enablewait = ktime_ms_delta(wuxga_nt->earliest_wake, ktime_get_real());
     96
     97	/* Sanity check, this should never happen */
     98	if (enablewait > MIN_POFF_MS)
     99		enablewait = MIN_POFF_MS;
    100
    101	if (enablewait > 0)
    102		msleep(enablewait);
    103
    104	ret = regulator_enable(wuxga_nt->supply);
    105	if (ret < 0)
    106		return ret;
    107
    108	/*
    109	 * A minimum delay of 250ms is required after power-up until commands
    110	 * can be sent
    111	 */
    112	msleep(250);
    113
    114	ret = wuxga_nt_panel_on(wuxga_nt);
    115	if (ret < 0) {
    116		dev_err(panel->dev, "failed to set panel on: %d\n", ret);
    117		goto poweroff;
    118	}
    119
    120	wuxga_nt->prepared = true;
    121
    122	return 0;
    123
    124poweroff:
    125	regulator_disable(wuxga_nt->supply);
    126
    127	return ret;
    128}
    129
    130static int wuxga_nt_panel_enable(struct drm_panel *panel)
    131{
    132	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
    133
    134	if (wuxga_nt->enabled)
    135		return 0;
    136
    137	wuxga_nt->enabled = true;
    138
    139	return 0;
    140}
    141
    142static const struct drm_display_mode default_mode = {
    143	.clock = 164402,
    144	.hdisplay = 1920,
    145	.hsync_start = 1920 + 152,
    146	.hsync_end = 1920 + 152 + 52,
    147	.htotal = 1920 + 152 + 52 + 20,
    148	.vdisplay = 1200,
    149	.vsync_start = 1200 + 24,
    150	.vsync_end = 1200 + 24 + 6,
    151	.vtotal = 1200 + 24 + 6 + 48,
    152};
    153
    154static int wuxga_nt_panel_get_modes(struct drm_panel *panel,
    155				    struct drm_connector *connector)
    156{
    157	struct drm_display_mode *mode;
    158
    159	mode = drm_mode_duplicate(connector->dev, &default_mode);
    160	if (!mode) {
    161		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
    162			default_mode.hdisplay, default_mode.vdisplay,
    163			drm_mode_vrefresh(&default_mode));
    164		return -ENOMEM;
    165	}
    166
    167	drm_mode_set_name(mode);
    168
    169	drm_mode_probed_add(connector, mode);
    170
    171	connector->display_info.width_mm = 217;
    172	connector->display_info.height_mm = 136;
    173
    174	return 1;
    175}
    176
    177static const struct drm_panel_funcs wuxga_nt_panel_funcs = {
    178	.disable = wuxga_nt_panel_disable,
    179	.unprepare = wuxga_nt_panel_unprepare,
    180	.prepare = wuxga_nt_panel_prepare,
    181	.enable = wuxga_nt_panel_enable,
    182	.get_modes = wuxga_nt_panel_get_modes,
    183};
    184
    185static const struct of_device_id wuxga_nt_of_match[] = {
    186	{ .compatible = "panasonic,vvx10f034n00", },
    187	{ }
    188};
    189MODULE_DEVICE_TABLE(of, wuxga_nt_of_match);
    190
    191static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)
    192{
    193	struct device *dev = &wuxga_nt->dsi->dev;
    194	int ret;
    195
    196	wuxga_nt->mode = &default_mode;
    197
    198	wuxga_nt->supply = devm_regulator_get(dev, "power");
    199	if (IS_ERR(wuxga_nt->supply))
    200		return PTR_ERR(wuxga_nt->supply);
    201
    202	drm_panel_init(&wuxga_nt->base, &wuxga_nt->dsi->dev,
    203		       &wuxga_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
    204
    205	ret = drm_panel_of_backlight(&wuxga_nt->base);
    206	if (ret)
    207		return ret;
    208
    209	drm_panel_add(&wuxga_nt->base);
    210
    211	return 0;
    212}
    213
    214static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)
    215{
    216	if (wuxga_nt->base.dev)
    217		drm_panel_remove(&wuxga_nt->base);
    218}
    219
    220static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi)
    221{
    222	struct wuxga_nt_panel *wuxga_nt;
    223	int ret;
    224
    225	dsi->lanes = 4;
    226	dsi->format = MIPI_DSI_FMT_RGB888;
    227	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
    228			MIPI_DSI_MODE_VIDEO_HSE |
    229			MIPI_DSI_CLOCK_NON_CONTINUOUS |
    230			MIPI_DSI_MODE_LPM;
    231
    232	wuxga_nt = devm_kzalloc(&dsi->dev, sizeof(*wuxga_nt), GFP_KERNEL);
    233	if (!wuxga_nt)
    234		return -ENOMEM;
    235
    236	mipi_dsi_set_drvdata(dsi, wuxga_nt);
    237
    238	wuxga_nt->dsi = dsi;
    239
    240	ret = wuxga_nt_panel_add(wuxga_nt);
    241	if (ret < 0)
    242		return ret;
    243
    244	ret = mipi_dsi_attach(dsi);
    245	if (ret < 0) {
    246		wuxga_nt_panel_del(wuxga_nt);
    247		return ret;
    248	}
    249
    250	return 0;
    251}
    252
    253static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi)
    254{
    255	struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
    256	int ret;
    257
    258	ret = drm_panel_disable(&wuxga_nt->base);
    259	if (ret < 0)
    260		dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
    261
    262	ret = mipi_dsi_detach(dsi);
    263	if (ret < 0)
    264		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
    265
    266	wuxga_nt_panel_del(wuxga_nt);
    267
    268	return 0;
    269}
    270
    271static void wuxga_nt_panel_shutdown(struct mipi_dsi_device *dsi)
    272{
    273	struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
    274
    275	drm_panel_disable(&wuxga_nt->base);
    276}
    277
    278static struct mipi_dsi_driver wuxga_nt_panel_driver = {
    279	.driver = {
    280		.name = "panel-panasonic-vvx10f034n00",
    281		.of_match_table = wuxga_nt_of_match,
    282	},
    283	.probe = wuxga_nt_panel_probe,
    284	.remove = wuxga_nt_panel_remove,
    285	.shutdown = wuxga_nt_panel_shutdown,
    286};
    287module_mipi_dsi_driver(wuxga_nt_panel_driver);
    288
    289MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
    290MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");
    291MODULE_LICENSE("GPL v2");