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