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-atna33xc20.c (9359B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright 2021 Google Inc.
      4 *
      5 * Panel driver for the Samsung ATNA33XC20 panel. This panel can't be handled
      6 * by the DRM_PANEL_SIMPLE driver because its power sequencing is non-standard.
      7 */
      8
      9#include <linux/backlight.h>
     10#include <linux/delay.h>
     11#include <linux/gpio/consumer.h>
     12#include <linux/iopoll.h>
     13#include <linux/module.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/regulator/consumer.h>
     16
     17#include <drm/display/drm_dp_aux_bus.h>
     18#include <drm/display/drm_dp_helper.h>
     19#include <drm/drm_edid.h>
     20#include <drm/drm_panel.h>
     21
     22struct atana33xc20_panel {
     23	struct drm_panel base;
     24	bool prepared;
     25	bool enabled;
     26	bool el3_was_on;
     27
     28	bool no_hpd;
     29	struct gpio_desc *hpd_gpio;
     30
     31	struct regulator *supply;
     32	struct gpio_desc *el_on3_gpio;
     33
     34	struct edid *edid;
     35
     36	ktime_t powered_off_time;
     37	ktime_t powered_on_time;
     38	ktime_t el_on3_off_time;
     39};
     40
     41static inline struct atana33xc20_panel *to_atana33xc20(struct drm_panel *panel)
     42{
     43	return container_of(panel, struct atana33xc20_panel, base);
     44}
     45
     46static void atana33xc20_wait(ktime_t start_ktime, unsigned int min_ms)
     47{
     48	ktime_t now_ktime, min_ktime;
     49
     50	min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
     51	now_ktime = ktime_get();
     52
     53	if (ktime_before(now_ktime, min_ktime))
     54		msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
     55}
     56
     57static int atana33xc20_suspend(struct device *dev)
     58{
     59	struct atana33xc20_panel *p = dev_get_drvdata(dev);
     60	int ret;
     61
     62	/*
     63	 * Note 3 (Example of power off sequence in detail) in spec
     64	 * specifies to wait 150 ms after deasserting EL3_ON before
     65	 * powering off.
     66	 */
     67	if (p->el3_was_on)
     68		atana33xc20_wait(p->el_on3_off_time, 150);
     69
     70	ret = regulator_disable(p->supply);
     71	if (ret)
     72		return ret;
     73	p->powered_off_time = ktime_get();
     74	p->el3_was_on = false;
     75
     76	return 0;
     77}
     78
     79static int atana33xc20_resume(struct device *dev)
     80{
     81	struct atana33xc20_panel *p = dev_get_drvdata(dev);
     82	bool hpd_asserted = false;
     83	int ret;
     84
     85	/* T12 (Power off time) is min 500 ms */
     86	atana33xc20_wait(p->powered_off_time, 500);
     87
     88	ret = regulator_enable(p->supply);
     89	if (ret)
     90		return ret;
     91	p->powered_on_time = ktime_get();
     92
     93	/*
     94	 * Handle HPD. Note: if HPD is hooked up to a dedicated pin on the
     95	 * eDP controller then "no_hpd" will be false _and_ "hpd_gpio" will be
     96	 * NULL. It's up to the controller driver to wait for HPD after
     97	 * preparing the panel in that case.
     98	 */
     99	if (p->no_hpd) {
    100		/* T3 VCC to HPD high is max 200 ms */
    101		msleep(200);
    102	} else if (p->hpd_gpio) {
    103		ret = readx_poll_timeout(gpiod_get_value_cansleep, p->hpd_gpio,
    104					 hpd_asserted, hpd_asserted,
    105					 1000, 200000);
    106		if (!hpd_asserted)
    107			dev_warn(dev, "Timeout waiting for HPD\n");
    108	}
    109
    110	return 0;
    111}
    112
    113static int atana33xc20_disable(struct drm_panel *panel)
    114{
    115	struct atana33xc20_panel *p = to_atana33xc20(panel);
    116
    117	/* Disabling when already disabled is a no-op */
    118	if (!p->enabled)
    119		return 0;
    120
    121	gpiod_set_value_cansleep(p->el_on3_gpio, 0);
    122	p->el_on3_off_time = ktime_get();
    123	p->enabled = false;
    124
    125	/*
    126	 * Keep track of the fact that EL_ON3 was on but we haven't power
    127	 * cycled yet. This lets us know that "el_on3_off_time" is recent (we
    128	 * don't need to worry about ktime wraparounds) and also makes it
    129	 * obvious if we try to enable again without a power cycle (see the
    130	 * warning in atana33xc20_enable()).
    131	 */
    132	p->el3_was_on = true;
    133
    134	/*
    135	 * Sleeping 20 ms here (after setting the GPIO) avoids a glitch when
    136	 * powering off.
    137	 */
    138	msleep(20);
    139
    140	return 0;
    141}
    142
    143static int atana33xc20_enable(struct drm_panel *panel)
    144{
    145	struct atana33xc20_panel *p = to_atana33xc20(panel);
    146
    147	/* Enabling when already enabled is a no-op */
    148	if (p->enabled)
    149		return 0;
    150
    151	/*
    152	 * Once EL_ON3 drops we absolutely need a power cycle before the next
    153	 * enable or the backlight will never come on again. The code ensures
    154	 * this because disable() is _always_ followed by unprepare() and
    155	 * unprepare() forces a suspend with pm_runtime_put_sync_suspend(),
    156	 * but let's track just to make sure since the requirement is so
    157	 * non-obvious.
    158	 */
    159	if (WARN_ON(p->el3_was_on))
    160		return -EIO;
    161
    162	/*
    163	 * Note 2 (Example of power on sequence in detail) in spec specifies
    164	 * to wait 400 ms after powering on before asserting EL3_on.
    165	 */
    166	atana33xc20_wait(p->powered_on_time, 400);
    167
    168	gpiod_set_value_cansleep(p->el_on3_gpio, 1);
    169	p->enabled = true;
    170
    171	return 0;
    172}
    173
    174static int atana33xc20_unprepare(struct drm_panel *panel)
    175{
    176	struct atana33xc20_panel *p = to_atana33xc20(panel);
    177	int ret;
    178
    179	/* Unpreparing when already unprepared is a no-op */
    180	if (!p->prepared)
    181		return 0;
    182
    183	/*
    184	 * Purposely do a put_sync, don't use autosuspend. The panel's tcon
    185	 * seems to sometimes crash when you stop giving it data and this is
    186	 * the best way to ensure it will come back.
    187	 *
    188	 * NOTE: we still want autosuspend for cases where we only turn on
    189	 * to get the EDID or otherwise send DP AUX commands to the panel.
    190	 */
    191	ret = pm_runtime_put_sync_suspend(panel->dev);
    192	if (ret < 0)
    193		return ret;
    194	p->prepared = false;
    195
    196	return 0;
    197}
    198
    199static int atana33xc20_prepare(struct drm_panel *panel)
    200{
    201	struct atana33xc20_panel *p = to_atana33xc20(panel);
    202	int ret;
    203
    204	/* Preparing when already prepared is a no-op */
    205	if (p->prepared)
    206		return 0;
    207
    208	ret = pm_runtime_get_sync(panel->dev);
    209	if (ret < 0) {
    210		pm_runtime_put_autosuspend(panel->dev);
    211		return ret;
    212	}
    213	p->prepared = true;
    214
    215	return 0;
    216}
    217
    218static int atana33xc20_get_modes(struct drm_panel *panel,
    219				 struct drm_connector *connector)
    220{
    221	struct atana33xc20_panel *p = to_atana33xc20(panel);
    222	struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(panel->dev);
    223	int num = 0;
    224
    225	pm_runtime_get_sync(panel->dev);
    226
    227	if (!p->edid)
    228		p->edid = drm_get_edid(connector, &aux_ep->aux->ddc);
    229	num = drm_add_edid_modes(connector, p->edid);
    230
    231	pm_runtime_mark_last_busy(panel->dev);
    232	pm_runtime_put_autosuspend(panel->dev);
    233
    234	return num;
    235}
    236
    237static const struct drm_panel_funcs atana33xc20_funcs = {
    238	.disable = atana33xc20_disable,
    239	.enable = atana33xc20_enable,
    240	.unprepare = atana33xc20_unprepare,
    241	.prepare = atana33xc20_prepare,
    242	.get_modes = atana33xc20_get_modes,
    243};
    244
    245static void atana33xc20_runtime_disable(void *data)
    246{
    247	pm_runtime_disable(data);
    248}
    249
    250static void atana33xc20_dont_use_autosuspend(void *data)
    251{
    252	pm_runtime_dont_use_autosuspend(data);
    253}
    254
    255static int atana33xc20_probe(struct dp_aux_ep_device *aux_ep)
    256{
    257	struct atana33xc20_panel *panel;
    258	struct device *dev = &aux_ep->dev;
    259	int ret;
    260
    261	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
    262	if (!panel)
    263		return -ENOMEM;
    264	dev_set_drvdata(dev, panel);
    265
    266	panel->supply = devm_regulator_get(dev, "power");
    267	if (IS_ERR(panel->supply))
    268		return dev_err_probe(dev, PTR_ERR(panel->supply),
    269				     "Failed to get power supply\n");
    270
    271	panel->el_on3_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
    272	if (IS_ERR(panel->el_on3_gpio))
    273		return dev_err_probe(dev, PTR_ERR(panel->el_on3_gpio),
    274				     "Failed to get enable GPIO\n");
    275
    276	panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd");
    277	if (!panel->no_hpd) {
    278		panel->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
    279		if (IS_ERR(panel->hpd_gpio))
    280			return dev_err_probe(dev, PTR_ERR(panel->hpd_gpio),
    281					     "Failed to get HPD GPIO\n");
    282	}
    283
    284	pm_runtime_enable(dev);
    285	ret = devm_add_action_or_reset(dev,  atana33xc20_runtime_disable, dev);
    286	if (ret)
    287		return ret;
    288	pm_runtime_set_autosuspend_delay(dev, 1000);
    289	pm_runtime_use_autosuspend(dev);
    290	ret = devm_add_action_or_reset(dev,  atana33xc20_dont_use_autosuspend, dev);
    291	if (ret)
    292		return ret;
    293
    294	drm_panel_init(&panel->base, dev, &atana33xc20_funcs, DRM_MODE_CONNECTOR_eDP);
    295
    296	pm_runtime_get_sync(dev);
    297	ret = drm_panel_dp_aux_backlight(&panel->base, aux_ep->aux);
    298	pm_runtime_mark_last_busy(dev);
    299	pm_runtime_put_autosuspend(dev);
    300	if (ret)
    301		return dev_err_probe(dev, ret,
    302				     "failed to register dp aux backlight\n");
    303
    304	drm_panel_add(&panel->base);
    305
    306	return 0;
    307}
    308
    309static void atana33xc20_remove(struct dp_aux_ep_device *aux_ep)
    310{
    311	struct device *dev = &aux_ep->dev;
    312	struct atana33xc20_panel *panel = dev_get_drvdata(dev);
    313
    314	drm_panel_remove(&panel->base);
    315	drm_panel_disable(&panel->base);
    316	drm_panel_unprepare(&panel->base);
    317
    318	kfree(panel->edid);
    319}
    320
    321static void atana33xc20_shutdown(struct dp_aux_ep_device *aux_ep)
    322{
    323	struct device *dev = &aux_ep->dev;
    324	struct atana33xc20_panel *panel = dev_get_drvdata(dev);
    325
    326	drm_panel_disable(&panel->base);
    327	drm_panel_unprepare(&panel->base);
    328}
    329
    330static const struct of_device_id atana33xc20_dt_match[] = {
    331	{ .compatible = "samsung,atna33xc20", },
    332	{ /* sentinal */ }
    333};
    334MODULE_DEVICE_TABLE(of, atana33xc20_dt_match);
    335
    336static const struct dev_pm_ops atana33xc20_pm_ops = {
    337	SET_RUNTIME_PM_OPS(atana33xc20_suspend, atana33xc20_resume, NULL)
    338	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
    339				pm_runtime_force_resume)
    340};
    341
    342static struct dp_aux_ep_driver atana33xc20_driver = {
    343	.driver = {
    344		.name		= "samsung_atana33xc20",
    345		.of_match_table = atana33xc20_dt_match,
    346		.pm		= &atana33xc20_pm_ops,
    347	},
    348	.probe = atana33xc20_probe,
    349	.remove = atana33xc20_remove,
    350	.shutdown = atana33xc20_shutdown,
    351};
    352
    353static int __init atana33xc20_init(void)
    354{
    355	return dp_aux_dp_driver_register(&atana33xc20_driver);
    356}
    357module_init(atana33xc20_init);
    358
    359static void __exit atana33xc20_exit(void)
    360{
    361	dp_aux_dp_driver_unregister(&atana33xc20_driver);
    362}
    363module_exit(atana33xc20_exit);
    364
    365MODULE_DESCRIPTION("Samsung ATANA33XC20 Panel Driver");
    366MODULE_LICENSE("GPL v2");