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

tilcdc_panel.c (10402B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2012 Texas Instruments
      4 * Author: Rob Clark <robdclark@gmail.com>
      5 */
      6
      7#include <linux/gpio/consumer.h>
      8#include <linux/pinctrl/consumer.h>
      9#include <linux/platform_device.h>
     10
     11#include <video/display_timing.h>
     12#include <video/of_display_timing.h>
     13#include <video/videomode.h>
     14
     15#include <drm/drm_atomic_state_helper.h>
     16#include <drm/drm_connector.h>
     17#include <drm/drm_modeset_helper_vtables.h>
     18#include <drm/drm_probe_helper.h>
     19#include <drm/drm_simple_kms_helper.h>
     20
     21#include "tilcdc_drv.h"
     22#include "tilcdc_panel.h"
     23
     24struct panel_module {
     25	struct tilcdc_module base;
     26	struct tilcdc_panel_info *info;
     27	struct display_timings *timings;
     28	struct backlight_device *backlight;
     29	struct gpio_desc *enable_gpio;
     30};
     31#define to_panel_module(x) container_of(x, struct panel_module, base)
     32
     33
     34/*
     35 * Encoder:
     36 */
     37
     38struct panel_encoder {
     39	struct drm_encoder base;
     40	struct panel_module *mod;
     41};
     42#define to_panel_encoder(x) container_of(x, struct panel_encoder, base)
     43
     44static void panel_encoder_dpms(struct drm_encoder *encoder, int mode)
     45{
     46	struct panel_encoder *panel_encoder = to_panel_encoder(encoder);
     47	struct backlight_device *backlight = panel_encoder->mod->backlight;
     48	struct gpio_desc *gpio = panel_encoder->mod->enable_gpio;
     49
     50	if (backlight) {
     51		backlight->props.power = mode == DRM_MODE_DPMS_ON ?
     52					 FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
     53		backlight_update_status(backlight);
     54	}
     55
     56	if (gpio)
     57		gpiod_set_value_cansleep(gpio,
     58					 mode == DRM_MODE_DPMS_ON ? 1 : 0);
     59}
     60
     61static void panel_encoder_prepare(struct drm_encoder *encoder)
     62{
     63	panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
     64}
     65
     66static void panel_encoder_commit(struct drm_encoder *encoder)
     67{
     68	panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
     69}
     70
     71static void panel_encoder_mode_set(struct drm_encoder *encoder,
     72		struct drm_display_mode *mode,
     73		struct drm_display_mode *adjusted_mode)
     74{
     75	/* nothing needed */
     76}
     77
     78static const struct drm_encoder_helper_funcs panel_encoder_helper_funcs = {
     79		.dpms           = panel_encoder_dpms,
     80		.prepare        = panel_encoder_prepare,
     81		.commit         = panel_encoder_commit,
     82		.mode_set       = panel_encoder_mode_set,
     83};
     84
     85static struct drm_encoder *panel_encoder_create(struct drm_device *dev,
     86		struct panel_module *mod)
     87{
     88	struct panel_encoder *panel_encoder;
     89	struct drm_encoder *encoder;
     90	int ret;
     91
     92	panel_encoder = devm_kzalloc(dev->dev, sizeof(*panel_encoder),
     93				     GFP_KERNEL);
     94	if (!panel_encoder)
     95		return NULL;
     96
     97	panel_encoder->mod = mod;
     98
     99	encoder = &panel_encoder->base;
    100	encoder->possible_crtcs = 1;
    101
    102	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS);
    103	if (ret < 0)
    104		goto fail;
    105
    106	drm_encoder_helper_add(encoder, &panel_encoder_helper_funcs);
    107
    108	return encoder;
    109
    110fail:
    111	drm_encoder_cleanup(encoder);
    112	return NULL;
    113}
    114
    115/*
    116 * Connector:
    117 */
    118
    119struct panel_connector {
    120	struct drm_connector base;
    121
    122	struct drm_encoder *encoder;  /* our connected encoder */
    123	struct panel_module *mod;
    124};
    125#define to_panel_connector(x) container_of(x, struct panel_connector, base)
    126
    127
    128static void panel_connector_destroy(struct drm_connector *connector)
    129{
    130	drm_connector_unregister(connector);
    131	drm_connector_cleanup(connector);
    132}
    133
    134static int panel_connector_get_modes(struct drm_connector *connector)
    135{
    136	struct drm_device *dev = connector->dev;
    137	struct panel_connector *panel_connector = to_panel_connector(connector);
    138	struct display_timings *timings = panel_connector->mod->timings;
    139	int i;
    140
    141	for (i = 0; i < timings->num_timings; i++) {
    142		struct drm_display_mode *mode;
    143		struct videomode vm;
    144
    145		if (videomode_from_timings(timings, &vm, i))
    146			break;
    147
    148		mode = drm_mode_create(dev);
    149		if (!mode)
    150			break;
    151
    152		drm_display_mode_from_videomode(&vm, mode);
    153
    154		mode->type = DRM_MODE_TYPE_DRIVER;
    155
    156		if (timings->native_mode == i)
    157			mode->type |= DRM_MODE_TYPE_PREFERRED;
    158
    159		drm_mode_set_name(mode);
    160		drm_mode_probed_add(connector, mode);
    161	}
    162
    163	return i;
    164}
    165
    166static struct drm_encoder *panel_connector_best_encoder(
    167		struct drm_connector *connector)
    168{
    169	struct panel_connector *panel_connector = to_panel_connector(connector);
    170	return panel_connector->encoder;
    171}
    172
    173static const struct drm_connector_funcs panel_connector_funcs = {
    174	.destroy            = panel_connector_destroy,
    175	.fill_modes         = drm_helper_probe_single_connector_modes,
    176	.reset              = drm_atomic_helper_connector_reset,
    177	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
    178	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
    179};
    180
    181static const struct drm_connector_helper_funcs panel_connector_helper_funcs = {
    182	.get_modes          = panel_connector_get_modes,
    183	.best_encoder       = panel_connector_best_encoder,
    184};
    185
    186static struct drm_connector *panel_connector_create(struct drm_device *dev,
    187		struct panel_module *mod, struct drm_encoder *encoder)
    188{
    189	struct panel_connector *panel_connector;
    190	struct drm_connector *connector;
    191	int ret;
    192
    193	panel_connector = devm_kzalloc(dev->dev, sizeof(*panel_connector),
    194				       GFP_KERNEL);
    195	if (!panel_connector)
    196		return NULL;
    197
    198	panel_connector->encoder = encoder;
    199	panel_connector->mod = mod;
    200
    201	connector = &panel_connector->base;
    202
    203	drm_connector_init(dev, connector, &panel_connector_funcs,
    204			DRM_MODE_CONNECTOR_LVDS);
    205	drm_connector_helper_add(connector, &panel_connector_helper_funcs);
    206
    207	connector->interlace_allowed = 0;
    208	connector->doublescan_allowed = 0;
    209
    210	ret = drm_connector_attach_encoder(connector, encoder);
    211	if (ret)
    212		goto fail;
    213
    214	return connector;
    215
    216fail:
    217	panel_connector_destroy(connector);
    218	return NULL;
    219}
    220
    221/*
    222 * Module:
    223 */
    224
    225static int panel_modeset_init(struct tilcdc_module *mod, struct drm_device *dev)
    226{
    227	struct panel_module *panel_mod = to_panel_module(mod);
    228	struct tilcdc_drm_private *priv = dev->dev_private;
    229	struct drm_encoder *encoder;
    230	struct drm_connector *connector;
    231
    232	encoder = panel_encoder_create(dev, panel_mod);
    233	if (!encoder)
    234		return -ENOMEM;
    235
    236	connector = panel_connector_create(dev, panel_mod, encoder);
    237	if (!connector)
    238		return -ENOMEM;
    239
    240	priv->encoders[priv->num_encoders++] = encoder;
    241	priv->connectors[priv->num_connectors++] = connector;
    242
    243	tilcdc_crtc_set_panel_info(priv->crtc,
    244				   to_panel_encoder(encoder)->mod->info);
    245
    246	return 0;
    247}
    248
    249static const struct tilcdc_module_ops panel_module_ops = {
    250		.modeset_init = panel_modeset_init,
    251};
    252
    253/*
    254 * Device:
    255 */
    256
    257/* maybe move this somewhere common if it is needed by other outputs? */
    258static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np)
    259{
    260	struct device_node *info_np;
    261	struct tilcdc_panel_info *info;
    262	int ret = 0;
    263
    264	if (!np) {
    265		pr_err("%s: no devicenode given\n", __func__);
    266		return NULL;
    267	}
    268
    269	info_np = of_get_child_by_name(np, "panel-info");
    270	if (!info_np) {
    271		pr_err("%s: could not find panel-info node\n", __func__);
    272		return NULL;
    273	}
    274
    275	info = kzalloc(sizeof(*info), GFP_KERNEL);
    276	if (!info)
    277		goto put_node;
    278
    279	ret |= of_property_read_u32(info_np, "ac-bias", &info->ac_bias);
    280	ret |= of_property_read_u32(info_np, "ac-bias-intrpt", &info->ac_bias_intrpt);
    281	ret |= of_property_read_u32(info_np, "dma-burst-sz", &info->dma_burst_sz);
    282	ret |= of_property_read_u32(info_np, "bpp", &info->bpp);
    283	ret |= of_property_read_u32(info_np, "fdd", &info->fdd);
    284	ret |= of_property_read_u32(info_np, "sync-edge", &info->sync_edge);
    285	ret |= of_property_read_u32(info_np, "sync-ctrl", &info->sync_ctrl);
    286	ret |= of_property_read_u32(info_np, "raster-order", &info->raster_order);
    287	ret |= of_property_read_u32(info_np, "fifo-th", &info->fifo_th);
    288
    289	/* optional: */
    290	info->tft_alt_mode      = of_property_read_bool(info_np, "tft-alt-mode");
    291	info->invert_pxl_clk    = of_property_read_bool(info_np, "invert-pxl-clk");
    292
    293	if (ret) {
    294		pr_err("%s: error reading panel-info properties\n", __func__);
    295		kfree(info);
    296		info = NULL;
    297	}
    298
    299put_node:
    300	of_node_put(info_np);
    301	return info;
    302}
    303
    304static int panel_probe(struct platform_device *pdev)
    305{
    306	struct device_node *node = pdev->dev.of_node;
    307	struct backlight_device *backlight;
    308	struct panel_module *panel_mod;
    309	struct tilcdc_module *mod;
    310	struct pinctrl *pinctrl;
    311	int ret;
    312
    313	/* bail out early if no DT data: */
    314	if (!node) {
    315		dev_err(&pdev->dev, "device-tree data is missing\n");
    316		return -ENXIO;
    317	}
    318
    319	panel_mod = devm_kzalloc(&pdev->dev, sizeof(*panel_mod), GFP_KERNEL);
    320	if (!panel_mod)
    321		return -ENOMEM;
    322
    323	backlight = devm_of_find_backlight(&pdev->dev);
    324	if (IS_ERR(backlight))
    325		return PTR_ERR(backlight);
    326	panel_mod->backlight = backlight;
    327
    328	panel_mod->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
    329							 GPIOD_OUT_LOW);
    330	if (IS_ERR(panel_mod->enable_gpio)) {
    331		ret = PTR_ERR(panel_mod->enable_gpio);
    332		dev_err(&pdev->dev, "failed to request enable GPIO\n");
    333		goto fail_backlight;
    334	}
    335
    336	if (panel_mod->enable_gpio)
    337		dev_info(&pdev->dev, "found enable GPIO\n");
    338
    339	mod = &panel_mod->base;
    340	pdev->dev.platform_data = mod;
    341
    342	tilcdc_module_init(mod, "panel", &panel_module_ops);
    343
    344	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
    345	if (IS_ERR(pinctrl))
    346		dev_warn(&pdev->dev, "pins are not configured\n");
    347
    348	panel_mod->timings = of_get_display_timings(node);
    349	if (!panel_mod->timings) {
    350		dev_err(&pdev->dev, "could not get panel timings\n");
    351		ret = -EINVAL;
    352		goto fail_free;
    353	}
    354
    355	panel_mod->info = of_get_panel_info(node);
    356	if (!panel_mod->info) {
    357		dev_err(&pdev->dev, "could not get panel info\n");
    358		ret = -EINVAL;
    359		goto fail_timings;
    360	}
    361
    362	return 0;
    363
    364fail_timings:
    365	display_timings_release(panel_mod->timings);
    366
    367fail_free:
    368	tilcdc_module_cleanup(mod);
    369
    370fail_backlight:
    371	if (panel_mod->backlight)
    372		put_device(&panel_mod->backlight->dev);
    373	return ret;
    374}
    375
    376static int panel_remove(struct platform_device *pdev)
    377{
    378	struct tilcdc_module *mod = dev_get_platdata(&pdev->dev);
    379	struct panel_module *panel_mod = to_panel_module(mod);
    380	struct backlight_device *backlight = panel_mod->backlight;
    381
    382	if (backlight)
    383		put_device(&backlight->dev);
    384
    385	display_timings_release(panel_mod->timings);
    386
    387	tilcdc_module_cleanup(mod);
    388	kfree(panel_mod->info);
    389
    390	return 0;
    391}
    392
    393static const struct of_device_id panel_of_match[] = {
    394		{ .compatible = "ti,tilcdc,panel", },
    395		{ },
    396};
    397
    398static struct platform_driver panel_driver = {
    399	.probe = panel_probe,
    400	.remove = panel_remove,
    401	.driver = {
    402		.name = "tilcdc-panel",
    403		.of_match_table = panel_of_match,
    404	},
    405};
    406
    407int __init tilcdc_panel_init(void)
    408{
    409	return platform_driver_register(&panel_driver);
    410}
    411
    412void __exit tilcdc_panel_fini(void)
    413{
    414	platform_driver_unregister(&panel_driver);
    415}