1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * OMAP panel support 4 * 5 * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it> 6 */ 7 8#include <common.h> 9#include <backlight.h> 10#include <clk.h> 11#include <display.h> 12#include <dm.h> 13#include <dm/device_compat.h> 14#include <log.h> 15#include <panel.h> 16#include <asm/gpio.h> 17#include <linux/err.h> 18#include "tilcdc.h" 19 20struct tilcdc_panel_priv { 21 struct tilcdc_panel_info info; 22 struct display_timing timing; 23 struct udevice *backlight; 24 struct gpio_desc enable; 25}; 26 27static int tilcdc_panel_enable_backlight(struct udevice *dev) 28{ 29 struct tilcdc_panel_priv *priv = dev_get_priv(dev); 30 31 if (dm_gpio_is_valid(&priv->enable)) 32 dm_gpio_set_value(&priv->enable, 1); 33 34 if (priv->backlight) 35 return backlight_enable(priv->backlight); 36 37 return 0; 38} 39 40static int tilcdc_panel_set_backlight(struct udevice *dev, int percent) 41{ 42 struct tilcdc_panel_priv *priv = dev_get_priv(dev); 43 44 if (dm_gpio_is_valid(&priv->enable)) 45 dm_gpio_set_value(&priv->enable, 1); 46 47 if (priv->backlight) 48 return backlight_set_brightness(priv->backlight, percent); 49 50 return 0; 51} 52 53int tilcdc_panel_get_display_info(struct udevice *dev, 54 struct tilcdc_panel_info *info) 55{ 56 struct tilcdc_panel_priv *priv = dev_get_priv(dev); 57 58 memcpy(info, &priv->info, sizeof(*info)); 59 return 0; 60} 61 62static int tilcdc_panel_get_display_timing(struct udevice *dev, 63 struct display_timing *timing) 64{ 65 struct tilcdc_panel_priv *priv = dev_get_priv(dev); 66 67 memcpy(timing, &priv->timing, sizeof(*timing)); 68 return 0; 69} 70 71static int tilcdc_panel_remove(struct udevice *dev) 72{ 73 struct tilcdc_panel_priv *priv = dev_get_priv(dev); 74 75 if (dm_gpio_is_valid(&priv->enable)) 76 dm_gpio_free(dev, &priv->enable); 77 78 return 0; 79} 80 81static int tilcdc_panel_probe(struct udevice *dev) 82{ 83 struct tilcdc_panel_priv *priv = dev_get_priv(dev); 84 int err; 85 86 err = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, 87 "backlight", &priv->backlight); 88 if (err) 89 dev_warn(dev, "failed to get backlight\n"); 90 91 err = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable, 92 GPIOD_IS_OUT); 93 if (err) { 94 dev_warn(dev, "failed to get enable GPIO\n"); 95 if (err != -ENOENT) 96 return err; 97 } 98 99 return 0; 100} 101 102static int tilcdc_panel_of_to_plat(struct udevice *dev) 103{ 104 struct tilcdc_panel_priv *priv = dev_get_priv(dev); 105 ofnode node; 106 int err; 107 108 err = ofnode_decode_display_timing(dev_ofnode(dev), 0, &priv->timing); 109 if (err) { 110 dev_err(dev, "failed to get display timing\n"); 111 return err; 112 } 113 114 node = dev_read_subnode(dev, "panel-info"); 115 if (!ofnode_valid(node)) { 116 dev_err(dev, "missing 'panel-info' node\n"); 117 return -ENXIO; 118 } 119 120 err |= ofnode_read_u32(node, "ac-bias", &priv->info.ac_bias); 121 err |= ofnode_read_u32(node, "ac-bias-intrpt", 122 &priv->info.ac_bias_intrpt); 123 err |= ofnode_read_u32(node, "dma-burst-sz", &priv->info.dma_burst_sz); 124 err |= ofnode_read_u32(node, "bpp", &priv->info.bpp); 125 err |= ofnode_read_u32(node, "fdd", &priv->info.fdd); 126 err |= ofnode_read_u32(node, "sync-edge", &priv->info.sync_edge); 127 err |= ofnode_read_u32(node, "sync-ctrl", &priv->info.sync_ctrl); 128 err |= ofnode_read_u32(node, "raster-order", &priv->info.raster_order); 129 err |= ofnode_read_u32(node, "fifo-th", &priv->info.fifo_th); 130 if (err) { 131 dev_err(dev, "failed to get panel info\n"); 132 return err; 133 } 134 135 /* optional */ 136 priv->info.tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode"); 137 priv->info.invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk"); 138 139 dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n", 140 priv->timing.hactive.typ, priv->timing.vactive.typ, 141 priv->info.bpp, priv->timing.pixelclock.typ); 142 dev_dbg(dev, " hbp=%d, hfp=%d, hsw=%d\n", 143 priv->timing.hback_porch.typ, priv->timing.hfront_porch.typ, 144 priv->timing.hsync_len.typ); 145 dev_dbg(dev, " vbp=%d, vfp=%d, vsw=%d\n", 146 priv->timing.vback_porch.typ, priv->timing.vfront_porch.typ, 147 priv->timing.vsync_len.typ); 148 149 return 0; 150} 151 152static const struct panel_ops tilcdc_panel_ops = { 153 .enable_backlight = tilcdc_panel_enable_backlight, 154 .set_backlight = tilcdc_panel_set_backlight, 155 .get_display_timing = tilcdc_panel_get_display_timing, 156}; 157 158static const struct udevice_id tilcdc_panel_ids[] = { 159 {.compatible = "ti,tilcdc,panel"}, 160 {} 161}; 162 163U_BOOT_DRIVER(tilcdc_panel) = { 164 .name = "tilcdc_panel", 165 .id = UCLASS_PANEL, 166 .of_match = tilcdc_panel_ids, 167 .ops = &tilcdc_panel_ops, 168 .of_to_plat = tilcdc_panel_of_to_plat, 169 .probe = tilcdc_panel_probe, 170 .remove = tilcdc_panel_remove, 171 .priv_auto = sizeof(struct tilcdc_panel_priv), 172}; 173