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-samsung-sofef00.c (8595B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Copyright (c) 2020 Caleb Connolly <caleb@connolly.tech>
      3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
      4 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
      5 */
      6
      7#include <linux/delay.h>
      8#include <linux/gpio/consumer.h>
      9#include <linux/module.h>
     10#include <linux/of.h>
     11#include <linux/of_device.h>
     12#include <linux/regulator/consumer.h>
     13#include <linux/swab.h>
     14#include <linux/backlight.h>
     15
     16#include <video/mipi_display.h>
     17
     18#include <drm/drm_mipi_dsi.h>
     19#include <drm/drm_modes.h>
     20#include <drm/drm_panel.h>
     21
     22struct sofef00_panel {
     23	struct drm_panel panel;
     24	struct mipi_dsi_device *dsi;
     25	struct regulator *supply;
     26	struct gpio_desc *reset_gpio;
     27	const struct drm_display_mode *mode;
     28	bool prepared;
     29};
     30
     31static inline
     32struct sofef00_panel *to_sofef00_panel(struct drm_panel *panel)
     33{
     34	return container_of(panel, struct sofef00_panel, panel);
     35}
     36
     37#define dsi_dcs_write_seq(dsi, seq...) do {				\
     38		static const u8 d[] = { seq };				\
     39		int ret;						\
     40		ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d));	\
     41		if (ret < 0)						\
     42			return ret;					\
     43	} while (0)
     44
     45static void sofef00_panel_reset(struct sofef00_panel *ctx)
     46{
     47	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
     48	usleep_range(5000, 6000);
     49	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
     50	usleep_range(2000, 3000);
     51	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
     52	usleep_range(12000, 13000);
     53}
     54
     55static int sofef00_panel_on(struct sofef00_panel *ctx)
     56{
     57	struct mipi_dsi_device *dsi = ctx->dsi;
     58	struct device *dev = &dsi->dev;
     59	int ret;
     60
     61	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
     62
     63	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
     64	if (ret < 0) {
     65		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
     66		return ret;
     67	}
     68	usleep_range(10000, 11000);
     69
     70	dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
     71
     72	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
     73	if (ret < 0) {
     74		dev_err(dev, "Failed to set tear on: %d\n", ret);
     75		return ret;
     76	}
     77
     78	dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
     79	dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
     80	dsi_dcs_write_seq(dsi, 0xb0, 0x07);
     81	dsi_dcs_write_seq(dsi, 0xb6, 0x12);
     82	dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
     83	dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
     84	dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
     85
     86	ret = mipi_dsi_dcs_set_display_on(dsi);
     87	if (ret < 0) {
     88		dev_err(dev, "Failed to set display on: %d\n", ret);
     89		return ret;
     90	}
     91
     92	return 0;
     93}
     94
     95static int sofef00_panel_off(struct sofef00_panel *ctx)
     96{
     97	struct mipi_dsi_device *dsi = ctx->dsi;
     98	struct device *dev = &dsi->dev;
     99	int ret;
    100
    101	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    102
    103	ret = mipi_dsi_dcs_set_display_off(dsi);
    104	if (ret < 0) {
    105		dev_err(dev, "Failed to set display off: %d\n", ret);
    106		return ret;
    107	}
    108	msleep(40);
    109
    110	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
    111	if (ret < 0) {
    112		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
    113		return ret;
    114	}
    115	msleep(160);
    116
    117	return 0;
    118}
    119
    120static int sofef00_panel_prepare(struct drm_panel *panel)
    121{
    122	struct sofef00_panel *ctx = to_sofef00_panel(panel);
    123	struct device *dev = &ctx->dsi->dev;
    124	int ret;
    125
    126	if (ctx->prepared)
    127		return 0;
    128
    129	ret = regulator_enable(ctx->supply);
    130	if (ret < 0) {
    131		dev_err(dev, "Failed to enable regulator: %d\n", ret);
    132		return ret;
    133	}
    134
    135	sofef00_panel_reset(ctx);
    136
    137	ret = sofef00_panel_on(ctx);
    138	if (ret < 0) {
    139		dev_err(dev, "Failed to initialize panel: %d\n", ret);
    140		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
    141		return ret;
    142	}
    143
    144	ctx->prepared = true;
    145	return 0;
    146}
    147
    148static int sofef00_panel_unprepare(struct drm_panel *panel)
    149{
    150	struct sofef00_panel *ctx = to_sofef00_panel(panel);
    151	struct device *dev = &ctx->dsi->dev;
    152	int ret;
    153
    154	if (!ctx->prepared)
    155		return 0;
    156
    157	ret = sofef00_panel_off(ctx);
    158	if (ret < 0)
    159		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
    160
    161	regulator_disable(ctx->supply);
    162
    163	ctx->prepared = false;
    164	return 0;
    165}
    166
    167static const struct drm_display_mode enchilada_panel_mode = {
    168	.clock = (1080 + 112 + 16 + 36) * (2280 + 36 + 8 + 12) * 60 / 1000,
    169	.hdisplay = 1080,
    170	.hsync_start = 1080 + 112,
    171	.hsync_end = 1080 + 112 + 16,
    172	.htotal = 1080 + 112 + 16 + 36,
    173	.vdisplay = 2280,
    174	.vsync_start = 2280 + 36,
    175	.vsync_end = 2280 + 36 + 8,
    176	.vtotal = 2280 + 36 + 8 + 12,
    177	.width_mm = 68,
    178	.height_mm = 145,
    179};
    180
    181static const struct drm_display_mode fajita_panel_mode = {
    182	.clock = (1080 + 72 + 16 + 36) * (2340 + 32 + 4 + 18) * 60 / 1000,
    183	.hdisplay = 1080,
    184	.hsync_start = 1080 + 72,
    185	.hsync_end = 1080 + 72 + 16,
    186	.htotal = 1080 + 72 + 16 + 36,
    187	.vdisplay = 2340,
    188	.vsync_start = 2340 + 32,
    189	.vsync_end = 2340 + 32 + 4,
    190	.vtotal = 2340 + 32 + 4 + 18,
    191	.width_mm = 68,
    192	.height_mm = 145,
    193};
    194
    195static int sofef00_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector)
    196{
    197	struct drm_display_mode *mode;
    198	struct sofef00_panel *ctx = to_sofef00_panel(panel);
    199
    200	mode = drm_mode_duplicate(connector->dev, ctx->mode);
    201	if (!mode)
    202		return -ENOMEM;
    203
    204	drm_mode_set_name(mode);
    205
    206	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    207	connector->display_info.width_mm = mode->width_mm;
    208	connector->display_info.height_mm = mode->height_mm;
    209	drm_mode_probed_add(connector, mode);
    210
    211	return 1;
    212}
    213
    214static const struct drm_panel_funcs sofef00_panel_panel_funcs = {
    215	.prepare = sofef00_panel_prepare,
    216	.unprepare = sofef00_panel_unprepare,
    217	.get_modes = sofef00_panel_get_modes,
    218};
    219
    220static int sofef00_panel_bl_update_status(struct backlight_device *bl)
    221{
    222	struct mipi_dsi_device *dsi = bl_get_data(bl);
    223	int err;
    224	u16 brightness;
    225
    226	brightness = (u16)backlight_get_brightness(bl);
    227	// This panel needs the high and low bytes swapped for the brightness value
    228	brightness = __swab16(brightness);
    229
    230	err = mipi_dsi_dcs_set_display_brightness(dsi, brightness);
    231	if (err < 0)
    232		return err;
    233
    234	return 0;
    235}
    236
    237static const struct backlight_ops sofef00_panel_bl_ops = {
    238	.update_status = sofef00_panel_bl_update_status,
    239};
    240
    241static struct backlight_device *
    242sofef00_create_backlight(struct mipi_dsi_device *dsi)
    243{
    244	struct device *dev = &dsi->dev;
    245	const struct backlight_properties props = {
    246		.type = BACKLIGHT_PLATFORM,
    247		.brightness = 1023,
    248		.max_brightness = 1023,
    249	};
    250
    251	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
    252					      &sofef00_panel_bl_ops, &props);
    253}
    254
    255static int sofef00_panel_probe(struct mipi_dsi_device *dsi)
    256{
    257	struct device *dev = &dsi->dev;
    258	struct sofef00_panel *ctx;
    259	int ret;
    260
    261	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
    262	if (!ctx)
    263		return -ENOMEM;
    264
    265	ctx->mode = of_device_get_match_data(dev);
    266
    267	if (!ctx->mode) {
    268		dev_err(dev, "Missing device mode\n");
    269		return -ENODEV;
    270	}
    271
    272	ctx->supply = devm_regulator_get(dev, "vddio");
    273	if (IS_ERR(ctx->supply))
    274		return dev_err_probe(dev, PTR_ERR(ctx->supply),
    275				     "Failed to get vddio regulator\n");
    276
    277	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
    278	if (IS_ERR(ctx->reset_gpio))
    279		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
    280				     "Failed to get reset-gpios\n");
    281
    282	ctx->dsi = dsi;
    283	mipi_dsi_set_drvdata(dsi, ctx);
    284
    285	dsi->lanes = 4;
    286	dsi->format = MIPI_DSI_FMT_RGB888;
    287
    288	drm_panel_init(&ctx->panel, dev, &sofef00_panel_panel_funcs,
    289		       DRM_MODE_CONNECTOR_DSI);
    290
    291	ctx->panel.backlight = sofef00_create_backlight(dsi);
    292	if (IS_ERR(ctx->panel.backlight))
    293		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
    294				     "Failed to create backlight\n");
    295
    296	drm_panel_add(&ctx->panel);
    297
    298	ret = mipi_dsi_attach(dsi);
    299	if (ret < 0) {
    300		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
    301		drm_panel_remove(&ctx->panel);
    302		return ret;
    303	}
    304
    305	return 0;
    306}
    307
    308static int sofef00_panel_remove(struct mipi_dsi_device *dsi)
    309{
    310	struct sofef00_panel *ctx = mipi_dsi_get_drvdata(dsi);
    311	int ret;
    312
    313	ret = mipi_dsi_detach(dsi);
    314	if (ret < 0)
    315		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
    316
    317	drm_panel_remove(&ctx->panel);
    318
    319	return 0;
    320}
    321
    322static const struct of_device_id sofef00_panel_of_match[] = {
    323	{ // OnePlus 6 / enchilada
    324		.compatible = "samsung,sofef00",
    325		.data = &enchilada_panel_mode,
    326	},
    327	{ // OnePlus 6T / fajita
    328		.compatible = "samsung,s6e3fc2x01",
    329		.data = &fajita_panel_mode,
    330	},
    331	{ /* sentinel */ }
    332};
    333MODULE_DEVICE_TABLE(of, sofef00_panel_of_match);
    334
    335static struct mipi_dsi_driver sofef00_panel_driver = {
    336	.probe = sofef00_panel_probe,
    337	.remove = sofef00_panel_remove,
    338	.driver = {
    339		.name = "panel-oneplus6",
    340		.of_match_table = sofef00_panel_of_match,
    341	},
    342};
    343
    344module_mipi_dsi_driver(sofef00_panel_driver);
    345
    346MODULE_AUTHOR("Caleb Connolly <caleb@connolly.tech>");
    347MODULE_DESCRIPTION("DRM driver for Samsung AMOLED DSI panels found in OnePlus 6/6T phones");
    348MODULE_LICENSE("GPL v2");