Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/panel: atna33xc20: Introduce the Samsung ATNA33XC20 panel

The Samsung ATNA33XC20 panel is an AMOLED eDP panel that has backlight
control over the DP AUX channel.

This panel is _almost_ able to be controlled in a "simple" way (and it
originally was implemented in panel-simple.c), but it's really
impossible to get the backlight semantics right there without adding
wacky special-case code to panel-simple. Let's give up and clone the
parts of panel-simple that we need and implement the power sequence
that this panel needs.

NOTE: we'll still leave the devicetree bindings alone. Even though the
power-sequencing is non-standard the bindings are still "simple".

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210730084534.v2.6.I3a2900080f8749d2bb4baf49ca902db4b0e1df7d@changeid

authored by

Douglas Anderson and committed by
Sam Ravnborg
32ce3b32 81c3212d

+378
+11
drivers/gpu/drm/panel/Kconfig
··· 353 353 Say Y here if you want to enable support for Ronbo Electronics 354 354 RB070D30 1024x600 DSI panel. 355 355 356 + config DRM_PANEL_SAMSUNG_ATNA33XC20 357 + tristate "Samsung ATNA33XC20 eDP panel" 358 + depends on OF 359 + depends on BACKLIGHT_CLASS_DEVICE 360 + depends on PM 361 + select DRM_DP_AUX_BUS 362 + help 363 + DRM panel driver for the Samsung ATNA33XC20 panel. This panel can't 364 + be handled by the DRM_PANEL_SIMPLE driver because its power 365 + sequencing is non-standard. 366 + 356 367 config DRM_PANEL_SAMSUNG_DB7430 357 368 tristate "Samsung DB7430-based DPI panels" 358 369 depends on OF && SPI && GPIOLIB
+1
drivers/gpu/drm/panel/Makefile
··· 34 34 obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o 35 35 obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o 36 36 obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o 37 + obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o 37 38 obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o 38 39 obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o 39 40 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
+366
drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
··· 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/drm_dp_aux_bus.h> 18 + #include <drm/drm_dp_helper.h> 19 + #include <drm/drm_edid.h> 20 + #include <drm/drm_panel.h> 21 + 22 + struct 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 + 41 + static inline struct atana33xc20_panel *to_atana33xc20(struct drm_panel *panel) 42 + { 43 + return container_of(panel, struct atana33xc20_panel, base); 44 + } 45 + 46 + static 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 + 57 + static 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 + 79 + static 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 + 113 + static 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 + 143 + static 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 + 174 + static 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 + 199 + static 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 + 218 + static 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 + 237 + static 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 + 245 + static void atana33xc20_runtime_disable(void *data) 246 + { 247 + pm_runtime_disable(data); 248 + } 249 + 250 + static void atana33xc20_dont_use_autosuspend(void *data) 251 + { 252 + pm_runtime_dont_use_autosuspend(data); 253 + } 254 + 255 + static 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 + 309 + static 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 + 321 + static 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 + 330 + static const struct of_device_id atana33xc20_dt_match[] = { 331 + { .compatible = "samsung,atna33xc20", }, 332 + { /* sentinal */ } 333 + }; 334 + MODULE_DEVICE_TABLE(of, atana33xc20_dt_match); 335 + 336 + static 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 + 342 + static 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 + 353 + static int __init atana33xc20_init(void) 354 + { 355 + return dp_aux_dp_driver_register(&atana33xc20_driver); 356 + } 357 + module_init(atana33xc20_init); 358 + 359 + static void __exit atana33xc20_exit(void) 360 + { 361 + dp_aux_dp_driver_unregister(&atana33xc20_driver); 362 + } 363 + module_exit(atana33xc20_exit); 364 + 365 + MODULE_DESCRIPTION("Samsung ATANA33XC20 Panel Driver"); 366 + MODULE_LICENSE("GPL v2");