mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-25 21:24:21 +08:00
video: omap: add panel driver
The previous version of am335x-fb.c contained the functionalities of two drivers that this patch has split. It was a video type driver that used the same registration compatible string that now registers a panel type driver. The proof of this is that two compatible strings were referred to within the same driver. There are now two drivers, each with its own compatible string, functions and API. Furthermore, the panel driver, in addition to decoding the display timings, is now also able to manage the backlight. Signed-off-by: Dario Binacchi <dariobin@libero.it> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
15daa4860b
commit
ff94c15a3c
@ -53,8 +53,6 @@
|
||||
bkl-pwm = <&pwmbacklight>;
|
||||
bkl-tps = <&tps_bl>;
|
||||
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
panel-info {
|
||||
ac-bias = <255>;
|
||||
ac-bias-intrpt = <0>;
|
||||
@ -238,8 +236,19 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&lcdc {
|
||||
status = "disabled";
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&elm {
|
||||
|
@ -53,8 +53,6 @@
|
||||
bkl-pwm = <&pwmbacklight>;
|
||||
bkl-tps = <&tps_bl>;
|
||||
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
panel-info {
|
||||
ac-bias = <255>;
|
||||
ac-bias-intrpt = <0>;
|
||||
@ -228,8 +226,19 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&lcdc {
|
||||
status = "disabled";
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&elm {
|
||||
|
@ -54,8 +54,6 @@
|
||||
bkl-pwm = <&pwmbacklight>;
|
||||
bkl-tps = <&tps_bl>;
|
||||
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
panel-info {
|
||||
ac-bias = <255>;
|
||||
ac-bias-intrpt = <0>;
|
||||
@ -259,8 +257,19 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&lcdc {
|
||||
status = "disabled";
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&elm {
|
||||
|
@ -59,7 +59,6 @@
|
||||
/*backlight = <&tps_bl>; */
|
||||
compatible = "ti,tilcdc,panel";
|
||||
status = "okay";
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
panel-info {
|
||||
ac-bias = <255>;
|
||||
@ -298,10 +297,21 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&lcdc {
|
||||
status = "okay";
|
||||
ti,no-reset-on-init;
|
||||
ti,no-idle-on-init;
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
status = "okay";
|
||||
ti,no-reset-on-init;
|
||||
ti,no-idle-on-init;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&elm {
|
||||
|
@ -79,8 +79,6 @@
|
||||
|
||||
backlight = <&tps_bl>;
|
||||
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
panel-info {
|
||||
ac-bias = <255>;
|
||||
ac-bias-intrpt = <0>;
|
||||
@ -254,10 +252,21 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&lcdc {
|
||||
status = "okay";
|
||||
ti,no-reset-on-init;
|
||||
ti,no-idle-on-init;
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
status = "okay";
|
||||
ti,no-reset-on-init;
|
||||
ti,no-idle-on-init;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&elm {
|
||||
|
@ -5,13 +5,20 @@
|
||||
|
||||
#include "am33xx-u-boot.dtsi"
|
||||
|
||||
/ {
|
||||
panel {
|
||||
u-boot,dm-pre-reloc;
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&mmc3 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -7,8 +7,16 @@
|
||||
|
||||
#include "am33xx-u-boot.dtsi"
|
||||
|
||||
/ {
|
||||
panel {
|
||||
u-boot,dm-pre-reloc;
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -10,16 +10,26 @@
|
||||
ocp {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
panel {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
|
||||
&l4_wkup {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&mmc1 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
@ -9,16 +9,26 @@
|
||||
ocp {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
panel {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
|
||||
&l4_wkup {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&scm {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
@ -7,8 +7,16 @@
|
||||
|
||||
#include "am33xx-u-boot.dtsi"
|
||||
|
||||
/ {
|
||||
panel {
|
||||
u-boot,dm-pre-reloc;
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -7,8 +7,16 @@
|
||||
|
||||
#include "am33xx-u-boot.dtsi"
|
||||
|
||||
/ {
|
||||
panel {
|
||||
u-boot,dm-pre-reloc;
|
||||
&l4_per {
|
||||
|
||||
segment@300000 {
|
||||
|
||||
target-module@e000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
|
||||
lcdc: lcdc@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o
|
||||
obj-$(CONFIG_DM_VIDEO) += video_bmp.o
|
||||
obj-$(CONFIG_PANEL) += panel-uclass.o
|
||||
obj-$(CONFIG_SIMPLE_PANEL) += simple_panel.o
|
||||
obj-$(CONFIG_AM335X_LCD) += tilcdc-panel.o
|
||||
endif
|
||||
|
||||
obj-${CONFIG_EXYNOS_FB} += exynos/
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <dm.h>
|
||||
#include <lcd.h>
|
||||
#include <log.h>
|
||||
#include <panel.h>
|
||||
#include <video.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
@ -25,6 +26,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include "am335x-fb.h"
|
||||
#include "tilcdc-panel.h"
|
||||
|
||||
#define LCDC_FMAX 200000000
|
||||
|
||||
@ -323,7 +325,7 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
|
||||
|
||||
#else /* CONFIG_DM_VIDEO */
|
||||
|
||||
#define FBSIZE(t, p) (((t)->hactive.typ * (t)->vactive.typ * (p)->bpp) >> 3)
|
||||
#define FBSIZE(t, p) (((t).hactive.typ * (t).vactive.typ * (p).bpp) >> 3)
|
||||
|
||||
enum {
|
||||
LCD_MAX_WIDTH = 2048,
|
||||
@ -331,39 +333,8 @@ enum {
|
||||
LCD_MAX_LOG2_BPP = VIDEO_BPP32,
|
||||
};
|
||||
|
||||
/**
|
||||
* tilcdc_panel_info: Panel parameters
|
||||
*
|
||||
* @ac_bias: AC Bias Pin Frequency
|
||||
* @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
|
||||
* @dma_burst_sz: DMA burst size
|
||||
* @bpp: Bits per pixel
|
||||
* @fdd: FIFO DMA Request Delay
|
||||
* @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
|
||||
* @invert_pxl_clk: Invert pixel clock
|
||||
* @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
|
||||
* @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
|
||||
* @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
|
||||
* @fifo_th: DMA FIFO threshold
|
||||
*/
|
||||
struct tilcdc_panel_info {
|
||||
u32 ac_bias;
|
||||
u32 ac_bias_intrpt;
|
||||
u32 dma_burst_sz;
|
||||
u32 bpp;
|
||||
u32 fdd;
|
||||
bool tft_alt_mode;
|
||||
bool invert_pxl_clk;
|
||||
u32 sync_edge;
|
||||
u32 sync_ctrl;
|
||||
u32 raster_order;
|
||||
u32 fifo_th;
|
||||
};
|
||||
|
||||
struct am335x_fb_priv {
|
||||
struct am335x_lcdhw *regs;
|
||||
struct tilcdc_panel_info panel;
|
||||
struct display_timing timing;
|
||||
};
|
||||
|
||||
static int am335x_fb_remove(struct udevice *dev)
|
||||
@ -381,16 +352,71 @@ static int am335x_fb_probe(struct udevice *dev)
|
||||
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct am335x_fb_priv *priv = dev_get_priv(dev);
|
||||
struct am335x_lcdhw *regs = priv->regs;
|
||||
struct tilcdc_panel_info *panel = &priv->panel;
|
||||
struct display_timing *timing = &priv->timing;
|
||||
struct udevice *panel;
|
||||
struct tilcdc_panel_info info;
|
||||
struct display_timing timing;
|
||||
struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
|
||||
u32 reg;
|
||||
int err;
|
||||
|
||||
/* Before relocation we don't need to do anything */
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return 0;
|
||||
|
||||
am335x_fb_set_pixel_clk_rate(regs, timing->pixelclock.typ);
|
||||
err = uclass_get_device(UCLASS_PANEL, 0, &panel);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get panel\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = panel_get_display_timing(panel, &timing);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get display timing\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (timing.pixelclock.typ > (LCDC_FMAX / 2)) {
|
||||
dev_err(dev, "invalid display clock-frequency: %d Hz\n",
|
||||
timing.pixelclock.typ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (timing.hactive.typ > LCD_MAX_WIDTH)
|
||||
timing.hactive.typ = LCD_MAX_WIDTH;
|
||||
|
||||
if (timing.vactive.typ > LCD_MAX_HEIGHT)
|
||||
timing.vactive.typ = LCD_MAX_HEIGHT;
|
||||
|
||||
err = tilcdc_panel_get_display_info(panel, &info);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get panel info\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (info.bpp) {
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid seting, bpp: %d\n", info.bpp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (info.dma_burst_sz) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
|
||||
info.dma_burst_sz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
am335x_fb_set_pixel_clk_rate(regs, timing.pixelclock.typ);
|
||||
|
||||
/* clock source for LCDC from dispPLL M2 */
|
||||
writel(0, &cmdpll->clklcdcpixelclk);
|
||||
@ -411,14 +437,14 @@ static int am335x_fb_probe(struct udevice *dev)
|
||||
writel(reg, ®s->ctrl);
|
||||
|
||||
writel(uc_plat->base, ®s->lcddma_fb0_base);
|
||||
writel(uc_plat->base + FBSIZE(timing, panel),
|
||||
writel(uc_plat->base + FBSIZE(timing, info),
|
||||
®s->lcddma_fb0_ceiling);
|
||||
writel(uc_plat->base, ®s->lcddma_fb1_base);
|
||||
writel(uc_plat->base + FBSIZE(timing, panel),
|
||||
writel(uc_plat->base + FBSIZE(timing, info),
|
||||
®s->lcddma_fb1_ceiling);
|
||||
|
||||
reg = LCDC_DMA_CTRL_FIFO_TH(panel->fifo_th);
|
||||
switch (panel->dma_burst_sz) {
|
||||
reg = LCDC_DMA_CTRL_FIFO_TH(info.fifo_th);
|
||||
switch (info.dma_burst_sz) {
|
||||
case 1:
|
||||
reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_1);
|
||||
break;
|
||||
@ -438,155 +464,84 @@ static int am335x_fb_probe(struct udevice *dev)
|
||||
|
||||
writel(reg, ®s->lcddma_ctrl);
|
||||
|
||||
writel(LCDC_RASTER_TIMING_0_HORLSB(timing->hactive.typ) |
|
||||
LCDC_RASTER_TIMING_0_HORMSB(timing->hactive.typ) |
|
||||
LCDC_RASTER_TIMING_0_HFPLSB(timing->hfront_porch.typ) |
|
||||
LCDC_RASTER_TIMING_0_HBPLSB(timing->hback_porch.typ) |
|
||||
LCDC_RASTER_TIMING_0_HSWLSB(timing->hsync_len.typ),
|
||||
writel(LCDC_RASTER_TIMING_0_HORLSB(timing.hactive.typ) |
|
||||
LCDC_RASTER_TIMING_0_HORMSB(timing.hactive.typ) |
|
||||
LCDC_RASTER_TIMING_0_HFPLSB(timing.hfront_porch.typ) |
|
||||
LCDC_RASTER_TIMING_0_HBPLSB(timing.hback_porch.typ) |
|
||||
LCDC_RASTER_TIMING_0_HSWLSB(timing.hsync_len.typ),
|
||||
®s->raster_timing0);
|
||||
|
||||
writel(LCDC_RASTER_TIMING_1_VBP(timing->vback_porch.typ) |
|
||||
LCDC_RASTER_TIMING_1_VFP(timing->vfront_porch.typ) |
|
||||
LCDC_RASTER_TIMING_1_VSW(timing->vsync_len.typ) |
|
||||
LCDC_RASTER_TIMING_1_VERLSB(timing->vactive.typ),
|
||||
writel(LCDC_RASTER_TIMING_1_VBP(timing.vback_porch.typ) |
|
||||
LCDC_RASTER_TIMING_1_VFP(timing.vfront_porch.typ) |
|
||||
LCDC_RASTER_TIMING_1_VSW(timing.vsync_len.typ) |
|
||||
LCDC_RASTER_TIMING_1_VERLSB(timing.vactive.typ),
|
||||
®s->raster_timing1);
|
||||
|
||||
reg = LCDC_RASTER_TIMING_2_ACB(panel->ac_bias) |
|
||||
LCDC_RASTER_TIMING_2_ACBI(panel->ac_bias_intrpt) |
|
||||
LCDC_RASTER_TIMING_2_HSWMSB(timing->hsync_len.typ) |
|
||||
LCDC_RASTER_TIMING_2_VERMSB(timing->vactive.typ) |
|
||||
LCDC_RASTER_TIMING_2_HBPMSB(timing->hback_porch.typ) |
|
||||
LCDC_RASTER_TIMING_2_HFPMSB(timing->hfront_porch.typ);
|
||||
reg = LCDC_RASTER_TIMING_2_ACB(info.ac_bias) |
|
||||
LCDC_RASTER_TIMING_2_ACBI(info.ac_bias_intrpt) |
|
||||
LCDC_RASTER_TIMING_2_HSWMSB(timing.hsync_len.typ) |
|
||||
LCDC_RASTER_TIMING_2_VERMSB(timing.vactive.typ) |
|
||||
LCDC_RASTER_TIMING_2_HBPMSB(timing.hback_porch.typ) |
|
||||
LCDC_RASTER_TIMING_2_HFPMSB(timing.hfront_porch.typ);
|
||||
|
||||
if (timing->flags & DISPLAY_FLAGS_VSYNC_LOW)
|
||||
if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
|
||||
reg |= LCDC_RASTER_TIMING_2_VSYNC_INVERT;
|
||||
|
||||
if (timing->flags & DISPLAY_FLAGS_HSYNC_LOW)
|
||||
if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
|
||||
reg |= LCDC_RASTER_TIMING_2_HSYNC_INVERT;
|
||||
|
||||
if (panel->invert_pxl_clk)
|
||||
if (info.invert_pxl_clk)
|
||||
reg |= LCDC_RASTER_TIMING_2_PXCLK_INVERT;
|
||||
|
||||
if (panel->sync_edge)
|
||||
if (info.sync_edge)
|
||||
reg |= LCDC_RASTER_TIMING_2_HSVS_RISEFALL;
|
||||
|
||||
if (panel->sync_ctrl)
|
||||
if (info.sync_ctrl)
|
||||
reg |= LCDC_RASTER_TIMING_2_HSVS_CONTROL;
|
||||
|
||||
writel(reg, ®s->raster_timing2);
|
||||
|
||||
reg = LCDC_RASTER_CTRL_PALMODE_RAWDATA | LCDC_RASTER_CTRL_TFT_MODE |
|
||||
LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(panel->fdd);
|
||||
LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(info.fdd);
|
||||
|
||||
if (panel->tft_alt_mode)
|
||||
if (info.tft_alt_mode)
|
||||
reg |= LCDC_RASTER_CTRL_TFT_ALT_ENABLE;
|
||||
|
||||
if (panel->bpp == 24)
|
||||
if (info.bpp == 24)
|
||||
reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
|
||||
else if (panel->bpp == 32)
|
||||
else if (info.bpp == 32)
|
||||
reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE |
|
||||
LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
|
||||
|
||||
if (panel->raster_order)
|
||||
if (info.raster_order)
|
||||
reg |= LCDC_RASTER_CTRL_DATA_ORDER;
|
||||
|
||||
writel(reg, ®s->raster_ctrl);
|
||||
|
||||
uc_priv->xsize = timing->hactive.typ;
|
||||
uc_priv->ysize = timing->vactive.typ;
|
||||
uc_priv->bpix = log_2_n_round_up(panel->bpp);
|
||||
uc_priv->xsize = timing.hactive.typ;
|
||||
uc_priv->ysize = timing.vactive.typ;
|
||||
uc_priv->bpix = log_2_n_round_up(info.bpp);
|
||||
|
||||
err = panel_enable_backlight(panel);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable panel backlight\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am335x_fb_of_to_plat(struct udevice *dev)
|
||||
static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct am335x_fb_priv *priv = dev_get_priv(dev);
|
||||
struct tilcdc_panel_info *panel = &priv->panel;
|
||||
struct display_timing *timing = &priv->timing;
|
||||
ofnode node;
|
||||
int err;
|
||||
|
||||
node = ofnode_by_compatible(ofnode_null(), "ti,am33xx-tilcdc");
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_err(dev, "missing 'ti,am33xx-tilcdc' node\n");
|
||||
return -ENXIO;
|
||||
priv->regs = (struct am335x_lcdhw *)dev_read_addr(dev);
|
||||
if ((fdt_addr_t)priv->regs == FDT_ADDR_T_NONE) {
|
||||
dev_err(dev, "failed to get base address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->regs = (struct am335x_lcdhw *)ofnode_get_addr(node);
|
||||
dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
|
||||
|
||||
err = ofnode_decode_display_timing(dev_ofnode(dev), 0, timing);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get display timing\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (timing->pixelclock.typ > (LCDC_FMAX / 2)) {
|
||||
dev_err(dev, "invalid display clock-frequency: %d Hz\n",
|
||||
timing->pixelclock.typ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (timing->hactive.typ > LCD_MAX_WIDTH)
|
||||
timing->hactive.typ = LCD_MAX_WIDTH;
|
||||
|
||||
if (timing->vactive.typ > LCD_MAX_HEIGHT)
|
||||
timing->vactive.typ = LCD_MAX_HEIGHT;
|
||||
|
||||
node = ofnode_find_subnode(dev_ofnode(dev), "panel-info");
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_err(dev, "missing 'panel-info' node\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
err |= ofnode_read_u32(node, "ac-bias", &panel->ac_bias);
|
||||
err |= ofnode_read_u32(node, "ac-bias-intrpt", &panel->ac_bias_intrpt);
|
||||
err |= ofnode_read_u32(node, "dma-burst-sz", &panel->dma_burst_sz);
|
||||
err |= ofnode_read_u32(node, "bpp", &panel->bpp);
|
||||
err |= ofnode_read_u32(node, "fdd", &panel->fdd);
|
||||
err |= ofnode_read_u32(node, "sync-edge", &panel->sync_edge);
|
||||
err |= ofnode_read_u32(node, "sync-ctrl", &panel->sync_ctrl);
|
||||
err |= ofnode_read_u32(node, "raster-order", &panel->raster_order);
|
||||
err |= ofnode_read_u32(node, "fifo-th", &panel->fifo_th);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get panel info\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (panel->bpp) {
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid seting, bpp: %d\n", panel->bpp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (panel->dma_burst_sz) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
|
||||
panel->dma_burst_sz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* optional */
|
||||
panel->tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
|
||||
panel->invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
|
||||
|
||||
dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n", timing->hactive.typ,
|
||||
timing->vactive.typ, panel->bpp, timing->pixelclock.typ);
|
||||
dev_dbg(dev, " hbp=%d, hfp=%d, hsw=%d\n", timing->hback_porch.typ,
|
||||
timing->hfront_porch.typ, timing->hsync_len.typ);
|
||||
dev_dbg(dev, " vbp=%d, vfp=%d, vsw=%d\n", timing->vback_porch.typ,
|
||||
timing->vfront_porch.typ, timing->vsync_len.typ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -602,7 +557,7 @@ static int am335x_fb_bind(struct udevice *dev)
|
||||
}
|
||||
|
||||
static const struct udevice_id am335x_fb_ids[] = {
|
||||
{ .compatible = "ti,tilcdc,panel" },
|
||||
{ .compatible = "ti,am33xx-tilcdc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,37 @@ struct am335x_lcdpanel {
|
||||
|
||||
int am335xfb_init(struct am335x_lcdpanel *panel);
|
||||
|
||||
#else /* CONFIG_DM_VIDEO */
|
||||
|
||||
/**
|
||||
* tilcdc_panel_info: Panel parameters
|
||||
*
|
||||
* @ac_bias: AC Bias Pin Frequency
|
||||
* @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
|
||||
* @dma_burst_sz: DMA burst size
|
||||
* @bpp: Bits per pixel
|
||||
* @fdd: FIFO DMA Request Delay
|
||||
* @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
|
||||
* @invert_pxl_clk: Invert pixel clock
|
||||
* @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
|
||||
* @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
|
||||
* @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
|
||||
* @fifo_th: DMA FIFO threshold
|
||||
*/
|
||||
struct tilcdc_panel_info {
|
||||
u32 ac_bias;
|
||||
u32 ac_bias_intrpt;
|
||||
u32 dma_burst_sz;
|
||||
u32 bpp;
|
||||
u32 fdd;
|
||||
bool tft_alt_mode;
|
||||
bool invert_pxl_clk;
|
||||
u32 sync_edge;
|
||||
u32 sync_ctrl;
|
||||
u32 raster_order;
|
||||
u32 fifo_th;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_DM_VIDEO */
|
||||
|
||||
#endif /* AM335X_FB_H */
|
||||
|
172
drivers/video/tilcdc-panel.c
Normal file
172
drivers/video/tilcdc-panel.c
Normal file
@ -0,0 +1,172 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* OMAP panel support
|
||||
*
|
||||
* Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <backlight.h>
|
||||
#include <clk.h>
|
||||
#include <display.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <log.h>
|
||||
#include <panel.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/err.h>
|
||||
#include "am335x-fb.h"
|
||||
|
||||
struct tilcdc_panel_priv {
|
||||
struct tilcdc_panel_info info;
|
||||
struct display_timing timing;
|
||||
struct udevice *backlight;
|
||||
struct gpio_desc enable;
|
||||
};
|
||||
|
||||
static int tilcdc_panel_enable_backlight(struct udevice *dev)
|
||||
{
|
||||
struct tilcdc_panel_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (dm_gpio_is_valid(&priv->enable))
|
||||
dm_gpio_set_value(&priv->enable, 1);
|
||||
|
||||
if (priv->backlight)
|
||||
return backlight_enable(priv->backlight);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tilcdc_panel_set_backlight(struct udevice *dev, int percent)
|
||||
{
|
||||
struct tilcdc_panel_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (dm_gpio_is_valid(&priv->enable))
|
||||
dm_gpio_set_value(&priv->enable, 1);
|
||||
|
||||
if (priv->backlight)
|
||||
return backlight_set_brightness(priv->backlight, percent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tilcdc_panel_get_display_info(struct udevice *dev,
|
||||
struct tilcdc_panel_info *info)
|
||||
{
|
||||
struct tilcdc_panel_priv *priv = dev_get_priv(dev);
|
||||
|
||||
memcpy(info, &priv->info, sizeof(*info));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tilcdc_panel_get_display_timing(struct udevice *dev,
|
||||
struct display_timing *timing)
|
||||
{
|
||||
struct tilcdc_panel_priv *priv = dev_get_priv(dev);
|
||||
|
||||
memcpy(timing, &priv->timing, sizeof(*timing));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tilcdc_panel_remove(struct udevice *dev)
|
||||
{
|
||||
struct tilcdc_panel_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (dm_gpio_is_valid(&priv->enable))
|
||||
dm_gpio_free(dev, &priv->enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tilcdc_panel_probe(struct udevice *dev)
|
||||
{
|
||||
struct tilcdc_panel_priv *priv = dev_get_priv(dev);
|
||||
int err;
|
||||
|
||||
err = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
|
||||
"backlight", &priv->backlight);
|
||||
if (err)
|
||||
dev_warn(dev, "failed to get backlight\n");
|
||||
|
||||
err = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
|
||||
GPIOD_IS_OUT);
|
||||
if (err) {
|
||||
dev_warn(dev, "failed to get enable GPIO\n");
|
||||
if (err != -ENOENT)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tilcdc_panel_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct tilcdc_panel_priv *priv = dev_get_priv(dev);
|
||||
ofnode node;
|
||||
int err;
|
||||
|
||||
err = ofnode_decode_display_timing(dev_ofnode(dev), 0, &priv->timing);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get display timing\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
node = dev_read_subnode(dev, "panel-info");
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_err(dev, "missing 'panel-info' node\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
err |= ofnode_read_u32(node, "ac-bias", &priv->info.ac_bias);
|
||||
err |= ofnode_read_u32(node, "ac-bias-intrpt",
|
||||
&priv->info.ac_bias_intrpt);
|
||||
err |= ofnode_read_u32(node, "dma-burst-sz", &priv->info.dma_burst_sz);
|
||||
err |= ofnode_read_u32(node, "bpp", &priv->info.bpp);
|
||||
err |= ofnode_read_u32(node, "fdd", &priv->info.fdd);
|
||||
err |= ofnode_read_u32(node, "sync-edge", &priv->info.sync_edge);
|
||||
err |= ofnode_read_u32(node, "sync-ctrl", &priv->info.sync_ctrl);
|
||||
err |= ofnode_read_u32(node, "raster-order", &priv->info.raster_order);
|
||||
err |= ofnode_read_u32(node, "fifo-th", &priv->info.fifo_th);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get panel info\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* optional */
|
||||
priv->info.tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
|
||||
priv->info.invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
|
||||
|
||||
dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n",
|
||||
priv->timing.hactive.typ, priv->timing.vactive.typ,
|
||||
priv->info.bpp, priv->timing.pixelclock.typ);
|
||||
dev_dbg(dev, " hbp=%d, hfp=%d, hsw=%d\n",
|
||||
priv->timing.hback_porch.typ, priv->timing.hfront_porch.typ,
|
||||
priv->timing.hsync_len.typ);
|
||||
dev_dbg(dev, " vbp=%d, vfp=%d, vsw=%d\n",
|
||||
priv->timing.vback_porch.typ, priv->timing.vfront_porch.typ,
|
||||
priv->timing.vsync_len.typ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct panel_ops tilcdc_panel_ops = {
|
||||
.enable_backlight = tilcdc_panel_enable_backlight,
|
||||
.set_backlight = tilcdc_panel_set_backlight,
|
||||
.get_display_timing = tilcdc_panel_get_display_timing,
|
||||
};
|
||||
|
||||
static const struct udevice_id tilcdc_panel_ids[] = {
|
||||
{.compatible = "ti,tilcdc,panel"},
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(tilcdc_panel) = {
|
||||
.name = "tilcdc_panel",
|
||||
.id = UCLASS_PANEL,
|
||||
.of_match = tilcdc_panel_ids,
|
||||
.ops = &tilcdc_panel_ops,
|
||||
.ofdata_to_platdata = tilcdc_panel_of_to_plat,
|
||||
.probe = tilcdc_panel_probe,
|
||||
.remove = tilcdc_panel_remove,
|
||||
.priv_auto = sizeof(struct tilcdc_panel_priv),
|
||||
};
|
14
drivers/video/tilcdc-panel.h
Normal file
14
drivers/video/tilcdc-panel.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
|
||||
*/
|
||||
|
||||
#ifndef _TILCDC_PANEL_H
|
||||
#define _TILCDC_PANEL_H
|
||||
|
||||
#include "am335x-fb.h"
|
||||
|
||||
int tilcdc_panel_get_display_info(struct udevice *dev,
|
||||
struct tilcdc_panel_info *info);
|
||||
|
||||
#endif /* _TILCDC_PANEL_H */
|
Loading…
Reference in New Issue
Block a user