summaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig69
-rw-r--r--drivers/video/Makefile12
-rw-r--r--drivers/video/atmel_hlcdfb.c25
-rw-r--r--drivers/video/atmel_lcdfb.c22
-rw-r--r--drivers/video/atmel_lcdfb.h5
-rw-r--r--drivers/video/atmel_lcdfb_core.c49
-rw-r--r--drivers/video/backlight-pwm.c34
-rw-r--r--drivers/video/backlight.c1
-rw-r--r--drivers/video/bcm2835.c28
-rw-r--r--drivers/video/bochs/Kconfig24
-rw-r--r--drivers/video/bochs/Makefile5
-rw-r--r--drivers/video/bochs/bochs_hw.c206
-rw-r--r--drivers/video/bochs/bochs_hw.h15
-rw-r--r--drivers/video/bochs/bochs_isa.c31
-rw-r--r--drivers/video/bochs/bochs_pci.c38
-rw-r--r--drivers/video/edid.c28
-rw-r--r--drivers/video/edid.h17
-rw-r--r--drivers/video/efi_gop.c25
-rw-r--r--drivers/video/fb.c34
-rw-r--r--drivers/video/fbconsole.c116
-rw-r--r--drivers/video/imx-ipu-fb.c31
-rw-r--r--drivers/video/imx-ipu-v3/Kconfig1
-rw-r--r--drivers/video/imx-ipu-v3/Makefile1
-rw-r--r--drivers/video/imx-ipu-v3/imx-hdmi.c64
-rw-r--r--drivers/video/imx-ipu-v3/imx-hdmi.h6
-rw-r--r--drivers/video/imx-ipu-v3/imx-ipu-v3.h8
-rw-r--r--drivers/video/imx-ipu-v3/imx-ldb.c39
-rw-r--r--drivers/video/imx-ipu-v3/imx-pd.c50
-rw-r--r--drivers/video/imx-ipu-v3/ipu-common.c39
-rw-r--r--drivers/video/imx-ipu-v3/ipu-dc.c15
-rw-r--r--drivers/video/imx-ipu-v3/ipu-di.c32
-rw-r--r--drivers/video/imx-ipu-v3/ipu-dmfc.c17
-rw-r--r--drivers/video/imx-ipu-v3/ipu-dp.c15
-rw-r--r--drivers/video/imx-ipu-v3/ipu-prv.h26
-rw-r--r--drivers/video/imx-ipu-v3/ipufb.c38
-rw-r--r--drivers/video/imx-ipu-v3/ipuv3-plane.c12
-rw-r--r--drivers/video/imx-ipu-v3/ipuv3-plane.h1
-rw-r--r--drivers/video/imx.c21
-rw-r--r--drivers/video/mipi_dbi.c745
-rw-r--r--drivers/video/mtl017.c32
-rw-r--r--drivers/video/of_display_timing.c56
-rw-r--r--drivers/video/omap.c32
-rw-r--r--drivers/video/omap.h14
-rw-r--r--drivers/video/panel-ilitek-ili9341.c543
-rw-r--r--drivers/video/panel-mipi-dbi.c332
-rw-r--r--drivers/video/pxa.c28
-rw-r--r--drivers/video/ramfb.c191
-rw-r--r--drivers/video/rave-sp-backlight.c19
-rw-r--r--drivers/video/s3c24xx.c421
-rw-r--r--drivers/video/sdl.c55
-rw-r--r--drivers/video/simple-panel.c28
-rw-r--r--drivers/video/simplefb-client.c152
-rw-r--r--drivers/video/simplefb-fixup.c (renamed from drivers/video/simplefb.c)10
-rw-r--r--drivers/video/ssd1307fb.c201
-rw-r--r--drivers/video/stm.c25
-rw-r--r--drivers/video/stm32_ltdc.c337
-rw-r--r--drivers/video/stm32_ltdc.h130
-rw-r--r--drivers/video/tc358767.c36
-rw-r--r--drivers/video/vpl.c30
59 files changed, 3472 insertions, 1145 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a26bace176..9e176d3198 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
menuconfig VIDEO
bool "Video drivers"
help
@@ -14,7 +15,7 @@ config FRAMEBUFFER_CONSOLE
config DRIVER_VIDEO_FB_SSD1307
bool "Solomon SSD1307 framebuffer support"
- depends on I2C && GPIOLIB
+ depends on (I2C || SPI) && GPIOLIB
config VIDEO_VPL
depends on OFTREE
@@ -30,7 +31,8 @@ config DRIVER_VIDEO_ATMEL_HLCD
config DRIVER_VIDEO_EFI_GOP
bool "EFI Graphics Output Protocol (GOP)"
- depends on EFI_BOOTUP
+ depends on EFI_PAYLOAD
+ depends on X86
config DRIVER_VIDEO_IMX
bool "i.MX framebuffer driver"
@@ -58,30 +60,26 @@ config DRIVER_VIDEO_STM
Say 'Y' here to enable framebuffer and splash screen support for
i.MX23 and i.MX28 based systems.
-config DRIVER_VIDEO_S3C24XX
- bool "S3C244x framebuffer driver"
- depends on ARCH_S3C24xx
+config DRIVER_VIDEO_STM32_LTDC
+ bool "STM32 LTDC framebuffer driver"
+ select VIDEO_VPL
+ depends on ARCH_STM32 || COMPILE_TEST
help
- Add support for the S3C244x LCD controller.
+ Say 'Y' here to enable framebuffer and splash screen support for
+ STM32 and STM32MP1.
config DRIVER_VIDEO_OMAP
bool "OMAP framebuffer driver"
- depends on ARCH_OMAP4
+ depends on ARCH_OMAP4 || COMPILE_TEST
help
Add support for OMAP Display Controller. Currently this
driver only supports OMAP4 SoCs in DISPC parallel mode on
LCD2 (MIPI DPI).
-if DRIVER_VIDEO_S3C24XX
-
-config DRIVER_VIDEO_S3C_VERBOSE
- bool "S3C244x verbose framebuffer info"
-
-endif
-
config DRIVER_VIDEO_SDL
bool "SDL framebuffer driver"
depends on SANDBOX
+ select SDL
config DRIVER_VIDEO_PXA
bool "PXA27x framebuffer driver"
@@ -98,20 +96,36 @@ config DRIVER_VIDEO_BCM283X
source "drivers/video/imx-ipu-v3/Kconfig"
+source "drivers/video/bochs/Kconfig"
+
+config DRIVER_VIDEO_SIMPLEFB_CLIENT
+ bool "Simple framebuffer client support"
+ depends on OFTREE
+ help
+ Add support for reusing a previously set up simple framebuffer.
+
config DRIVER_VIDEO_SIMPLEFB
- bool "Simple framebuffer support"
+ bool "Simple framebuffer fixup support"
depends on OFTREE
help
Add support for setting up the kernel's simple framebuffer driver
based on the active barebox framebuffer.
+config DRIVER_VIDEO_RAMFB
+ bool "QEMU RamFB support"
+ select QEMU_FW_CFG
+ help
+ Add support for setting up a QEMU RamFB driver.
+
config DRIVER_VIDEO_EDID
- depends on I2C
bool "Add EDID support"
help
This enabled support for reading and parsing EDID data from an attached
monitor.
+config DRIVER_VIDEO_MIPI_DBI
+ bool
+
config DRIVER_VIDEO_BACKLIGHT
bool "Add backlight support"
help
@@ -161,4 +175,27 @@ config DRIVER_VIDEO_SIMPLE_PANEL
Linux Kernel implementation this one is able to understand display-timings
nodes so that it's not necessary to keep a list of all known displays
with their corresponding timings in barebox.
+
+config DRIVER_VIDEO_PANEL_ILITEK_ILI9341
+ tristate "Ilitek ILI9341 240x320 QVGA panels"
+ depends on OFTREE && SPI
+ select DRIVER_VIDEO_MIPI_DBI
+ select VIDEO_VPL
+ help
+ Say Y here if you want to enable support for Ilitek IL9341
+ QVGA (240x320) RGB panels. support serial & parallel rgb
+ interface.
+
+config DRIVER_VIDEO_PANEL_MIPI_DBI
+ tristate "DRM support for MIPI DBI compatible panels"
+ depends on OFTREE && SPI
+ select DRIVER_VIDEO_MIPI_DBI
+ select FIRMWARE
+ select VIDEO_VPL
+ help
+ Say Y here if you want to enable support for MIPI DBI compatible
+ panels. The controller command setup can be provided using a
+ firmware file. For more information see
+ https://github.com/notro/panel-mipi-dbi/wiki.
+
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 01fabe8809..85cffb5a33 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_VIDEO) += fb.o
obj-$(CONFIG_DRIVER_VIDEO_EDID) += edid.o
obj-$(CONFIG_OFDEVICE) += of_display_timing.o
@@ -8,20 +9,25 @@ obj-$(CONFIG_VIDEO_VPL) += vpl.o
obj-$(CONFIG_DRIVER_VIDEO_MTL017) += mtl017.o
obj-$(CONFIG_DRIVER_VIDEO_TC358767) += tc358767.o
obj-$(CONFIG_DRIVER_VIDEO_SIMPLE_PANEL) += simple-panel.o
+obj-$(CONFIG_DRIVER_VIDEO_MIPI_DBI) += mipi_dbi.o
+obj-$(CONFIG_DRIVER_VIDEO_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
+obj-$(CONFIG_DRIVER_VIDEO_PANEL_MIPI_DBI) += panel-mipi-dbi.o
obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
obj-$(CONFIG_DRIVER_VIDEO_STM) += stm.o
+obj-$(CONFIG_DRIVER_VIDEO_STM32_LTDC) += stm32_ltdc.o
obj-$(CONFIG_DRIVER_VIDEO_IMX) += imx.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPU) += imx-ipu-fb.o
-obj-$(CONFIG_DRIVER_VIDEO_S3C24XX) += s3c24xx.o
obj-$(CONFIG_DRIVER_VIDEO_PXA) += pxa.o
obj-$(CONFIG_DRIVER_VIDEO_SDL) += sdl.o
obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
-obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
+obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT) += simplefb-client.o
+obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb-fixup.o
+obj-$(CONFIG_DRIVER_VIDEO_RAMFB) += ramfb.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
obj-$(CONFIG_DRIVER_VIDEO_EFI_GOP) += efi_gop.o
obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o
-
+obj-$(CONFIG_DRIVER_VIDEO_BOCHS) += bochs/
diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
index aa84334b09..0a24493907 100644
--- a/drivers/video/atmel_hlcdfb.c
+++ b/drivers/video/atmel_hlcdfb.c
@@ -1,30 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for AT91/AT32 LCD Controller
*
* Copyright (C) 2007 Atmel Corporation
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <io.h>
#include <init.h>
#include <linux/clk.h>
-#include <mach/hardware.h>
-#include <mach/atmel_hlcdc.h>
-#include <mach/cpu.h>
+#include <mach/at91/hardware.h>
+#include <mach/at91/atmel_hlcdc.h>
+#include <mach/at91/cpu.h>
#include <errno.h>
#include "atmel_lcdfb.h"
@@ -273,12 +260,12 @@ struct atmel_lcdfb_devdata atmel_hlcdfb_data = {
.dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
};
-static int atmel_hlcdc_probe(struct device_d *dev)
+static int atmel_hlcdc_probe(struct device *dev)
{
return atmel_lcdc_register(dev, &atmel_hlcdfb_data);
}
-static struct driver_d atmel_hlcdc_driver = {
+static struct driver atmel_hlcdc_driver = {
.name = "atmel_hlcdfb",
.probe = atmel_hlcdc_probe,
};
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 322404f322..5d8dc8f8b9 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -1,27 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for AT91/AT32 LCD Controller
*
* Copyright (C) 2007 Atmel Corporation
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <io.h>
#include <init.h>
-#include <mach/hardware.h>
+#include <mach/at91/hardware.h>
#include <errno.h>
#include <linux/clk.h>
@@ -236,7 +223,7 @@ struct atmel_lcdfb_devdata atmel_lcdfb_data = {
.limit_screeninfo = atmel_lcdfb_limit_screeninfo,
};
-static int atmel_lcdc_probe(struct device_d *dev)
+static int atmel_lcdc_probe(struct device *dev)
{
return atmel_lcdc_register(dev, &atmel_lcdfb_data);
}
@@ -276,8 +263,9 @@ static __maybe_unused struct of_device_id atmel_lcdfb_compatible[] = {
{ .compatible = "atmel,at32ap-lcdc", .data = &at32ap_config, },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, atmel_lcdfb_compatible);
-static struct driver_d atmel_lcdc_driver = {
+static struct driver atmel_lcdc_driver = {
.name = "atmel_lcdfb",
.probe = atmel_lcdc_probe,
.of_compatible = DRV_OF_COMPAT(atmel_lcdfb_compatible),
diff --git a/drivers/video/atmel_lcdfb.h b/drivers/video/atmel_lcdfb.h
index 76c0e739e8..7aa058e198 100644
--- a/drivers/video/atmel_lcdfb.h
+++ b/drivers/video/atmel_lcdfb.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <fb.h>
#include <video/atmel_lcdc.h>
@@ -23,7 +24,7 @@ struct atmel_lcdfb_devdata {
struct atmel_lcdfb_info {
struct fb_info info;
void __iomem *mmio;
- struct device_d *device;
+ struct device *device;
unsigned int guard_time;
unsigned int smem_len;
@@ -48,4 +49,4 @@ struct atmel_lcdfb_info {
#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
-int atmel_lcdc_register(struct device_d *dev, struct atmel_lcdfb_devdata *data);
+int atmel_lcdc_register(struct device *dev, struct atmel_lcdfb_devdata *data);
diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
index c6ece5b785..9d3e6682b6 100644
--- a/drivers/video/atmel_lcdfb_core.c
+++ b/drivers/video/atmel_lcdfb_core.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for AT91/AT32 LCD Controller
*
* Copyright (C) 2007 Atmel Corporation
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -27,7 +14,7 @@
#include <linux/clk.h>
#include <malloc.h>
-#include <mach/cpu.h>
+#include <mach/at91/cpu.h>
#include "atmel_lcdfb.h"
@@ -75,7 +62,7 @@ static void atmel_lcdc_disable_controller(struct fb_info *fb_info)
static int atmel_lcdfb_check_var(struct fb_info *info)
{
- struct device_d *dev = &info->dev;
+ struct device *dev = &info->dev;
struct atmel_lcdfb_info *sinfo = info->priv;
struct fb_videomode *mode = info->mode;
unsigned long clk_value_khz;
@@ -132,7 +119,7 @@ static int atmel_lcdfb_check_var(struct fb_info *info)
= info->bits_per_pixel;
break;
case 16:
- /* Older SOCs use BGR:555 rather than BGR:565. */
+ /* Older SOCs use BRG:555 rather than BRG:565. */
if (sinfo->have_intensity_bit)
info->green.length = 5;
else
@@ -142,7 +129,7 @@ static int atmel_lcdfb_check_var(struct fb_info *info)
info->red.offset = info->green.length + 5;
info->blue.offset = 0;
} else {
- /* BGR:5X5 mode */
+ /* BRG:5X5 mode */
info->red.offset = 0;
info->blue.offset = info->green.length + 5;
}
@@ -159,7 +146,7 @@ static int atmel_lcdfb_check_var(struct fb_info *info)
info->red.offset = 16;
info->blue.offset = 0;
} else {
- /* BGR:888 mode */
+ /* BRG:888 mode */
info->red.offset = 0;
info->blue.offset = 16;
}
@@ -250,7 +237,7 @@ static struct fb_ops atmel_lcdc_ops = {
.fb_disable = atmel_lcdc_disable_controller,
};
-static int power_control_init(struct device_d *dev,
+static int power_control_init(struct device *dev,
struct atmel_lcdfb_info *sinfo,
int gpio,
bool active_low)
@@ -282,7 +269,7 @@ static int power_control_init(struct device_d *dev,
}
/*
- * Syntax: atmel,lcd-wiring-mode: lcd wiring mode "RGB", "BGR"
+ * Syntax: atmel,lcd-wiring-mode: lcd wiring mode "RGB", "BRG"
*/
static int of_get_wiring_mode(struct device_node *np,
struct atmel_lcdfb_info *sinfo)
@@ -293,12 +280,12 @@ static int of_get_wiring_mode(struct device_node *np,
ret = of_property_read_string(np, "atmel,lcd-wiring-mode", &mode);
if (ret < 0) {
/* Not present, use defaults */
- sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_BGR;
+ sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_BRG;
return 0;
}
- if (!strcasecmp(mode, "BGR")) {
- sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_BGR;
+ if (!strcasecmp(mode, "BRG")) {
+ sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_BRG;
} else if (!strcasecmp(mode, "RGB")) {
sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB;
} else {
@@ -307,7 +294,7 @@ static int of_get_wiring_mode(struct device_node *np,
return 0;
}
-static int of_get_power_control(struct device_d *dev,
+static int of_get_power_control(struct device *dev,
struct device_node *np,
struct atmel_lcdfb_info *sinfo)
{
@@ -324,7 +311,7 @@ static int of_get_power_control(struct device_d *dev,
return power_control_init(dev, sinfo, gpio, active_low);
}
-static int lcdfb_of_init(struct device_d *dev, struct atmel_lcdfb_info *sinfo)
+static int lcdfb_of_init(struct device *dev, struct atmel_lcdfb_info *sinfo)
{
struct fb_info *info = &sinfo->info;
struct display_timings *modes;
@@ -341,7 +328,7 @@ static int lcdfb_of_init(struct device_d *dev, struct atmel_lcdfb_info *sinfo)
}
/* Required properties */
- display = of_parse_phandle(dev->device_node, "display", 0);
+ display = of_parse_phandle(dev->of_node, "display", 0);
if (!display) {
dev_err(dev, "no display phandle\n");
return -ENOENT;
@@ -391,7 +378,8 @@ err:
return ret;
}
-static int lcdfb_pdata_init(struct device_d *dev, struct atmel_lcdfb_info *sinfo)
+static int lcdfb_pdata_init(struct device *dev,
+ struct atmel_lcdfb_info *sinfo)
{
struct atmel_lcdfb_platform_data *pdata;
struct fb_info *info;
@@ -435,7 +423,7 @@ err:
return ret;
}
-int atmel_lcdc_register(struct device_d *dev, struct atmel_lcdfb_devdata *data)
+int atmel_lcdc_register(struct device *dev, struct atmel_lcdfb_devdata *data)
{
struct atmel_lcdfb_info *sinfo;
const char *bus_clk_name;
@@ -463,7 +451,7 @@ int atmel_lcdc_register(struct device_d *dev, struct atmel_lcdfb_devdata *data)
}
bus_clk_name = "hck1";
} else {
- if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->device_node)
+ if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->of_node)
return -EINVAL;
ret = lcdfb_of_init(dev, sinfo);
@@ -492,6 +480,7 @@ int atmel_lcdc_register(struct device_d *dev, struct atmel_lcdfb_devdata *data)
sinfo->dma_desc = dma_alloc_coherent(data->dma_desc_size,
DMA_ADDRESS_BROKEN);
+ info->dev.parent = dev;
ret = register_framebuffer(info);
if (ret != 0) {
dev_err(dev, "Failed to register framebuffer\n");
diff --git a/drivers/video/backlight-pwm.c b/drivers/video/backlight-pwm.c
index 9111a42d75..87358ca778 100644
--- a/drivers/video/backlight-pwm.c
+++ b/drivers/video/backlight-pwm.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* pwm backlight support for barebox
*
* (C) Copyright 2014 Sascha Hauer, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <malloc.h>
@@ -27,7 +14,7 @@
#include <regulator.h>
#include <gpio.h>
#include <of_gpio.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
struct pwm_backlight {
struct backlight_device backlight;
@@ -37,7 +24,6 @@ struct pwm_backlight {
unsigned int *levels;
int enable_gpio;
int enable_active_high;
- int max_value;
int enabled;
unsigned int scale;
};
@@ -115,10 +101,10 @@ static int backlight_pwm_set(struct backlight_device *backlight,
return backlight_pwm_disable(pwm_backlight);
}
-static int pwm_backlight_parse_dt(struct device_d *dev,
- struct pwm_backlight *pwm_backlight)
+static int pwm_backlight_parse_dt(struct device *dev,
+ struct pwm_backlight *pwm_backlight)
{
- struct device_node *node = dev->device_node;
+ struct device_node *node = dev->of_node;
struct property *prop;
int length;
u32 value;
@@ -178,13 +164,13 @@ static int pwm_backlight_parse_dt(struct device_d *dev,
return 0;
}
-static int backlight_pwm_of_probe(struct device_d *dev)
+static int backlight_pwm_of_probe(struct device *dev)
{
int ret;
struct pwm_backlight *pwm_backlight;
struct pwm_device *pwm;
- pwm = of_pwm_request(dev->device_node, NULL);
+ pwm = of_pwm_request(dev->of_node, NULL);
if (IS_ERR(pwm)) {
dev_err(dev, "Cannot find PWM device\n");
return PTR_ERR(pwm);
@@ -206,7 +192,8 @@ static int backlight_pwm_of_probe(struct device_d *dev)
pwm_backlight->backlight.slew_time_ms = 100;
pwm_backlight->backlight.brightness_set = backlight_pwm_set;
- pwm_backlight->backlight.node = dev->device_node;
+ pwm_backlight->backlight.dev.parent = dev;
+ pwm_backlight->backlight.node = dev->of_node;
ret = backlight_register(&pwm_backlight->backlight);
if (ret)
@@ -222,8 +209,9 @@ static struct of_device_id backlight_pwm_of_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, backlight_pwm_of_ids);
-static struct driver_d backlight_pwm_of_driver = {
+static struct driver backlight_pwm_of_driver = {
.name = "pwm-backlight",
.probe = backlight_pwm_of_probe,
.of_compatible = DRV_OF_COMPAT(backlight_pwm_of_ids),
diff --git a/drivers/video/backlight.c b/drivers/video/backlight.c
index 3913d1c4c9..6c00cc115e 100644
--- a/drivers/video/backlight.c
+++ b/drivers/video/backlight.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
#include <driver.h>
#include <linux/list.h>
diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c
index 3d52f8b6b8..070d1b4902 100644
--- a/drivers/video/bcm2835.c
+++ b/drivers/video/bcm2835.c
@@ -14,7 +14,8 @@
#include <malloc.h>
#include <xfuncs.h>
-#include <mach/mbox.h>
+#include <of_address.h>
+#include <mach/bcm283x/mbox.h>
struct bcm2835fb_info {
struct fb_info fbi;
@@ -53,14 +54,29 @@ static struct fb_ops bcm2835fb_ops = {
.fb_disable = bcm2835fb_disable,
};
-static int bcm2835fb_probe(struct device_d *dev)
+static int bcm2835fb_probe(struct device *dev)
{
BCM2835_MBOX_STACK_ALIGN(struct msg_fb_query, msg_query);
BCM2835_MBOX_STACK_ALIGN(struct msg_fb_setup, msg_setup);
struct bcm2835fb_info *info;
+ struct device_node *soc;
u32 w, h;
+ u64 dma_addr, cpu_addr, _region_size;
+ phys_addr_t buffer_addr;
int ret;
+ soc = of_find_node_by_path("/soc");
+ if (!soc) {
+ dev_err(dev, "could not find required OF node /soc\n");
+ return -ENODEV;
+ }
+
+ ret = of_dma_get_range(soc, &dma_addr, &cpu_addr, &_region_size);
+ if (ret) {
+ dev_err(dev, "OF node /soc has no dma-ranges\n");
+ return ret;
+ }
+
BCM2835_MBOX_INIT_HDR(msg_query);
BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_query->physical_w_h,
GET_PHYSICAL_W_H);
@@ -99,10 +115,11 @@ static int bcm2835fb_probe(struct device_d *dev)
return ret;
}
+ buffer_addr = (msg_setup->allocate_buffer.body.resp.fb_address & ~dma_addr) + cpu_addr;
+
info = xzalloc(sizeof *info);
info->fbi.fbops = &bcm2835fb_ops;
- info->fbi.screen_base =
- (void *)msg_setup->allocate_buffer.body.resp.fb_address;
+ info->fbi.screen_base = phys_to_virt(buffer_addr);
info->fbi.xres = msg_setup->physical_w_h.body.resp.width;
info->fbi.yres = msg_setup->physical_w_h.body.resp.height;
info->fbi.bits_per_pixel = 16;
@@ -118,6 +135,7 @@ static int bcm2835fb_probe(struct device_d *dev)
info->fbi.mode->xres = info->fbi.xres;
info->fbi.mode->yres = info->fbi.yres;
+ info->fbi.dev.parent = dev;
ret = register_framebuffer(&info->fbi);
if (ret) {
free(info);
@@ -129,7 +147,7 @@ static int bcm2835fb_probe(struct device_d *dev)
return 0;
}
-static struct driver_d bcm2835fb_driver = {
+static struct driver bcm2835fb_driver = {
.name = "bcm2835_fb",
.probe = bcm2835fb_probe,
};
diff --git a/drivers/video/bochs/Kconfig b/drivers/video/bochs/Kconfig
new file mode 100644
index 0000000000..ae5d38a8ad
--- /dev/null
+++ b/drivers/video/bochs/Kconfig
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRIVER_VIDEO_BOCHS
+ select DRIVER_VIDEO_EDID
+ bool
+
+config DRIVER_VIDEO_BOCHS_PCI
+ bool "bochs dispi / QEMU standard VGA PCI driver"
+ select DRIVER_VIDEO_BOCHS
+ depends on PCI
+ help
+ Say yes here if you have a PCI VGA display controller that
+ implements the bochs dispi VBE extension. This is a very simple
+ interface to drive the graphical output of virtual machines
+ like bochs, VirtualBox and Qemu (-device VGA).
+
+config DRIVER_VIDEO_BOCHS_ISA
+ bool "bochs dispi / QEMU standard VGA ISA driver"
+ select DRIVER_VIDEO_BOCHS
+ help
+ Say yes here if you have a ISA (I/O ports) VGA display controller that
+ implements the bochs dispi VBE extension. This is a very simple
+ interface to drive the graphical output of virtual machines
+ like bochs, VirtualBox and Qemu (-device isa-vga).
diff --git a/drivers/video/bochs/Makefile b/drivers/video/bochs/Makefile
new file mode 100644
index 0000000000..3ab7ade8a1
--- /dev/null
+++ b/drivers/video/bochs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += bochs_hw.o
+obj-$(CONFIG_DRIVER_VIDEO_BOCHS_PCI) += bochs_pci.o
+obj-$(CONFIG_DRIVER_VIDEO_BOCHS_ISA) += bochs_isa.o
diff --git a/drivers/video/bochs/bochs_hw.c b/drivers/video/bochs/bochs_hw.c
new file mode 100644
index 0000000000..60439ddee5
--- /dev/null
+++ b/drivers/video/bochs/bochs_hw.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright (c) 2020 Ahmad Fatoum, Pengutronix
+/*
+ * Driver for VGA with the Bochs VBE / QEMU stdvga extensions.
+ *
+ * Based on the Linux v5.11-rc1 bochs-dispi DRM driver.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <fb.h>
+#include "../edid.h"
+#include "bochs_hw.h"
+
+#define VBE_DISPI_INDEX_ID 0x0
+#define VBE_DISPI_INDEX_XRES 0x1
+#define VBE_DISPI_INDEX_YRES 0x2
+#define VBE_DISPI_INDEX_BPP 0x3
+#define VBE_DISPI_INDEX_ENABLE 0x4
+#define VBE_DISPI_INDEX_BANK 0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+#define VBE_DISPI_INDEX_X_OFFSET 0x8
+#define VBE_DISPI_INDEX_Y_OFFSET 0x9
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
+
+#define VBE_DISPI_ENABLED 0x01
+#define VBE_DISPI_GETCAPS 0x02
+#define VBE_DISPI_8BIT_DAC 0x20
+#define VBE_DISPI_LFB_ENABLED 0x40
+#define VBE_DISPI_NOCLEARMEM 0x80
+
+/* Offsets for accessing ioports via PCI BAR1 (MMIO) */
+#define VGA_MMIO_OFFSET (0x400 - 0x3c0)
+#define VBE_MMIO_OFFSET 0x500
+
+struct bochs {
+ struct fb_info fb;
+ void __iomem *fb_map;
+ void __iomem *mmio;
+};
+
+static void bochs_vga_writeb(struct bochs *bochs, u16 ioport, u8 val)
+{
+ if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df))
+ return;
+
+ if (bochs->mmio) {
+ int offset = ioport + VGA_MMIO_OFFSET;
+ writeb(val, bochs->mmio + offset);
+ } else {
+ outb(val, ioport);
+ }
+}
+
+static u16 bochs_dispi_read(struct bochs *bochs, u16 reg)
+{
+ u16 ret = 0;
+
+ if (bochs->mmio) {
+ int offset = VBE_MMIO_OFFSET + (reg << 1);
+ ret = readw(bochs->mmio + offset);
+ } else {
+ outw(reg, VBE_DISPI_IOPORT_INDEX);
+ ret = inw(VBE_DISPI_IOPORT_DATA);
+ }
+ return ret;
+}
+
+static void bochs_dispi_write(struct bochs *bochs, u16 reg, u16 val)
+{
+ if (bochs->mmio) {
+ int offset = VBE_MMIO_OFFSET + (reg << 1);
+ writew(val, bochs->mmio + offset);
+ } else {
+ outw(reg, VBE_DISPI_IOPORT_INDEX);
+ outw(val, VBE_DISPI_IOPORT_DATA);
+ }
+}
+
+static void bochs_fb_enable(struct fb_info *fb)
+{
+ struct bochs *bochs = fb->priv;
+
+ bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, 0);
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, fb->bits_per_pixel);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, fb->xres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, fb->yres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK, 0);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, fb->xres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT, fb->yres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, 0);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, 0);
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
+ VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED );
+}
+
+static void bochs_fb_disable(struct fb_info *fb)
+{
+ struct bochs *bochs = fb->priv;
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
+ bochs_dispi_read(bochs, VBE_DISPI_INDEX_ENABLE) &
+ ~VBE_DISPI_ENABLED);
+}
+
+static struct fb_ops bochs_fb_ops = {
+ .fb_enable = bochs_fb_enable,
+ .fb_disable = bochs_fb_disable,
+};
+
+static int bochs_hw_load_edid(struct bochs *bochs)
+{
+ u8 *edid;
+ int i;
+
+ edid = xzalloc(EDID_LENGTH);
+
+ for (i = 0; i <= EDID_HEADER_END; i++)
+ edid[i] = readb(bochs->mmio + i);
+
+ /* check header to detect whenever edid support is enabled in qemu */
+ if (!edid_check_header(edid)) {
+ free(edid);
+ return -EILSEQ;
+ }
+
+ for (i = EDID_HEADER_END + 1; i < EDID_LENGTH; i++)
+ edid[i] = readb(bochs->mmio + i);
+
+ bochs->fb.edid_data = edid;
+ return 0;
+}
+
+static int bochs_hw_read_version(struct bochs *bochs)
+{
+ u16 ver;
+
+ ver = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID);
+
+ if ((ver & 0xB0C0) != 0xB0C0)
+ return -ENODEV;
+
+ return ver & 0xF;
+}
+
+int bochs_hw_probe(struct device *dev, void __iomem *fb_map,
+ void __iomem *mmio)
+{
+ struct bochs *bochs;
+ struct fb_info *fb;
+ int ret;
+
+ bochs = xzalloc(sizeof(*bochs));
+
+ bochs->fb_map = fb_map;
+ bochs->mmio = mmio;
+
+ ret = bochs_hw_read_version(bochs);
+ if (ret < 0) {
+ free(bochs);
+ return ret;
+ }
+
+ dev_info(dev, "detected bochs dispi v%u\n", ret);
+
+ fb = &bochs->fb;
+ fb->screen_base = bochs->fb_map;
+
+ fb->bits_per_pixel = 16;
+ fb->red.length = 5;
+ fb->green.length = 6;
+ fb->blue.length = 5;
+ fb->red.offset = 11;
+ fb->green.offset = 5;
+ fb->blue.offset = 0;
+
+ /* EDID is only exposed over PCI */
+ ret = -ENODEV;
+
+ if (mmio) {
+ ret = bochs_hw_load_edid(bochs);
+ if (ret)
+ dev_warn(dev, "couldn't read EDID information\n");
+ }
+
+ if (ret) {
+ fb->mode = xzalloc(sizeof(*fb->mode));
+ fb->modes.modes = fb->mode;
+ fb->modes.num_modes = 1;
+
+ fb->mode->name = "640x480";
+ fb->mode->xres = 640;
+ fb->mode->yres = 480;
+ }
+
+ fb->priv = bochs;
+ fb->fbops = &bochs_fb_ops;
+
+ fb->dev.parent = dev;
+ return register_framebuffer(fb);
+}
diff --git a/drivers/video/bochs/bochs_hw.h b/drivers/video/bochs/bochs_hw.h
new file mode 100644
index 0000000000..c721113656
--- /dev/null
+++ b/drivers/video/bochs/bochs_hw.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef BOCHS_HW_H
+#define BOCHS_HW_H
+
+#include <linux/compiler.h>
+
+#define VBE_DISPI_IOPORT_INDEX 0x01CE
+#define VBE_DISPI_IOPORT_DATA 0x01CF
+
+struct device;
+
+int bochs_hw_probe(struct device *dev, void __iomem *fb_map, void __iomem *mmio);
+
+#endif
diff --git a/drivers/video/bochs/bochs_isa.c b/drivers/video/bochs/bochs_isa.c
new file mode 100644
index 0000000000..50fdecd9c8
--- /dev/null
+++ b/drivers/video/bochs/bochs_isa.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright (c) 2020 Ahmad Fatoum, Pengutronix
+/*
+ * ISA driver entry point for VGA with the Bochs VBE / QEMU stdvga extensions.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <linux/ioport.h>
+#include "bochs_hw.h"
+
+static int bochs_isa_detect(void)
+{
+ struct device *dev;
+ int ret;
+
+ outw(0, VBE_DISPI_IOPORT_INDEX);
+ ret = inw(VBE_DISPI_IOPORT_DATA);
+
+ if ((ret & 0xB0C0) != 0xB0C0)
+ return -ENODEV;
+
+ dev = device_alloc("bochs-dispi", 0);
+
+ ret = platform_device_register(dev);
+ if (ret)
+ return ret;
+
+ return bochs_hw_probe(dev, IOMEM(0xe0000000), NULL);
+}
+device_initcall(bochs_isa_detect);
diff --git a/drivers/video/bochs/bochs_pci.c b/drivers/video/bochs/bochs_pci.c
new file mode 100644
index 0000000000..39c4d1b662
--- /dev/null
+++ b/drivers/video/bochs/bochs_pci.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright (c) 2020 Ahmad Fatoum, Pengutronix
+/*
+ * PCI driver entry point for VGA with the Bochs VBE / QEMU stdvga extensions.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <linux/pci.h>
+#include "bochs_hw.h"
+
+static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ void __iomem *fb_map, *mmio;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ fb_map = pci_iomap(pdev, 0);
+ mmio = pci_iomap(pdev, 2);
+
+ return bochs_hw_probe(&pdev->dev, fb_map, mmio);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(bochs_pci_tbl) = {
+ /* https://github.com/qemu/qemu/blob/master/docs/specs/standard-vga.txt */
+ { PCI_DEVICE(0x1234, 0x1111) },
+ { },
+};
+
+static struct pci_driver bochs_pci_driver = {
+ .name = "bochs-dispi",
+ .probe = bochs_pci_probe,
+ .id_table = bochs_pci_tbl,
+};
+device_pci_driver(bochs_pci_driver);
diff --git a/drivers/video/edid.c b/drivers/video/edid.c
index bee4594118..7e6747ccd5 100644
--- a/drivers/video/edid.c
+++ b/drivers/video/edid.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/video/edid.c
*
@@ -20,11 +21,6 @@
*
* GTF Spreadsheet by Andy Morrish (1/5/97)
* available at http://www.vesa.org
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
*/
#define pr_fmt(fmt) "EDID: " fmt
@@ -223,19 +219,19 @@ static int edid_checksum(unsigned char *edid)
return err;
}
-static int edid_check_header(unsigned char *edid)
+bool edid_check_header(unsigned char *edid)
{
- int i, err = 1, fix = check_edid(edid);
+ int i, fix = check_edid(edid);
if (fix)
fix_edid(edid, fix);
for (i = 0; i < 8; i++) {
if (edid[i] != edid_v1_header[i])
- err = 0;
+ return false;
}
- return err;
+ return true;
}
/*
@@ -851,17 +847,27 @@ edid_do_read_i2c(struct i2c_adapter *adapter, unsigned char *buf,
ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
} while (ret != xfers && --retries);
- return ret == xfers ? 0 : -1;
+ if (ret == 0)
+ ret = -EPROTO;
+
+ return ret == xfers ? 0 : ret;
}
void *edid_read_i2c(struct i2c_adapter *adapter)
{
u8 *block;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_I2C))
+ return NULL;
block = xmalloc(EDID_LENGTH);
- if (edid_do_read_i2c(adapter, block, 0, EDID_LENGTH))
+ ret = edid_do_read_i2c(adapter, block, 0, EDID_LENGTH);
+ if (ret) {
+ dev_dbg(&adapter->dev, "EDID readout failed: %pe\n", ERR_PTR(ret));
goto out;
+ }
return block;
out:
diff --git a/drivers/video/edid.h b/drivers/video/edid.h
index 006d9f2834..b4bd578c96 100644
--- a/drivers/video/edid.h
+++ b/drivers/video/edid.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/video/edid.h - EDID/DDC Header
*
@@ -9,11 +10,7 @@
* Ani Joshi <ajoshi@unixbox.com>
*
* DDC is a Trademark of VESA (Video Electronics Standard Association).
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
-*/
+ */
#ifndef __EDID_H__
#define __EDID_H__
@@ -135,4 +132,14 @@
#define DPMS_SUSPEND (1 << 6)
#define DPMS_STANDBY (1 << 7)
+/**
+ * edid_check_header - sanity check the header of the base EDID block
+ * @raw_edid: pointer to raw base EDID block
+ *
+ * Sanity check the header of the base EDID block.
+ *
+ * Return: true if the header is perfect, false if any byte is wrong.
+ */
+bool edid_check_header(unsigned char *edid);
+
#endif /* __EDID_H__ */
diff --git a/drivers/video/efi_gop.c b/drivers/video/efi_gop.c
index 7c083e4fb3..cd2506c04b 100644
--- a/drivers/video/efi_gop.c
+++ b/drivers/video/efi_gop.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2011 Intel Corporation; author Matt Fleming
* Copyright (c) 2017 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * GPL v2
*/
#include <common.h>
@@ -13,7 +12,7 @@
#include <errno.h>
#include <gui/graphic_utils.h>
#include <efi.h>
-#include <efi/efi.h>
+#include <efi/efi-payload.h>
#include <efi/efi-device.h>
#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR 0
@@ -64,7 +63,7 @@ struct efi_graphics_output_protocol {
};
struct efi_gop_priv {
- struct device_d *dev;
+ struct device *dev;
struct fb_info fb;
uint32_t mode;
@@ -239,11 +238,23 @@ static int efi_gop_probe(struct efi_device *efidev)
priv->fb.current_mode = priv->mode;
ret = register_framebuffer(&priv->fb);
- if (!ret) {
- priv->dev->priv = &priv->fb;
- return 0;
+ if (ret)
+ goto free_modes;
+
+ priv->dev->priv = &priv->fb;
+
+ if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE)) {
+ struct console_device *cdev;
+
+ cdev = console_get_by_dev(&priv->fb.dev);
+ if (cdev)
+ dev_add_param_fixed(&cdev->class_dev, "linux.bootargs.earlycon",
+ "earlycon=efifb");
}
+ return 0;
+
+free_modes:
if (priv->fb.modes.modes) {
int i;
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index 2d82bc01fa..6f412d62c4 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
#include <malloc.h>
#include <fb.h>
@@ -42,6 +43,12 @@ static int fb_close(struct cdev *cdev)
return 0;
}
+void fb_damage(struct fb_info *info, struct fb_rect *rect)
+{
+ if (info->fbops->fb_damage)
+ info->fbops->fb_damage(info, rect);
+}
+
static int fb_op_flush(struct cdev *cdev)
{
struct fb_info *info = cdev->priv;
@@ -119,22 +126,25 @@ int fb_disable(struct fb_info *info)
return 0;
}
+static int fb_enable_get(struct param_d *param, void *priv)
+{
+ struct fb_info *info = priv;
+
+ info->p_enable = info->enabled;
+ return 0;
+}
+
static int fb_enable_set(struct param_d *param, void *priv)
{
struct fb_info *info = priv;
- int enable;
if (!info->mode)
return -EINVAL;
- enable = info->p_enable;
-
- if (enable)
- fb_enable(info);
+ if (info->p_enable)
+ return fb_enable(info);
else
- fb_disable(info);
-
- return 0;
+ return fb_disable(info);
}
static struct fb_videomode *fb_num_to_mode(struct fb_info *info, int num)
@@ -154,7 +164,7 @@ static struct fb_videomode *fb_num_to_mode(struct fb_info *info, int num)
static int fb_setup_mode(struct fb_info *info)
{
- struct device_d *dev = &info->dev;
+ struct device *dev = &info->dev;
int ret;
struct fb_videomode *mode;
@@ -247,7 +257,7 @@ static void fb_print_modes(struct display_timings *modes)
fb_print_mode(&modes->modes[i]);
}
-static void fb_info(struct device_d *dev)
+static void fb_info(struct device *dev)
{
struct fb_info *info = dev->priv;
@@ -275,7 +285,7 @@ static int fb_set_shadowfb(struct param_d *p, void *priv)
int register_framebuffer(struct fb_info *info)
{
int id = get_free_deviceid("fb");
- struct device_d *dev;
+ struct device *dev;
int ret, num_modes, i;
const char **names;
@@ -314,7 +324,7 @@ int register_framebuffer(struct fb_info *info)
if (ret)
goto err_free;
- dev_add_param_bool(dev, "enable", fb_enable_set, NULL,
+ dev_add_param_bool(dev, "enable", fb_enable_set, fb_enable_get,
&info->p_enable, info);
if (IS_ENABLED(CONFIG_DRIVER_VIDEO_EDID))
diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c
index b261f17048..6c85e8e06a 100644
--- a/drivers/video/fbconsole.c
+++ b/drivers/video/fbconsole.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
#include <errno.h>
#include <malloc.h>
@@ -17,6 +18,12 @@ enum state_t {
struct fbc_priv {
struct console_device cdev;
struct fb_info *fb;
+ struct {
+ u32 top;
+ u32 left;
+ u32 bottom;
+ u32 right;
+ } margin;
struct screen *sc;
@@ -59,9 +66,26 @@ static int fbc_tstc(struct console_device *cdev)
static void cls(struct fbc_priv *priv)
{
void *buf = gui_screen_render_buffer(priv->sc);
+ struct fb_info *fb = priv->fb;
+ int width = fb->xres - priv->margin.left - priv->margin.right;
+ int height = fb->yres - priv->margin.top - priv->margin.bottom;
+ void *adr;
+
+ adr = buf + priv->fb->line_length * priv->margin.top;
+
+ if (!priv->margin.left && !priv->margin.right) {
+ memset(adr, 0, priv->fb->line_length * height);
+ } else {
+ int bpp = priv->fb->bits_per_pixel >> 3;
+ int y;
- memset(buf, 0, priv->fb->line_length * priv->fb->yres);
- gu_screen_blit(priv->sc);
+ for (y = 0; y < height; y++) {
+ memset(adr + priv->margin.left * bpp, 0, width * bpp);
+ adr += priv->fb->line_length;
+ }
+ }
+ gu_screen_blit_area(priv->sc, priv->margin.left, priv->margin.top,
+ width, height);
}
struct rgb {
@@ -121,7 +145,8 @@ static void drawchar(struct fbc_priv *priv, int x, int y, int c)
uint8_t t = inbuf[i];
int j;
- adr = buf + line_length * (y * priv->font->height + i) + x * priv->font->width * bpp;
+ adr = buf + line_length * (priv->margin.top + y * priv->font->height + i) +
+ (priv->margin.left + x * priv->font->width) * bpp;
for (j = 0; j < priv->font->width; j++) {
if (t & 0x80)
@@ -141,9 +166,11 @@ static void video_invertchar(struct fbc_priv *priv, int x, int y)
buf = gui_screen_render_buffer(priv->sc);
- gu_invert_area(priv->fb, buf, x * priv->font->width, y * priv->font->height,
+ gu_invert_area(priv->fb, buf, priv->margin.left + x * priv->font->width,
+ priv->margin.top + y * priv->font->height,
priv->font->width, priv->font->height);
- gu_screen_blit_area(priv->sc, x * priv->font->width, y * priv->font->height,
+ gu_screen_blit_area(priv->sc, priv->margin.left + x * priv->font->width,
+ priv->margin.top + y * priv->font->height,
priv->font->width, priv->font->height);
}
@@ -184,8 +211,9 @@ static void printchar(struct fbc_priv *priv, int c)
default:
drawchar(priv, priv->x, priv->y, c);
- gu_screen_blit_area(priv->sc, priv->x * priv->font->width,
- priv->y * priv->font->height,
+ gu_screen_blit_area(priv->sc,
+ priv->margin.left + priv->x * priv->font->width,
+ priv->margin.top + priv->y * priv->font->height,
priv->font->width, priv->font->height);
priv->x++;
@@ -197,15 +225,36 @@ static void printchar(struct fbc_priv *priv, int c)
if (priv->y > priv->rows) {
void *buf;
+ void *adr;
u32 line_length = priv->fb->line_length;
int line_height = line_length * priv->font->height;
+ int width = priv->fb->xres - priv->margin.left - priv->margin.right;
+ int height = (priv->rows + 1) * priv->font->height;
buf = gui_screen_render_buffer(priv->sc);
+ adr = buf + priv->margin.top * line_length;
+
+ if (!priv->margin.left && !priv->margin.right) {
+ memcpy(adr, adr + line_height, line_height * priv->rows);
+ memset(adr + line_height * priv->rows, 0, line_height);
+ } else {
+ int bpp = priv->fb->bits_per_pixel >> 3;
+ int y;
+
+ adr += priv->margin.left * bpp;
+
+ for (y = 0; y < height - priv->font->height; y++) {
+ memcpy(adr, adr + line_height, width * bpp);
+ adr += line_length;
+ }
+ for (y = height - priv->font->height; y < height; y++) {
+ memset(adr, 0, width * bpp);
+ adr += line_length;
+ }
+ }
- memcpy(buf, buf + line_height, line_height * priv->rows);
- memset(buf + line_height * priv->rows, 0, line_height);
-
- gu_screen_blit(priv->sc);
+ gu_screen_blit_area(priv->sc, priv->margin.left, priv->margin.top,
+ width, height);
priv->y = priv->rows;
}
@@ -400,8 +449,9 @@ static void fbc_putc(struct console_device *cdev, char c)
static int setup_font(struct fbc_priv *priv)
{
- struct fb_info *fb = priv->fb;
const struct font_desc *font;
+ unsigned int height = priv->fb->yres - priv->margin.top - priv->margin.bottom;
+ unsigned int width = priv->fb->xres - priv->margin.left - priv->margin.right;
font = find_font_enum(priv->par_font_val);
if (!font) {
@@ -410,8 +460,8 @@ static int setup_font(struct fbc_priv *priv)
priv->font = font;
- priv->rows = fb->yres / priv->font->height - 1;
- priv->cols = fb->xres / priv->font->width - 1;
+ priv->rows = height / priv->font->height - 1;
+ priv->cols = width / priv->font->width - 1;
return 0;
}
@@ -471,6 +521,35 @@ static int set_font(struct param_d *p, void *vpriv)
return 0;
}
+static int set_margin(struct param_d *p, void *vpriv)
+{
+ struct fbc_priv *priv = vpriv;
+ struct console_device *cdev = &priv->cdev;
+ int ret;
+
+ if (!priv->font) {
+ ret = setup_font(priv);
+ if (ret)
+ return ret;
+ }
+
+ priv->margin.left = min(priv->margin.left,
+ priv->fb->xres - priv->margin.right - priv->font->width);
+ priv->margin.top = min(priv->margin.top,
+ priv->fb->yres - priv->margin.bottom - priv->font->height);
+ priv->margin.right = min(priv->margin.right,
+ priv->fb->xres - priv->margin.left - priv->font->width);
+ priv->margin.bottom = min(priv->margin.bottom,
+ priv->fb->yres - priv->margin.top - priv->font->height);
+
+ if (cdev->f_active & (CONSOLE_STDOUT | CONSOLE_STDERR)) {
+ cls(priv);
+ setup_font(priv);
+ }
+
+ return 0;
+}
+
int register_fbconsole(struct fb_info *fb)
{
struct fbc_priv *priv;
@@ -507,6 +586,15 @@ int register_fbconsole(struct fb_info *fb)
set_font, NULL,
&priv->par_font_val, priv);
+ dev_add_param_uint32(&cdev->class_dev, "margin.top", set_margin,
+ NULL, &priv->margin.top, "%u", priv);
+ dev_add_param_uint32(&cdev->class_dev, "margin.left", set_margin,
+ NULL, &priv->margin.left, "%u", priv);
+ dev_add_param_uint32(&cdev->class_dev, "margin.bottom", set_margin,
+ NULL, &priv->margin.bottom, "%u", priv);
+ dev_add_param_uint32(&cdev->class_dev, "margin.right", set_margin,
+ NULL, &priv->margin.right, "%u", priv);
+
pr_info("registered as %s%d\n", cdev->class_dev.name, cdev->class_dev.id);
return 0;
diff --git a/drivers/video/imx-ipu-fb.c b/drivers/video/imx-ipu-fb.c
index 9cc7a911ea..e2ff01929b 100644
--- a/drivers/video/imx-ipu-fb.c
+++ b/drivers/video/imx-ipu-fb.c
@@ -1,34 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2009
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <dma.h>
#include <init.h>
#include <io.h>
-#include <mach/imx35-regs.h>
+#include <mach/imx/imx35-regs.h>
#include <fb.h>
-#include <mach/imxfb.h>
+#include <platform_data/imxfb.h>
#include <malloc.h>
#include <errno.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
#include <mmu.h>
-#include <mach/imx-ipu-fb.h>
+#include <mach/imx/imx-ipu-fb.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -42,7 +29,7 @@ struct ipu_fb_info {
struct fb_info info;
struct fb_info overlay;
- struct device_d *dev;
+ struct device *dev;
unsigned int alpha;
int disable_fractional_divider;
@@ -972,6 +959,7 @@ static int sdc_fb_register_overlay(struct ipu_fb_info *fbi, void *fb)
sdc_enable_channel(fbi, overlay->screen_base, IDMAC_SDC_1);
+ fbi->overlay.dev.parent = &fbi->info.dev;
ret = register_framebuffer(&fbi->overlay);
if (ret < 0) {
dev_err(fbi->dev, "failed to register framebuffer\n");
@@ -986,7 +974,7 @@ static int sdc_fb_register_overlay(struct ipu_fb_info *fbi, void *fb)
#endif
-static int imxfb_probe(struct device_d *dev)
+static int imxfb_probe(struct device *dev)
{
struct resource *iores;
struct ipu_fb_info *fbi;
@@ -1042,6 +1030,7 @@ static int imxfb_probe(struct device_d *dev)
sdc_enable_channel(fbi, info->screen_base, IDMAC_SDC_0);
+ fbi->info.dev.parent = dev;
ret = register_framebuffer(&fbi->info);
if (ret < 0) {
dev_err(dev, "failed to register framebuffer\n");
@@ -1054,7 +1043,7 @@ static int imxfb_probe(struct device_d *dev)
return ret;
}
-static struct driver_d imx3fb_driver = {
+static struct driver imx3fb_driver = {
.name = "imx-ipu-fb",
.probe = imxfb_probe,
};
diff --git a/drivers/video/imx-ipu-v3/Kconfig b/drivers/video/imx-ipu-v3/Kconfig
index 55aeac9415..4429e815cd 100644
--- a/drivers/video/imx-ipu-v3/Kconfig
+++ b/drivers/video/imx-ipu-v3/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config DRIVER_VIDEO_IMX_IPUV3
bool "i.MX IPUv3 driver"
depends on ARCH_IMX
diff --git a/drivers/video/imx-ipu-v3/Makefile b/drivers/video/imx-ipu-v3/Makefile
index 1f6812021e..709a9203a3 100644
--- a/drivers/video/imx-ipu-v3/Makefile
+++ b/drivers/video/imx-ipu-v3/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += ipu-common.o ipu-dmfc.o ipu-di.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += ipu-dp.o ipuv3-plane.o ipufb.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += ipu-dc.o
diff --git a/drivers/video/imx-ipu-v3/imx-hdmi.c b/drivers/video/imx-ipu-v3/imx-hdmi.c
index 17b6e4cc25..2d5fd98666 100644
--- a/drivers/video/imx-ipu-v3/imx-hdmi.c
+++ b/drivers/video/imx-ipu-v3/imx-hdmi.c
@@ -1,14 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* Designware High-Definition Multimedia Interface (HDMI) driver
*
* Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
*/
#include <common.h>
#include <fb.h>
@@ -19,13 +14,12 @@
#include <init.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <asm-generic/div64.h>
-#include <linux/clk.h>
+#include <linux/math64.h>
#include <i2c/i2c.h>
#include <video/media-bus-format.h>
#include <video/vpl.h>
-#include <mach/imx6-regs.h>
-#include <mach/imx53-regs.h>
+#include <mach/imx/imx6-regs.h>
+#include <mach/imx/imx53-regs.h>
#include "imx-ipu-v3.h"
#include "ipuv3-plane.h"
@@ -119,7 +113,7 @@ struct hdmi_data_info {
struct dw_hdmi {
enum dw_hdmi_devtype dev_type;
- struct device_d *dev;
+ struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
@@ -1083,19 +1077,18 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
/* Workaround to clear the overflow condition */
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
- int count;
+ int count = 4;
u8 val;
/* TMDS software reset */
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
- if (hdmi->dev_type == IMX6DL_HDMI) {
- hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
- return;
- }
- for (count = 0; count < 4; count++)
+ if (hdmi->dev_type == IMX6DL_HDMI)
+ count = 1;
+
+ while (count--)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
@@ -1193,32 +1186,18 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
}
-struct dw_hdmi_data {
- unsigned ipu_mask;
- enum dw_hdmi_devtype devtype;
-};
-
-static struct dw_hdmi_data imx6q_hdmi_data = {
- .ipu_mask = 0xf,
- .devtype = IMX6Q_HDMI,
-};
-
-static struct dw_hdmi_data imx6dl_hdmi_data = {
- .ipu_mask = 0x3,
- .devtype = IMX6DL_HDMI,
-};
-
static struct of_device_id dw_hdmi_dt_ids[] = {
{
.compatible = "fsl,imx6q-hdmi",
- .data = &imx6q_hdmi_data,
+ .data = (void *)IMX6Q_HDMI,
}, {
.compatible = "fsl,imx6dl-hdmi",
- .data = &imx6dl_hdmi_data,
+ .data = (void *)IMX6DL_HDMI,
}, {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, dw_hdmi_dt_ids);
static int dw_hdmi_get_modes(struct dw_hdmi *hdmi, struct display_timings *timings)
{
@@ -1270,17 +1249,12 @@ static int dw_hdmi_ioctl(struct vpl *vpl, unsigned int port,
return 0;
}
-static int dw_hdmi_probe(struct device_d *dev)
+static int dw_hdmi_probe(struct device *dev)
{
struct resource *iores;
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
struct dw_hdmi *hdmi;
int ret;
- const struct dw_hdmi_data *devtype;
-
- ret = dev_get_drvdata(dev, (const void **)&devtype);
- if (ret)
- return ret;
hdmi = xzalloc(sizeof(*hdmi));
@@ -1289,9 +1263,7 @@ static int dw_hdmi_probe(struct device_d *dev)
hdmi->sample_rate = 48000;
hdmi->ratio = 100;
- ret = dev_get_drvdata(dev, (const void **)&hdmi->dev_type);
- if (ret)
- return ret;
+ hdmi->dev_type = (enum dw_hdmi_devtype)device_get_match_data(dev);
hdmi->ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
@@ -1376,7 +1348,7 @@ err_isfr:
return ret;
}
-static struct driver_d dw_hdmi_driver = {
+static struct driver dw_hdmi_driver = {
.probe = dw_hdmi_probe,
.of_compatible = dw_hdmi_dt_ids,
.name = "imx-hdmi",
diff --git a/drivers/video/imx-ipu-v3/imx-hdmi.h b/drivers/video/imx-ipu-v3/imx-hdmi.h
index b3e144227f..dcffe75529 100644
--- a/drivers/video/imx-ipu-v3/imx-hdmi.h
+++ b/drivers/video/imx-ipu-v3/imx-hdmi.h
@@ -1,10 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2011 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef __IMX_HDMI_H__
diff --git a/drivers/video/imx-ipu-v3/imx-ipu-v3.h b/drivers/video/imx-ipu-v3/imx-ipu-v3.h
index cdfff6992f..8b78b716d3 100644
--- a/drivers/video/imx-ipu-v3/imx-ipu-v3.h
+++ b/drivers/video/imx-ipu-v3/imx-ipu-v3.h
@@ -1,12 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright 2005-2009 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU Lesser General
- * Public License. You may obtain a copy of the GNU Lesser General
- * Public License Version 2.1 or later at the following locations:
- *
- * http://www.opensource.org/licenses/lgpl-license.html
- * http://www.gnu.org/copyleft/lgpl.html
*/
#ifndef __DRM_IPU_H__
diff --git a/drivers/video/imx-ipu-v3/imx-ldb.c b/drivers/video/imx-ipu-v3/imx-ldb.c
index 9b4524274c..3ed6d44f5b 100644
--- a/drivers/video/imx-ipu-v3/imx-ldb.c
+++ b/drivers/video/imx-ipu-v3/imx-ldb.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i.MX drm driver - parallel display implementation
*
* Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
*/
#include <common.h>
@@ -31,10 +18,9 @@
#include <mfd/imx6q-iomuxc-gpr.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <asm-generic/div64.h>
-#include <linux/clk.h>
-#include <mach/imx6-regs.h>
-#include <mach/imx53-regs.h>
+#include <linux/math64.h>
+#include <mach/imx/imx6-regs.h>
+#include <mach/imx/imx53-regs.h>
#include "imx-ipu-v3.h"
#include "ipuv3-plane.h"
@@ -75,7 +61,7 @@ struct imx_ldb_data {
};
struct imx_ldb {
- struct device_d *dev;
+ struct device *dev;
u32 bus_format;
int mode_valid;
struct imx_ldb_channel channel[2];
@@ -162,7 +148,7 @@ static int imx6q_set_clock(struct imx_ldb *ldb, int ipuno, int dino, int chno, u
diclk = clk_lookup(clkname);
free(clkname);
if (IS_ERR(diclk)) {
- dev_err(ldb->dev, "failed to get di clk: %s\n", strerrorp(diclk));
+ dev_err(ldb->dev, "failed to get di clk: %pe\n", diclk);
return PTR_ERR(diclk);
}
@@ -170,7 +156,7 @@ static int imx6q_set_clock(struct imx_ldb *ldb, int ipuno, int dino, int chno, u
ldbclk = clk_lookup(clkname);
free(clkname);
if (IS_ERR(ldbclk)) {
- dev_err(ldb->dev, "failed to get ldb clk: %s\n", strerrorp(ldbclk));
+ dev_err(ldb->dev, "failed to get ldb clk: %pe\n", ldbclk);
return PTR_ERR(ldbclk);
}
@@ -233,7 +219,7 @@ static int imx53_ldb_prepare(struct imx_ldb_channel *imx_ldb_ch, int di,
diclk = clk_lookup(clkname);
free(clkname);
if (IS_ERR(diclk)) {
- dev_err(ldb->dev, "failed to get di clk: %s\n", strerrorp(diclk));
+ dev_err(ldb->dev, "failed to get di clk: %pe\n", diclk);
return PTR_ERR(diclk);
}
@@ -241,7 +227,7 @@ static int imx53_ldb_prepare(struct imx_ldb_channel *imx_ldb_ch, int di,
ldbclk = clk_lookup(clkname);
free(clkname);
if (IS_ERR(ldbclk)) {
- dev_err(ldb->dev, "failed to get ldb clk: %s\n", strerrorp(ldbclk));
+ dev_err(ldb->dev, "failed to get ldb clk: %pe\n", ldbclk);
return PTR_ERR(ldbclk);
}
@@ -316,9 +302,9 @@ static int imx_ldb_ioctl(struct vpl *vpl, unsigned int port,
return 0;
}
-static int imx_ldb_probe(struct device_d *dev)
+static int imx_ldb_probe(struct device *dev)
{
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
struct device_node *child;
struct imx_ldb *imx_ldb;
int ret, i;
@@ -417,8 +403,9 @@ static struct of_device_id imx_ldb_dt_ids[] = {
{ .compatible = "fsl,imx53-ldb", &imx_ldb_data_imx53},
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
-static struct driver_d imx_ldb_driver = {
+static struct driver imx_ldb_driver = {
.probe = imx_ldb_probe,
.of_compatible = imx_ldb_dt_ids,
.name = "imx-ldb",
diff --git a/drivers/video/imx-ipu-v3/imx-pd.c b/drivers/video/imx-ipu-v3/imx-pd.c
index 601be35880..d8b5f90a6c 100644
--- a/drivers/video/imx-ipu-v3/imx-pd.c
+++ b/drivers/video/imx-ipu-v3/imx-pd.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i.MX drm driver - parallel display implementation
*
* Copyright (C) 2016 Philippe Leduc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <common.h>
@@ -27,8 +19,10 @@
#include "imx-ipu-v3.h"
+#define IMX_PD_OUTPUT_PORT 1
+
struct imx_pd {
- struct device_d *dev;
+ struct device *dev;
struct display_timings *timings;
u32 bus_format;
struct vpl vpl;
@@ -39,7 +33,6 @@ static int imx_pd_ioctl(struct vpl *vpl, unsigned int port,
{
struct imx_pd *imx_pd = container_of(vpl, struct imx_pd, vpl);
struct ipu_di_mode *mode;
- struct display_timings *timings;
switch (cmd) {
case IMX_IPU_VPL_DI_MODE:
@@ -50,22 +43,29 @@ static int imx_pd_ioctl(struct vpl *vpl, unsigned int port,
return 0;
case VPL_GET_VIDEOMODES:
- timings = data;
-
- timings->num_modes = imx_pd->timings->num_modes;
- timings->native_mode = imx_pd->timings->native_mode;
- timings->modes = imx_pd->timings->modes;
- timings->edid = NULL;
- return 0;
+ if (imx_pd->timings) {
+ struct display_timings *timings = data;
+
+ timings->num_modes = imx_pd->timings->num_modes;
+ timings->native_mode = imx_pd->timings->native_mode;
+ timings->modes = imx_pd->timings->modes;
+ timings->edid = NULL;
+ return 0;
+ }
+ break;
}
+ if (!imx_pd->timings)
+ return vpl_ioctl(vpl, IMX_PD_OUTPUT_PORT, cmd, data);
+
return 0;
}
-static int imx_pd_probe(struct device_d *dev)
+static int imx_pd_probe(struct device *dev)
{
- struct device_node *node = dev->device_node;
+ struct device_node *node = dev->of_node;
struct imx_pd *imx_pd;
+ struct device_node *port;
const char *fmt;
int ret;
@@ -88,8 +88,11 @@ static int imx_pd_probe(struct device_d *dev)
imx_pd->timings = of_get_display_timings(node);
if (!imx_pd->timings) {
- dev_err(dev, "No display timings panel found\n");
- return -EINVAL;
+ port = of_graph_get_port_by_id(node, IMX_PD_OUTPUT_PORT);
+ if (!port) {
+ dev_err(dev, "Neither display timings in nor remote panel found in node\n");
+ return -EINVAL;
+ }
}
imx_pd->vpl.node = node;
@@ -105,8 +108,9 @@ static struct of_device_id imx_pd_dt_ids[] = {
{ .compatible = "fsl,imx-parallel-display", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
-static struct driver_d imx_pd_driver = {
+static struct driver imx_pd_driver = {
.probe = imx_pd_probe,
.of_compatible = imx_pd_dt_ids,
.name = "imx-parallel-display",
diff --git a/drivers/video/imx-ipu-v3/ipu-common.c b/drivers/video/imx-ipu-v3/ipu-common.c
index 1811e50227..4909119d87 100644
--- a/drivers/video/imx-ipu-v3/ipu-common.c
+++ b/drivers/video/imx-ipu-v3/ipu-common.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
* Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
*/
#include <common.h>
@@ -20,10 +11,10 @@
#include <driver.h>
#include <init.h>
#include <linux/mutex.h>
-#include <mach/generic.h>
-#include <mach/imx6-regs.h>
-#include <mach/imx53-regs.h>
-#include <mach/imx51-regs.h>
+#include <mach/imx/generic.h>
+#include <mach/imx/imx6-regs.h>
+#include <mach/imx/imx53-regs.h>
+#include <mach/imx/imx51-regs.h>
#include "imx-ipu-v3.h"
#include "ipu-prv.h"
@@ -618,9 +609,10 @@ static struct of_device_id imx_ipu_dt_ids[] = {
{ .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
static int ipu_submodules_init(struct ipu_soc *ipu,
- struct device_d *dev, void __iomem *ipu_base,
+ struct device *dev, void __iomem *ipu_base,
struct clk *ipu_clk)
{
char *unit;
@@ -714,16 +706,16 @@ static struct ipu_platform_reg client_reg[] = {
static int ipu_client_id;
-static int ipu_add_subdevice_pdata(struct device_d *ipu_dev,
- struct ipu_platform_reg *reg)
+static int ipu_add_subdevice_pdata(struct device *ipu_dev,
+ struct ipu_platform_reg *reg)
{
- struct device_d *dev;
+ struct device *dev;
int ret;
dev = device_alloc(reg->name, ipu_client_id++);
dev->parent = ipu_dev;
device_add_data(dev, &reg->pdata, sizeof(reg->pdata));
- ((struct ipu_client_platformdata *)dev->platform_data)->device_node = ipu_dev->device_node;
+ ((struct ipu_client_platformdata *)dev->platform_data)->device_node = ipu_dev->of_node;
ret = platform_device_register(dev);
@@ -749,7 +741,7 @@ err_register:
return ret;
}
-static int ipu_probe(struct device_d *dev)
+static int ipu_probe(struct device *dev)
{
struct resource *iores;
struct ipu_soc *ipu;
@@ -804,9 +796,8 @@ static int ipu_probe(struct device_d *dev)
ipu->clk = clk_get(dev, "bus");
if (IS_ERR(ipu->clk)) {
- ret = PTR_ERR(ipu->clk);
- dev_err(dev, "clk_get failed: %s\n", strerror(-ret));
- return ret;
+ dev_err(dev, "clk_get failed: %pe\n", ipu->clk);
+ return PTR_ERR(ipu->clk);
}
dev->priv = ipu;
@@ -854,7 +845,7 @@ out_failed_reset:
return ret;
}
-static struct driver_d imx_ipu_driver = {
+static struct driver imx_ipu_driver = {
.name = "imx-ipuv3",
.of_compatible = imx_ipu_dt_ids,
.probe = ipu_probe,
diff --git a/drivers/video/imx-ipu-v3/ipu-dc.c b/drivers/video/imx-ipu-v3/ipu-dc.c
index 7b343e8149..a0292fc4a1 100644
--- a/drivers/video/imx-ipu-v3/ipu-dc.c
+++ b/drivers/video/imx-ipu-v3/ipu-dc.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
* Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
*/
#include <common.h>
@@ -105,7 +96,7 @@ struct ipu_dc_priv {
void __iomem *dc_reg;
void __iomem *dc_tmpl_reg;
struct ipu_soc *ipu;
- struct device_d *dev;
+ struct device *dev;
struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
};
@@ -321,7 +312,7 @@ void ipu_dc_put(struct ipu_dc *dc)
}
EXPORT_SYMBOL_GPL(ipu_dc_put);
-int ipu_dc_init(struct ipu_soc *ipu, struct device_d *dev,
+int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
void __iomem *base, void __iomem *template_base)
{
struct ipu_dc_priv *priv;
diff --git a/drivers/video/imx-ipu-v3/ipu-di.c b/drivers/video/imx-ipu-v3/ipu-di.c
index b4302412e0..6156911bfc 100644
--- a/drivers/video/imx-ipu-v3/ipu-di.c
+++ b/drivers/video/imx-ipu-v3/ipu-di.c
@@ -1,21 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
* Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
*/
#include <common.h>
#include <linux/err.h>
#include <linux/clk.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
#include <malloc.h>
#include "imx-ipu-v3.h"
@@ -167,9 +158,10 @@ static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
return div;
}
-static unsigned long clk_di_recalc_rate(struct clk *clk,
+static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
+ struct clk *clk = clk_hw_to_clk(hw);
struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel);
unsigned long outrate;
u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
@@ -182,9 +174,10 @@ static unsigned long clk_di_recalc_rate(struct clk *clk,
return outrate;
}
-static long clk_di_round_rate(struct clk *clk, unsigned long rate,
+static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
+ struct clk *clk = clk_hw_to_clk(hw);
struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel);
unsigned long outrate;
int div;
@@ -206,9 +199,10 @@ static long clk_di_round_rate(struct clk *clk, unsigned long rate,
return outrate;
}
-static int clk_di_set_rate(struct clk *clk, unsigned long rate,
+static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
+ struct clk *clk = clk_hw_to_clk(hw);
struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel);
int div;
u32 clkgen0;
@@ -224,8 +218,9 @@ static int clk_di_set_rate(struct clk *clk, unsigned long rate,
return 0;
}
-static int clk_di_get_parent(struct clk *clk)
+static int clk_di_get_parent(struct clk_hw *hw)
{
+ struct clk *clk = clk_hw_to_clk(hw);
struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel);
u32 val;
@@ -234,8 +229,9 @@ static int clk_di_get_parent(struct clk *clk)
return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
}
-static int clk_di_set_parent(struct clk *clk, u8 index)
+static int clk_di_set_parent(struct clk_hw *hw, u8 index)
{
+ struct clk *clk = clk_hw_to_clk(hw);
struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel);
u32 val;
@@ -704,7 +700,7 @@ void ipu_di_put(struct ipu_di *di)
}
EXPORT_SYMBOL_GPL(ipu_di_put);
-int ipu_di_init(struct ipu_soc *ipu, struct device_d *dev, int id,
+int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
void __iomem *base,
u32 module, struct clk *clk_ipu)
{
@@ -740,7 +736,7 @@ int ipu_di_init(struct ipu_soc *ipu, struct device_d *dev, int id,
di->clk_di_pixel.ops = &clk_di_ops;
di->clk_di_pixel.num_parents = 2;
di->clk_di_pixel.name = di->clk_name;
- ret = clk_register(&di->clk_di_pixel);
+ ret = bclk_register(&di->clk_di_pixel);
if (ret)
goto failed_clk_register;
diff --git a/drivers/video/imx-ipu-v3/ipu-dmfc.c b/drivers/video/imx-ipu-v3/ipu-dmfc.c
index 29c4bb4780..4be6a15eef 100644
--- a/drivers/video/imx-ipu-v3/ipu-dmfc.c
+++ b/drivers/video/imx-ipu-v3/ipu-dmfc.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
* Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
*/
#include <common.h>
@@ -109,7 +100,7 @@ struct dmfc_channel {
struct ipu_dmfc_priv {
struct ipu_soc *ipu;
- struct device_d *dev;
+ struct device *dev;
struct dmfc_channel channels[DMFC_NUM_CHANNELS];
unsigned long bandwidth_per_slot;
void __iomem *base;
@@ -349,8 +340,8 @@ void ipu_dmfc_put(struct dmfc_channel *dmfc)
}
EXPORT_SYMBOL_GPL(ipu_dmfc_put);
-int ipu_dmfc_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base,
- struct clk *ipu_clk)
+int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, void __iomem *base,
+ struct clk *ipu_clk)
{
struct ipu_dmfc_priv *priv;
int i;
diff --git a/drivers/video/imx-ipu-v3/ipu-dp.c b/drivers/video/imx-ipu-v3/ipu-dp.c
index 8829954db0..68b45c11c7 100644
--- a/drivers/video/imx-ipu-v3/ipu-dp.c
+++ b/drivers/video/imx-ipu-v3/ipu-dp.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
* Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
*/
#include <common.h>
#include <linux/err.h>
@@ -65,7 +56,7 @@ struct ipu_flow {
struct ipu_dp_priv {
struct ipu_soc *ipu;
- struct device_d *dev;
+ struct device *dev;
void __iomem *base;
struct ipu_flow flow[IPUV3_NUM_FLOWS];
int use_count;
@@ -286,7 +277,7 @@ void ipu_dp_put(struct ipu_dp *dp)
}
EXPORT_SYMBOL_GPL(ipu_dp_put);
-int ipu_dp_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base)
+int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, void __iomem *base)
{
struct ipu_dp_priv *priv;
int i;
diff --git a/drivers/video/imx-ipu-v3/ipu-prv.h b/drivers/video/imx-ipu-v3/ipu-prv.h
index 4d1c0692de..4465711ee4 100644
--- a/drivers/video/imx-ipu-v3/ipu-prv.h
+++ b/drivers/video/imx-ipu-v3/ipu-prv.h
@@ -1,16 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
* Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
*/
#ifndef __IPU_PRV_H__
#define __IPU_PRV_H__
@@ -149,7 +140,7 @@ struct ipu_di;
struct ipu_devtype;
struct ipu_soc {
- struct device_d *dev;
+ struct device *dev;
const struct ipu_devtype *devtype;
enum ipuv3_type ipu_type;
spinlock_t lock;
@@ -181,22 +172,23 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
-int ipu_di_init(struct ipu_soc *ipu, struct device_d *dev, int id,
+int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
void __iomem *base, u32 module, struct clk *ipu_clk);
void ipu_di_exit(struct ipu_soc *ipu, int id);
-int ipu_dmfc_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base,
- struct clk *ipu_clk);
+int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, void __iomem *base,
+ struct clk *ipu_clk);
void ipu_dmfc_exit(struct ipu_soc *ipu);
-int ipu_dp_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base);
+int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, void __iomem *base);
void ipu_dp_exit(struct ipu_soc *ipu);
-int ipu_dc_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base,
+int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, void __iomem *base,
void __iomem *template_base);
void ipu_dc_exit(struct ipu_soc *ipu);
-int ipu_cpmem_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base);
+int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev,
+ void __iomem *base);
void ipu_cpmem_exit(struct ipu_soc *ipu);
#endif /* __IPU_PRV_H__ */
diff --git a/drivers/video/imx-ipu-v3/ipufb.c b/drivers/video/imx-ipu-v3/ipufb.c
index 683f298e76..e4ac988053 100644
--- a/drivers/video/imx-ipu-v3/ipufb.c
+++ b/drivers/video/imx-ipu-v3/ipufb.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Freescale i.MX Frame Buffer device driver
*
* Copyright (C) 2004 Sascha Hauer, Pengutronix
* Based on acornfb.c Copyright (C) Russell King.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
*/
#define pr_fmt(fmt) "IPU: " fmt
@@ -22,7 +18,7 @@
#include <of_graph.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
#include <video/media-bus-format.h>
#include "imx-ipu-v3.h"
@@ -49,7 +45,7 @@ struct ipufb_info {
struct fb_videomode *mode;
struct fb_info info;
- struct device_d *dev;
+ struct device *dev;
/* plane[0] is the full plane, plane[1] is the partial plane */
struct ipu_plane *plane[2];
@@ -111,10 +107,8 @@ static int ipu_crtc_mode_set(struct ipufb_info *fbi,
struct ipu_di_mode di_mode = {};
u32 bus_format = 0;
- dev_info(fbi->dev, "%s: mode->xres: %d\n", __func__,
- mode->xres);
- dev_info(fbi->dev, "%s: mode->yres: %d\n", __func__,
- mode->yres);
+ dev_info(fbi->dev, "%s: mode->xres: %d mode->yres: %d\n", __func__,
+ mode->xres, mode->yres);
vpl_ioctl(&fbi->vpl, 2 + fbi->dino, IMX_IPU_VPL_DI_MODE, &di_mode);
vpl_ioctl(&fbi->vpl, 2 + fbi->dino, VPL_GET_BUS_FORMAT, &bus_format);
@@ -275,7 +269,7 @@ err_out:
return ret;
}
-static int ipufb_probe(struct device_d *dev)
+static int ipufb_probe(struct device *dev)
{
struct ipufb_info *fbi;
struct fb_info *info;
@@ -288,7 +282,7 @@ static int ipufb_probe(struct device_d *dev)
fbi = xzalloc(sizeof(*fbi));
info = &fbi->info;
- ipuid = of_alias_get_id(dev->parent->device_node, "ipu");
+ ipuid = of_alias_get_id(dev->parent->of_node, "ipu");
fbi->name = basprintf("ipu%d-di%d", ipuid + 1, pdata->di);
fbi->id = ipuid * 2 + pdata->di;
fbi->dino = pdata->di;
@@ -311,11 +305,12 @@ static int ipufb_probe(struct device_d *dev)
if (ret)
return ret;
- node = of_graph_get_port_by_id(dev->parent->device_node, 2 + pdata->di);
+ node = of_graph_get_port_by_id(dev->parent->of_node, 2 + pdata->di);
if (node && of_graph_port_is_available(node)) {
- dev_dbg(fbi->dev, "register vpl for %s\n", dev->parent->device_node->full_name);
+ dev_dbg(fbi->dev, "register vpl for %pOF\n",
+ dev->parent->of_node);
- fbi->vpl.node = dev->parent->device_node;
+ fbi->vpl.node = dev->parent->of_node;
ret = vpl_register(&fbi->vpl);
if (ret)
return ret;
@@ -336,6 +331,7 @@ static int ipufb_probe(struct device_d *dev)
if (ret)
dev_dbg(fbi->dev, "failed to get modes: %s\n", strerror(-ret));
+ info->dev.parent = dev;
ret = register_framebuffer(info);
if (ret < 0) {
dev_err(fbi->dev, "failed to register framebuffer\n");
@@ -346,18 +342,14 @@ static int ipufb_probe(struct device_d *dev)
return ret;
}
-static void ipufb_remove(struct device_d *dev)
+static void ipufb_remove(struct device *dev)
{
}
-static struct driver_d ipufb_driver = {
+static struct driver ipufb_driver = {
.name = "imx-ipuv3-crtc",
.probe = ipufb_probe,
.remove = ipufb_remove,
};
-static int ipufb_register(void)
-{
- return platform_driver_register(&ipufb_driver);
-}
-late_initcall(ipufb_register);
+late_platform_driver(ipufb_driver);
diff --git a/drivers/video/imx-ipu-v3/ipuv3-plane.c b/drivers/video/imx-ipu-v3/ipuv3-plane.c
index 9dffcfc670..aed7a46963 100644
--- a/drivers/video/imx-ipu-v3/ipuv3-plane.c
+++ b/drivers/video/imx-ipu-v3/ipuv3-plane.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i.MX IPUv3 DP Overlay Planes
*
* Copyright (C) 2013 Philipp Zabel, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <common.h>
#include <linux/err.h>
@@ -63,7 +55,7 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane,
uint32_t src_w, uint32_t src_h)
{
struct ipu_ch_param __iomem *cpmem;
- struct device_d *dev = &info->dev;
+ struct device *dev = &info->dev;
int ret;
/* no scaling */
diff --git a/drivers/video/imx-ipu-v3/ipuv3-plane.h b/drivers/video/imx-ipu-v3/ipuv3-plane.h
index 3d52f807fe..cade98e3e9 100644
--- a/drivers/video/imx-ipu-v3/ipuv3-plane.h
+++ b/drivers/video/imx-ipu-v3/ipuv3-plane.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __IPUV3_PLANE_H__
#define __IPUV3_PLANE_H__
diff --git a/drivers/video/imx.c b/drivers/video/imx.c
index d15c2d88fb..cb1c11b4cb 100644
--- a/drivers/video/imx.c
+++ b/drivers/video/imx.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Freescale i.MX Frame Buffer device driver
*
* Copyright (C) 2004 Sascha Hauer, Pengutronix
* Based on acornfb.c Copyright (C) Russell King.
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
* Please direct your questions and comments on this driver to the following
* email address:
*
@@ -17,7 +14,7 @@
#include <common.h>
#include <fb.h>
#include <io.h>
-#include <mach/imxfb.h>
+#include <platform_data/imxfb.h>
#include <driver.h>
#include <malloc.h>
#include <errno.h>
@@ -25,7 +22,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/sizes.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
#define LCDC_SSA 0x00
@@ -153,7 +150,7 @@ struct imxfb_info {
unused:30;
struct fb_info info;
- struct device_d *dev;
+ struct device *dev;
void (*enable)(int enable);
@@ -381,7 +378,7 @@ static struct fb_ops imxfb_ops = {
.fb_activate_var = imxfb_activate_var,
};
-static int imxfb_allocate_fbbuffer(const struct device_d *dev,
+static int imxfb_allocate_fbbuffer(const struct device *dev,
struct fb_info *info, void *forcefb)
{
size_t fbsize = info->xres * info->yres * (info->bits_per_pixel >> 3);
@@ -404,7 +401,7 @@ static int imxfb_allocate_fbbuffer(const struct device_d *dev,
* allocation as necessary, but in the absense of a better
* function just use it.
*/
- info->screen_base = memalign(fbsize, SZ_4M);
+ info->screen_base = memalign(SZ_4M, fbsize);
if (!info->screen_base)
return -ENOMEM;
memset(info->screen_base, 0, fbsize);
@@ -514,6 +511,7 @@ static int imxfb_register_overlay(struct imxfb_info *fbi, void *fb)
overlay->blue = rgb->blue;
overlay->transp = rgb->transp;
+ overlay->dev.parent = &fbi->info.dev;
ret = register_framebuffer(overlay);
if (ret < 0) {
dev_err(fbi->dev, "failed to register framebuffer\n");
@@ -527,7 +525,7 @@ static int imxfb_register_overlay(struct imxfb_info *fbi, void *fb)
}
#endif
-static int imxfb_probe(struct device_d *dev)
+static int imxfb_probe(struct device *dev)
{
struct resource *iores;
struct imxfb_info *fbi;
@@ -592,6 +590,7 @@ static int imxfb_probe(struct device_d *dev)
imxfb_activate_var(&fbi->info);
+ fbi->info.dev.parent = dev;
ret = register_framebuffer(&fbi->info);
if (ret < 0) {
dev_err(dev, "failed to register framebuffer\n");
@@ -603,7 +602,7 @@ static int imxfb_probe(struct device_d *dev)
return 0;
}
-static struct driver_d imxfb_driver = {
+static struct driver imxfb_driver = {
.name = "imxfb",
.probe = imxfb_probe,
};
diff --git a/drivers/video/mipi_dbi.c b/drivers/video/mipi_dbi.c
new file mode 100644
index 0000000000..2f8d6ecc72
--- /dev/null
+++ b/drivers/video/mipi_dbi.c
@@ -0,0 +1,745 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MIPI Display Bus Interface (DBI) LCD controller support
+ *
+ * Copyright 2016 Noralf Trønnes
+ */
+
+#define pr_fmt(fmt) "mipi-dbi: " fmt
+
+#include <common.h>
+#include <dma.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <linux/gpio/consumer.h>
+#include <regulator.h>
+#include <spi/spi.h>
+#include <video/backlight.h>
+#include <video/mipi_dbi.h>
+
+#include <video/vpl.h>
+#include <video/mipi_display.h>
+#include <video/fourcc.h>
+
+#define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */
+
+#define DCS_POWER_MODE_DISPLAY BIT(2)
+#define DCS_POWER_MODE_DISPLAY_NORMAL_MODE BIT(3)
+#define DCS_POWER_MODE_SLEEP_MODE BIT(4)
+#define DCS_POWER_MODE_PARTIAL_MODE BIT(5)
+#define DCS_POWER_MODE_IDLE_MODE BIT(6)
+#define DCS_POWER_MODE_RESERVED_MASK (BIT(0) | BIT(1) | BIT(7))
+
+LIST_HEAD(mipi_dbi_list);
+EXPORT_SYMBOL(mipi_dbi_list);
+
+/**
+ * DOC: overview
+ *
+ * This library provides helpers for MIPI Display Bus Interface (DBI)
+ * compatible display controllers.
+ *
+ * Many controllers for tiny lcd displays are MIPI compliant and can use this
+ * library. If a controller uses registers 0x2A and 0x2B to set the area to
+ * update and uses register 0x2C to write to frame memory, it is most likely
+ * MIPI compliant.
+ *
+ * Only MIPI Type 1 displays are supported since a full frame memory is needed.
+ *
+ * There are 3 MIPI DBI implementation types:
+ *
+ * A. Motorola 6800 type parallel bus
+ *
+ * B. Intel 8080 type parallel bus
+ *
+ * C. SPI type with 3 options:
+ *
+ * 1. 9-bit with the Data/Command signal as the ninth bit
+ * 2. Same as above except it's sent as 16 bits
+ * 3. 8-bit with the Data/Command signal as a separate D/CX pin
+ *
+ * Currently barebox mipi_dbi only supports Type C option 3 with
+ * mipi_dbi_spi_init().
+ */
+
+#define MIPI_DBI_DEBUG_COMMAND(cmd, data, len) \
+({ \
+ if (!len) \
+ pr_debug("cmd=%02x\n", cmd); \
+ else if (len <= 32) \
+ pr_debug("cmd=%02x, par=%*ph\n", cmd, (int)len, data);\
+ else \
+ pr_debug("cmd=%02x, len=%zu\n", cmd, len); \
+})
+
+static const u8 mipi_dbi_dcs_read_commands[] = {
+ MIPI_DCS_GET_DISPLAY_ID,
+ MIPI_DCS_GET_RED_CHANNEL,
+ MIPI_DCS_GET_GREEN_CHANNEL,
+ MIPI_DCS_GET_BLUE_CHANNEL,
+ MIPI_DCS_GET_DISPLAY_STATUS,
+ MIPI_DCS_GET_POWER_MODE,
+ MIPI_DCS_GET_ADDRESS_MODE,
+ MIPI_DCS_GET_PIXEL_FORMAT,
+ MIPI_DCS_GET_DISPLAY_MODE,
+ MIPI_DCS_GET_SIGNAL_MODE,
+ MIPI_DCS_GET_DIAGNOSTIC_RESULT,
+ MIPI_DCS_READ_MEMORY_START,
+ MIPI_DCS_READ_MEMORY_CONTINUE,
+ MIPI_DCS_GET_SCANLINE,
+ MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
+ MIPI_DCS_GET_CONTROL_DISPLAY,
+ MIPI_DCS_GET_POWER_SAVE,
+ MIPI_DCS_GET_CABC_MIN_BRIGHTNESS,
+ MIPI_DCS_READ_DDB_START,
+ MIPI_DCS_READ_DDB_CONTINUE,
+ 0, /* sentinel */
+};
+
+bool mipi_dbi_command_is_read(struct mipi_dbi *dbi, u8 cmd)
+{
+ unsigned int i;
+
+ if (!dbi->read_commands)
+ return false;
+
+ for (i = 0; i < 0xff; i++) {
+ if (!dbi->read_commands[i])
+ return false;
+ if (cmd == dbi->read_commands[i])
+ return true;
+ }
+
+ return false;
+}
+
+int mipi_dbi_command_read_len(int cmd)
+{
+ switch (cmd) {
+ case MIPI_DCS_READ_MEMORY_START:
+ case MIPI_DCS_READ_MEMORY_CONTINUE:
+ return 2;
+ case MIPI_DCS_GET_DISPLAY_ID:
+ return 3;
+ case MIPI_DCS_GET_DISPLAY_STATUS:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+/**
+ * mipi_dbi_command_read - MIPI DCS read command
+ * @dbi: MIPI DBI structure
+ * @cmd: Command
+ * @val: Value read
+ *
+ * Send MIPI DCS read command to the controller.
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_command_read(struct mipi_dbi *dbi, u8 cmd, u8 *val)
+{
+ if (!dbi->read_commands)
+ return -EACCES;
+
+ if (!mipi_dbi_command_is_read(dbi, cmd))
+ return -EINVAL;
+
+ return mipi_dbi_command_buf(dbi, cmd, val, 1);
+}
+EXPORT_SYMBOL(mipi_dbi_command_read);
+
+/**
+ * mipi_dbi_command_buf - MIPI DCS command with parameter(s) in an array
+ * @dbi: MIPI DBI structure
+ * @cmd: Command
+ * @data: Parameter buffer
+ * @len: Buffer length
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len)
+{
+ u8 *cmdbuf;
+ int ret;
+
+ /* SPI requires dma-safe buffers */
+ cmdbuf = kmemdup(&cmd, 1, GFP_KERNEL);
+ if (!cmdbuf)
+ return -ENOMEM;
+
+ ret = dbi->command(dbi, cmdbuf, data, len);
+
+ kfree(cmdbuf);
+
+ return ret;
+}
+EXPORT_SYMBOL(mipi_dbi_command_buf);
+
+/* This should only be used by mipi_dbi_command() */
+int mipi_dbi_command_stackbuf(struct mipi_dbi *dbi, u8 cmd, const u8 *data,
+ size_t len)
+{
+ u8 *buf;
+ int ret;
+
+ buf = kmemdup(data, len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = mipi_dbi_command_buf(dbi, cmd, buf, len);
+
+ kfree(buf);
+
+ return ret;
+}
+EXPORT_SYMBOL(mipi_dbi_command_stackbuf);
+
+/**
+ * mipi_dbi_buf_copy - Copy a framebuffer, transforming it if necessary
+ * @dst: The destination buffer
+ * @info: The source framebuffer info
+ * @clip: Clipping rectangle of the area to be copied
+ * @swap: When true, swap MSB/LSB of 16-bit values
+ */
+static void mipi_dbi_buf_copy(u16 *dst, struct fb_info *info,
+ struct fb_rect *clip, bool swap)
+{
+ u16 *src = (u16 *)info->screen_base;
+ unsigned int height = clip->y2 - clip->y1;
+ unsigned int width = clip->x2 - clip->x1;
+ int x, y;
+
+ src += clip->y1 * info->xres + clip->x1;
+ if (swap) {
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ *dst++ = src[x] << 8 | src[x] >> 8;
+ src += info->xres;
+ }
+ } else {
+ for (y = 0; y < height; y++) {
+ memcpy(dst, src, 2 * width);
+ dst += width;
+ src += info->xres;
+ }
+ }
+}
+
+static void mipi_dbi_set_window_address(struct mipi_dbi_dev *dbidev,
+ unsigned int xs, unsigned int xe,
+ unsigned int ys, unsigned int ye)
+{
+ struct mipi_dbi *dbi = &dbidev->dbi;
+
+ xs += dbidev->mode.left_margin;
+ xe += dbidev->mode.left_margin;
+ ys += dbidev->mode.upper_margin;
+ ye += dbidev->mode.upper_margin;
+
+ mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, (xs >> 8) & 0xff,
+ xs & 0xff, (xe >> 8) & 0xff, xe & 0xff);
+ mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, (ys >> 8) & 0xff,
+ ys & 0xff, (ye >> 8) & 0xff, ye & 0xff);
+}
+
+static void mipi_dbi_fb_dirty(struct mipi_dbi_dev *dbidev, struct fb_info *info,
+ struct fb_rect *rect)
+{
+ unsigned int height = rect->y2 - rect->y1;
+ unsigned int width = rect->x2 - rect->x1;
+ struct mipi_dbi *dbi = &dbidev->dbi;
+ bool swap = dbi->swap_bytes;
+ int ret;
+ bool full;
+ void *tr;
+
+ full = width == info->xres && height == info->yres;
+
+ if (!full || swap) {
+ tr = dbidev->tx_buf;
+ mipi_dbi_buf_copy(tr, info, rect, swap);
+ } else {
+ tr = info->screen_base;
+ }
+
+ mipi_dbi_set_window_address(dbidev, rect->x1, rect->x2 - 1, rect->y1,
+ rect->y2 - 1);
+
+ ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr,
+ width * height * 2);
+ if (ret)
+ pr_err_once("Failed to update display %d\n", ret);
+
+ dbidev->damage.x1 = 0;
+ dbidev->damage.y1 = 0;
+ dbidev->damage.x2 = 0;
+ dbidev->damage.y2 = 0;
+}
+
+/**
+ * mipi_dbi_enable_flush - MIPI DBI enable helper
+ * @dbidev: MIPI DBI device structure
+ * @info: Framebuffer info
+ *
+ * Flushes the whole framebuffer and enables the backlight. Drivers can use this
+ * in their &fb_ops->fb_enable callback.
+ */
+void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev,
+ struct fb_info *info)
+{
+ struct fb_rect rect = {
+ .x1 = 0,
+ .y1 = 0,
+ .x2 = info->xres,
+ .y2 = info->yres
+ };
+
+ mipi_dbi_fb_dirty(dbidev, info, &rect);
+
+ if (dbidev->backlight)
+ backlight_set_brightness_default(dbidev->backlight);
+}
+EXPORT_SYMBOL(mipi_dbi_enable_flush);
+
+static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev)
+{
+ u16 height = dbidev->mode.xres;
+ u16 width = dbidev->mode.yres;
+ struct mipi_dbi *dbi = &dbidev->dbi;
+ size_t len = width * height * 2;
+
+ memset(dbidev->tx_buf, 0, len);
+
+ mipi_dbi_set_window_address(dbidev, 0, width - 1, 0, height - 1);
+ mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, dbidev->tx_buf, len);
+}
+
+/**
+ * mipi_dbi_fb_disable - MIPI DBI framebuffer disable helper
+ * @info: Framebuffer info
+ *
+ * This function disables backlight if present, if not the display memory is
+ * blanked. The regulator is disabled if in use. Drivers can use this as their
+ * &fb_ops->fb_disable callback.
+ */
+void mipi_dbi_fb_disable(struct fb_info *info)
+{
+ struct mipi_dbi_dev *dbidev = container_of(info, struct mipi_dbi_dev, info);
+
+ if (dbidev->backlight)
+ backlight_set_brightness(dbidev->backlight, 0);
+ else
+ mipi_dbi_blank(dbidev);
+
+ regulator_disable(dbidev->regulator);
+ regulator_disable(dbidev->io_regulator);
+}
+EXPORT_SYMBOL(mipi_dbi_fb_disable);
+
+void mipi_dbi_fb_damage(struct fb_info *info, const struct fb_rect *rect)
+{
+ struct mipi_dbi_dev *dbidev = container_of(info, struct mipi_dbi_dev, info);
+
+ if (dbidev->damage.x2 && dbidev->damage.y2) {
+ dbidev->damage.x1 = min(dbidev->damage.x1, rect->x1);
+ dbidev->damage.y1 = min(dbidev->damage.y1, rect->y1);
+ dbidev->damage.x2 = max(dbidev->damage.x2, rect->x2);
+ dbidev->damage.y2 = max(dbidev->damage.y2, rect->y2);
+ } else {
+ dbidev->damage = *rect;
+ }
+}
+EXPORT_SYMBOL(mipi_dbi_fb_damage);
+
+void mipi_dbi_fb_flush(struct fb_info *info)
+{
+ struct mipi_dbi_dev *dbidev = container_of(info, struct mipi_dbi_dev, info);
+
+ if (!dbidev->damage.x2 || !dbidev->damage.y2) {
+ dbidev->damage.x1 = 0;
+ dbidev->damage.y1 = 0;
+ dbidev->damage.x2 = info->xres;
+ dbidev->damage.y2 = info->yres;
+ }
+
+ mipi_dbi_fb_dirty(dbidev, info, &dbidev->damage);
+}
+EXPORT_SYMBOL(mipi_dbi_fb_flush);
+
+/**
+ * mipi_dbi_dev_init - MIPI DBI device initialization
+ * @dbidev: MIPI DBI device structure to initialize
+ * @ops: Framebuffer operations
+ * @mode: Display mode
+ *
+ * This function sets up a &fb_info with one fixed &fb_videomode.
+ * Additionally &mipi_dbi.tx_buf is allocated.
+ *
+ * Supported format: RGB565.
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev, struct fb_ops *ops,
+ struct fb_videomode *mode)
+{
+ struct fb_info *info = &dbidev->info;
+
+ info->mode = mode;
+ info->fbops = ops;
+ info->dev.parent = dbidev->dev;
+
+ info->xres = mode->xres;
+ info->yres = mode->yres;
+ info->bits_per_pixel = 16;
+ info->line_length = info->xres * 2;
+ info->screen_size = info->line_length * info->yres;
+ info->screen_base = dma_alloc(info->screen_size);
+ memset(info->screen_base, 0, info->screen_size);
+
+ info->red.length = 5;
+ info->red.offset = 11;
+ info->green.length = 6;
+ info->green.offset = 5;
+ info->blue.length = 5;
+ info->blue.offset = 0;
+
+ dbidev->tx_buf = dma_alloc(info->screen_size);
+
+ return 0;
+}
+
+/**
+ * mipi_dbi_hw_reset - Hardware reset of controller
+ * @dbi: MIPI DBI structure
+ *
+ * Reset controller if the &mipi_dbi->reset gpio is set.
+ */
+void mipi_dbi_hw_reset(struct mipi_dbi *dbi)
+{
+ if (!dbi->reset)
+ return;
+
+ gpiod_set_value(dbi->reset, 0);
+ udelay(20);
+ gpiod_set_value(dbi->reset, 1);
+ mdelay(120);
+}
+EXPORT_SYMBOL(mipi_dbi_hw_reset);
+
+/**
+ * mipi_dbi_display_is_on - Check if display is on
+ * @dbi: MIPI DBI structure
+ *
+ * This function checks the Power Mode register (if readable) to see if
+ * display output is turned on. This can be used to see if the bootloader
+ * has already turned on the display avoiding flicker when the pipeline is
+ * enabled.
+ *
+ * Returns:
+ * true if the display can be verified to be on, false otherwise.
+ */
+bool mipi_dbi_display_is_on(struct mipi_dbi *dbi)
+{
+ u8 val;
+
+ if (mipi_dbi_command_read(dbi, MIPI_DCS_GET_POWER_MODE, &val))
+ return false;
+
+ val &= ~DCS_POWER_MODE_RESERVED_MASK;
+
+ /* The poweron/reset value is 08h DCS_POWER_MODE_DISPLAY_NORMAL_MODE */
+ if (val != (DCS_POWER_MODE_DISPLAY |
+ DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE))
+ return false;
+
+ pr_debug("Display is ON\n");
+
+ return true;
+}
+EXPORT_SYMBOL(mipi_dbi_display_is_on);
+
+static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi_dev *dbidev, bool cond)
+{
+ struct device *dev = dbidev->dev;
+ struct mipi_dbi *dbi = &dbidev->dbi;
+ int ret;
+
+ ret = regulator_enable(dbidev->regulator);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator (%d)\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(dbidev->io_regulator);
+ if (ret) {
+ dev_err(dev, "Failed to enable I/O regulator (%d)\n", ret);
+ regulator_disable(dbidev->regulator);
+ return ret;
+ }
+
+ if (cond && mipi_dbi_display_is_on(dbi))
+ return 1;
+
+ mipi_dbi_hw_reset(dbi);
+ ret = mipi_dbi_command(dbi, MIPI_DCS_SOFT_RESET);
+ if (ret) {
+ dev_err(dev, "Failed to send reset command (%d)\n", ret);
+ regulator_disable(dbidev->io_regulator);
+ regulator_disable(dbidev->regulator);
+ return ret;
+ }
+
+ /*
+ * If we did a hw reset, we know the controller is in Sleep mode and
+ * per MIPI DSC spec should wait 5ms after soft reset. If we didn't,
+ * we assume worst case and wait 120ms.
+ */
+ if (dbi->reset)
+ mdelay(5);
+ else
+ mdelay(120);
+
+ return 0;
+}
+
+/**
+ * mipi_dbi_poweron_conditional_reset - MIPI DBI poweron and conditional reset
+ * @dbidev: MIPI DBI device structure
+ *
+ * This function enables the regulator if used and if the display is off, it
+ * does a hardware and software reset. If mipi_dbi_display_is_on() determines
+ * that the display is on, no reset is performed.
+ *
+ * Returns:
+ * Zero if the controller was reset, 1 if the display was already on, or a
+ * negative error code.
+ */
+int mipi_dbi_poweron_conditional_reset(struct mipi_dbi_dev *dbidev)
+{
+ return mipi_dbi_poweron_reset_conditional(dbidev, true);
+}
+EXPORT_SYMBOL(mipi_dbi_poweron_conditional_reset);
+
+#if IS_ENABLED(CONFIG_SPI)
+
+/**
+ * mipi_dbi_spi_cmd_max_speed - get the maximum SPI bus speed
+ * @spi: SPI device
+ * @len: The transfer buffer length.
+ *
+ * Many controllers have a max speed of 10MHz, but can be pushed way beyond
+ * that. Increase reliability by running pixel data at max speed and the rest
+ * at 10MHz, preventing transfer glitches from messing up the init settings.
+ */
+u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len)
+{
+ if (len > 64)
+ return 0; /* use default */
+
+ return min_t(u32, 10000000, spi->max_speed_hz);
+}
+EXPORT_SYMBOL(mipi_dbi_spi_cmd_max_speed);
+
+static bool mipi_dbi_machine_little_endian(void)
+{
+#if defined(__LITTLE_ENDIAN)
+ return true;
+#else
+ return false;
+#endif
+}
+
+/* MIPI DBI Type C Option 3 */
+
+static int mipi_dbi_typec3_command_read(struct mipi_dbi *dbi, u8 *cmd,
+ u8 *data, size_t len)
+{
+ struct spi_device *spi = dbi->spi;
+ u32 speed_hz = min_t(u32, MIPI_DBI_MAX_SPI_READ_SPEED,
+ spi->max_speed_hz / 2);
+ struct spi_transfer tr[2] = {
+ {
+ .speed_hz = speed_hz,
+ .tx_buf = cmd,
+ .len = 1,
+ }, {
+ .speed_hz = speed_hz,
+ .len = len,
+ },
+ };
+ struct spi_message m;
+ u8 *buf;
+ int ret;
+
+ if (!len)
+ return -EINVAL;
+
+ /*
+ * Support non-standard 24-bit and 32-bit Nokia read commands which
+ * start with a dummy clock, so we need to read an extra byte.
+ */
+ if (*cmd == MIPI_DCS_GET_DISPLAY_ID ||
+ *cmd == MIPI_DCS_GET_DISPLAY_STATUS) {
+ if (!(len == 3 || len == 4))
+ return -EINVAL;
+
+ tr[1].len = len + 1;
+ }
+
+ buf = kmalloc(tr[1].len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tr[1].rx_buf = buf;
+ gpiod_set_value(dbi->dc, 0);
+
+ spi_message_init_with_transfers(&m, tr, ARRAY_SIZE(tr));
+ ret = spi_sync(spi, &m);
+ if (ret)
+ goto err_free;
+
+ if (tr[1].len == len) {
+ memcpy(data, buf, len);
+ } else {
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ data[i] = (buf[i] << 1) | (buf[i + 1] >> 7);
+ }
+
+ MIPI_DBI_DEBUG_COMMAND(*cmd, data, len);
+
+err_free:
+ kfree(buf);
+
+ return ret;
+}
+
+static int mipi_dbi_typec3_command(struct mipi_dbi *dbi, u8 *cmd,
+ u8 *par, size_t num)
+{
+ struct spi_device *spi = dbi->spi;
+ unsigned int bpw = 8;
+ u32 speed_hz;
+ int ret;
+
+ if (mipi_dbi_command_is_read(dbi, *cmd))
+ return mipi_dbi_typec3_command_read(dbi, cmd, par, num);
+
+ MIPI_DBI_DEBUG_COMMAND(*cmd, par, num);
+
+ gpiod_set_value(dbi->dc, 0);
+ speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1);
+ ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, cmd, 1);
+ if (ret || !num)
+ return ret;
+
+ if (*cmd == MIPI_DCS_WRITE_MEMORY_START && !dbi->swap_bytes)
+ bpw = 16;
+
+ gpiod_set_value(dbi->dc, 1);
+ speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
+
+ return mipi_dbi_spi_transfer(spi, speed_hz, bpw, par, num);
+}
+
+/**
+ * mipi_dbi_spi_init - Initialize MIPI DBI SPI interface
+ * @spi: SPI device
+ * @dbi: MIPI DBI structure to initialize
+ * @dc: D/C gpio
+ *
+ * This function sets &mipi_dbi->command, enables &mipi_dbi->read_commands for the
+ * usual read commands. It should be followed by a call to mipi_dbi_dev_init() or
+ * a driver-specific init.
+ *
+ * Type C Option 3 interface is assumed, Type C Option 1 is not yet supported,
+ * because barebox has no generic way yet to require a 9-bit SPI transfer
+ *
+ * If the SPI master driver doesn't support the necessary bits per word,
+ * the following transformation is used:
+ *
+ * - 9-bit: reorder buffer as 9x 8-bit words, padded with no-op command.
+ * - 16-bit: if big endian send as 8-bit, if little endian swap bytes
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi,
+ struct gpio_desc *dc)
+{
+ struct device *dev = &spi->dev;
+
+ dbi->spi = spi;
+ dbi->read_commands = mipi_dbi_dcs_read_commands;
+
+ if (!dc) {
+ dev_dbg(dev, "MIPI DBI Type-C 1 unsupported\n");
+ return -ENOSYS;
+ }
+
+ dbi->command = mipi_dbi_typec3_command;
+ dbi->dc = dc;
+ if (mipi_dbi_machine_little_endian() && !spi_is_bpw_supported(spi, 16))
+ dbi->swap_bytes = true;
+
+ dev_dbg(dev, "SPI speed: %uMHz\n", spi->max_speed_hz / 1000000);
+
+ list_add(&dbi->list, &mipi_dbi_list);
+ return 0;
+}
+EXPORT_SYMBOL(mipi_dbi_spi_init);
+
+/**
+ * mipi_dbi_spi_transfer - SPI transfer helper
+ * @spi: SPI device
+ * @speed_hz: Override speed (optional)
+ * @bpw: Bits per word
+ * @buf: Buffer to transfer
+ * @len: Buffer length
+ *
+ * This SPI transfer helper breaks up the transfer of @buf into chunks which
+ * the SPI controller driver can handle.
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_spi_transfer(struct spi_device *spi, u32 speed_hz,
+ u8 bpw, const void *buf, size_t len)
+{
+ size_t max_chunk = spi_max_transfer_size(spi);
+ struct spi_transfer tr = {
+ .bits_per_word = bpw,
+ .speed_hz = speed_hz,
+ };
+ struct spi_message m;
+ size_t chunk;
+ int ret;
+
+ spi_message_init_with_transfers(&m, &tr, 1);
+
+ while (len) {
+ chunk = min(len, max_chunk);
+
+ tr.tx_buf = buf;
+ tr.len = chunk;
+ buf += chunk;
+ len -= chunk;
+
+ ret = spi_sync(spi, &m);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mipi_dbi_spi_transfer);
+
+#endif /* CONFIG_SPI */
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mtl017.c b/drivers/video/mtl017.c
index c04875cd07..ba214b47ae 100644
--- a/drivers/video/mtl017.c
+++ b/drivers/video/mtl017.c
@@ -1,19 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright 2014 Sascha Hauer, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <driver.h>
@@ -29,7 +16,7 @@
struct mtl017 {
struct vpl vpl;
- struct device_d *dev;
+ struct device *dev;
struct i2c_client *client;
u8 *regs;
int enable_gpio;
@@ -231,14 +218,14 @@ forward:
return vpl_ioctl(&mtl017->vpl, 1, cmd, ptr);
}
-static int mtl017_probe(struct device_d *dev)
+static int mtl017_probe(struct device *dev)
{
struct mtl017 *mtl017;
int ret;
enum of_gpio_flags flags;
mtl017 = xzalloc(sizeof(struct mtl017));
- mtl017->vpl.node = dev->device_node;
+ mtl017->vpl.node = dev->of_node;
mtl017->vpl.ioctl = mtl017_ioctl;
mtl017->dev = dev;
mtl017->client = to_i2c_client(dev);
@@ -247,15 +234,16 @@ static int mtl017_probe(struct device_d *dev)
if (IS_ERR(mtl017->regulator))
mtl017->regulator = NULL;
- mtl017->enable_gpio = of_get_named_gpio_flags(dev->device_node,
- "enable-gpios", 0, &flags);
+ mtl017->enable_gpio = of_get_named_gpio_flags(dev->of_node,
+ "enable-gpios", 0,
+ &flags);
if (gpio_is_valid(mtl017->enable_gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
mtl017->enable_active_high = 1;
}
- mtl017->reset_gpio = of_get_named_gpio_flags(dev->device_node,
- "reset-gpios", 0, &flags);
+ mtl017->reset_gpio = of_get_named_gpio_flags(dev->of_node,
+ "reset-gpios", 0, &flags);
if (gpio_is_valid(mtl017->reset_gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
mtl017->reset_active_high = 1;
@@ -268,7 +256,7 @@ static int mtl017_probe(struct device_d *dev)
return 0;
}
-static struct driver_d mtl_driver = {
+static struct driver mtl_driver = {
.name = "mtl017",
.probe = mtl017_probe,
};
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c
index 17d8823c46..74b01239cb 100644
--- a/drivers/video/of_display_timing.c
+++ b/drivers/video/of_display_timing.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OF helpers for parsing display timings
*
* Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
*
* based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This file is released under the GPLv2
*/
#include <common.h>
#include <of.h>
@@ -38,8 +37,8 @@ static int parse_timing_property(const struct device_node *np, const char *name,
prop = of_find_property(np, name, &length);
if (!prop) {
- pr_err("%s: could not find property %s\n",
- np->full_name, name);
+ pr_err("%pOF: could not find property %s\n",
+ np, name);
return -EINVAL;
}
@@ -47,8 +46,8 @@ static int parse_timing_property(const struct device_node *np, const char *name,
if ((cells == 1) || (cells == 3)) {
ret = of_property_read_u32(np, name, res);
} else {
- pr_err("%s: illegal timing specification in %s\n",
- np->full_name, name);
+ pr_err("%pOF: illegal timing specification in %s\n",
+ np, name);
return -EINVAL;
}
@@ -91,8 +90,7 @@ static int of_parse_display_timing(const struct device_node *np,
DISPLAY_FLAGS_PIXDATA_NEGEDGE;
if (ret) {
- pr_err("%s: error reading timing properties\n",
- np->full_name);
+ pr_err("%pOF: error reading timing properties\n", np);
return -EINVAL;
}
@@ -100,6 +98,28 @@ static int of_parse_display_timing(const struct device_node *np,
}
/**
+ * of_get_display_timing - parse a display_timing entry
+ * @np: device_node with the timing subnode
+ * @name: name of the timing node
+ * @mode: fb_videomode struct to fill
+ **/
+int of_get_display_timing(const struct device_node *np, const char *name,
+ struct fb_videomode *mode)
+{
+ struct device_node *timing_np;
+
+ if (!np)
+ return -EINVAL;
+
+ timing_np = of_get_child_by_name(np, name);
+ if (!timing_np)
+ return -ENOENT;
+
+ return of_parse_display_timing(timing_np, mode);
+}
+EXPORT_SYMBOL_GPL(of_get_display_timing);
+
+/**
* of_get_display_timings - parse all display_timing entries from a device_node
* @np: device_node with the subnodes
**/
@@ -115,8 +135,7 @@ struct display_timings *of_get_display_timings(struct device_node *np)
timings_np = of_get_child_by_name(np, "display-timings");
if (!timings_np) {
- pr_debug("%s: could not find display-timings node\n",
- np->full_name);
+ pr_debug("%pOF: could not find display-timings node\n", np);
return NULL;
}
@@ -128,20 +147,19 @@ struct display_timings *of_get_display_timings(struct device_node *np)
entry = of_get_next_available_child(np, NULL);
/* if there is no child, it is useless to go on */
if (!entry) {
- pr_err("%s: no timing specifications given\n",
- np->full_name);
+ pr_err("%pOF: no timing specifications given\n", np);
goto fail;
}
- pr_debug("%s: using %s as default timing\n",
- np->full_name, entry->name);
+ pr_debug("%pOF: using %s as default timing\n",
+ np, entry->name);
native_mode = entry;
disp->num_modes = of_get_child_count(timings_np);
if (disp->num_modes == 0) {
/* should never happen, as entry was already found above */
- pr_err("%s: no timings specified\n", np->full_name);
+ pr_err("%pOF: no timings specified\n", np);
goto fail;
}
@@ -162,8 +180,8 @@ struct display_timings *of_get_display_timings(struct device_node *np)
* to not encourage wrong devicetrees, fail in case of
* an error
*/
- pr_err("%s: error in timing %d\n",
- np->full_name, disp->num_modes + 1);
+ pr_err("%pOF: error in timing %d\n",
+ np, disp->num_modes + 1);
goto fail;
}
@@ -175,8 +193,8 @@ struct display_timings *of_get_display_timings(struct device_node *np)
disp->num_modes++;
}
- pr_debug("%s: got %d timings. Using timing #%d as default\n",
- np->full_name, disp->num_modes,
+ pr_debug("%pOF: got %d timings. Using timing #%d as default\n",
+ np, disp->num_modes,
disp->native_mode + 1);
return disp;
diff --git a/drivers/video/omap.c b/drivers/video/omap.c
index 884365f609..3b1ec89c38 100644
--- a/drivers/video/omap.c
+++ b/drivers/video/omap.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* TI Omap Frame Buffer device driver
*
* Copyright (C) 2013 Christoph Fritz <chf.fritz@googlemail.com>
* Based on work by Enrico Scholz, sponsored by Phytec
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <driver.h>
@@ -28,12 +16,10 @@
#include <io.h>
#include <common.h>
#include <malloc.h>
-#include <common.h>
#include <clock.h>
#include <linux/err.h>
-#include <mach/omap4-silicon.h>
-#include <mach/omap-fb.h>
+#include <video/omap-fb.h>
#include <mmu.h>
@@ -41,7 +27,7 @@
struct omapfb_device {
struct fb_info info;
- struct device_d *dev;
+ struct device *dev;
struct omapfb_display const *cur_display;
@@ -424,7 +410,7 @@ static struct fb_ops omapfb_ops = {
.fb_activate_var = omapfb_activate_var,
};
-static int omapfb_probe(struct device_d *dev)
+static int omapfb_probe(struct device *dev)
{
struct omapfb_platform_data const *pdata = dev->platform_data;
struct omapfb_device *fbi;
@@ -496,6 +482,7 @@ static int omapfb_probe(struct device_d *dev)
goto out;
}
+ info->dev.parent = dev;
rc = register_framebuffer(info);
if (rc < 0) {
dev_err(dev, "failed to register framebuffer: %d\n", rc);
@@ -512,14 +499,9 @@ out:
return rc;
}
-static struct driver_d omapfb_driver = {
+static struct driver omapfb_driver = {
.name = "omap_fb",
.probe = omapfb_probe,
};
-static int omapfb_init(void)
-{
- return platform_driver_register(&omapfb_driver);
-}
-
-device_initcall(omapfb_init);
+device_platform_driver(omapfb_driver);
diff --git a/drivers/video/omap.h b/drivers/video/omap.h
index ac9e1cee87..991d7a0f91 100644
--- a/drivers/video/omap.h
+++ b/drivers/video/omap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* TI Omap4 Frame Buffer device driver
*
* Copyright (C) 2013 Christoph Fritz <chf.fritz@googlemail.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef H_BAREBOX_DRIVER_VIDEO_OMAP4_REGS_H
diff --git a/drivers/video/panel-ilitek-ili9341.c b/drivers/video/panel-ilitek-ili9341.c
new file mode 100644
index 0000000000..4d03a8513e
--- /dev/null
+++ b/drivers/video/panel-ilitek-ili9341.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ilitek ILI9341 TFT LCD driver.
+ *
+ * This panel can be configured to support:
+ * - 16-bit parallel RGB interface
+ * - 18-bit parallel RGB interface
+ * - 4-line serial spi interface
+ *
+ * Copyright 2018 David Lechner <david@lechnology.com>
+ * Copyright (C) 2021 Dillon Min <dillon.minfei@gmail.com>
+ *
+ * Derived from Linux drivers/drm/gpu/panel/panel-ilitek-ili9341.c
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <linux/gpio/consumer.h>
+#include <of.h>
+#include <regulator.h>
+#include <spi/spi.h>
+#include <video/vpl.h>
+#include <video/mipi_dbi.h>
+
+#include <video/mipi_display.h>
+
+#define ILI9341_RGB_INTERFACE 0xb0 /* RGB Interface Signal Control */
+#define ILI9341_FRC 0xb1 /* Frame Rate Control register */
+#define ILI9341_DFC 0xb6 /* Display Function Control register */
+#define ILI9341_POWER1 0xc0 /* Power Control 1 register */
+#define ILI9341_POWER2 0xc1 /* Power Control 2 register */
+#define ILI9341_VCOM1 0xc5 /* VCOM Control 1 register */
+#define ILI9341_VCOM2 0xc7 /* VCOM Control 2 register */
+#define ILI9341_POWERA 0xcb /* Power control A register */
+#define ILI9341_POWERB 0xcf /* Power control B register */
+#define ILI9341_PGAMMA 0xe0 /* Positive Gamma Correction register */
+#define ILI9341_NGAMMA 0xe1 /* Negative Gamma Correction register */
+#define ILI9341_DTCA 0xe8 /* Driver timing control A */
+#define ILI9341_DTCB 0xea /* Driver timing control B */
+#define ILI9341_POWER_SEQ 0xed /* Power on sequence register */
+#define ILI9341_3GAMMA_EN 0xf2 /* 3 Gamma enable register */
+#define ILI9341_INTERFACE 0xf6 /* Interface control register */
+#define ILI9341_PRC 0xf7 /* Pump ratio control register */
+#define ILI9341_ETMOD 0xb7 /* Entry mode set */
+
+#define ILI9341_MADCTL_BGR BIT(3)
+#define ILI9341_MADCTL_MV BIT(5)
+#define ILI9341_MADCTL_MX BIT(6)
+#define ILI9341_MADCTL_MY BIT(7)
+
+#define ILI9341_POWER_B_LEN 3
+#define ILI9341_POWER_SEQ_LEN 4
+#define ILI9341_DTCA_LEN 3
+#define ILI9341_DTCB_LEN 2
+#define ILI9341_POWER_A_LEN 5
+#define ILI9341_DFC_1_LEN 2
+#define ILI9341_FRC_LEN 2
+#define ILI9341_VCOM_1_LEN 2
+#define ILI9341_DFC_2_LEN 4
+#define ILI9341_COLUMN_ADDR_LEN 4
+#define ILI9341_PAGE_ADDR_LEN 4
+#define ILI9341_INTERFACE_LEN 3
+#define ILI9341_PGAMMA_LEN 15
+#define ILI9341_NGAMMA_LEN 15
+#define ILI9341_CA_LEN 3
+
+#define ILI9341_PIXEL_DPI_16_BITS (BIT(6) | BIT(4))
+#define ILI9341_PIXEL_DPI_18_BITS (BIT(6) | BIT(5))
+#define ILI9341_GAMMA_CURVE_1 BIT(0)
+#define ILI9341_IF_WE_MODE BIT(0)
+#define ILI9341_IF_BIG_ENDIAN 0x00
+#define ILI9341_IF_DM_RGB BIT(2)
+#define ILI9341_IF_DM_INTERNAL 0x00
+#define ILI9341_IF_DM_VSYNC BIT(3)
+#define ILI9341_IF_RM_RGB BIT(1)
+#define ILI9341_IF_RIM_RGB 0x00
+
+#define ILI9341_COLUMN_ADDR 0x00ef
+#define ILI9341_PAGE_ADDR 0x013f
+
+#define ILI9341_RGB_EPL BIT(0)
+#define ILI9341_RGB_DPL BIT(1)
+#define ILI9341_RGB_HSPL BIT(2)
+#define ILI9341_RGB_VSPL BIT(3)
+#define ILI9341_RGB_DE_MODE BIT(6)
+#define ILI9341_RGB_DISP_PATH_MEM BIT(7)
+
+#define ILI9341_DBI_VCOMH_4P6V 0x23
+#define ILI9341_DBI_PWR_2_DEFAULT 0x10
+#define ILI9341_DBI_PRC_NORMAL 0x20
+#define ILI9341_DBI_VCOM_1_VMH_4P25V 0x3e
+#define ILI9341_DBI_VCOM_1_VML_1P5V 0x28
+#define ILI9341_DBI_VCOM_2_DEC_58 0x86
+#define ILI9341_DBI_FRC_DIVA 0x00
+#define ILI9341_DBI_FRC_RTNA 0x1b
+#define ILI9341_DBI_EMS_GAS BIT(0)
+#define ILI9341_DBI_EMS_DTS BIT(1)
+#define ILI9341_DBI_EMS_GON BIT(2)
+
+/* struct ili9341_config - the system specific ILI9341 configuration */
+struct ili9341_config {
+ u32 max_spi_speed;
+ /* mode: the display mode */
+ const struct fb_videomode mode;
+ /* ca: TODO: need comments for this register */
+ u8 ca[ILI9341_CA_LEN];
+ /* power_b: TODO: need comments for this register */
+ u8 power_b[ILI9341_POWER_B_LEN];
+ /* power_seq: TODO: need comments for this register */
+ u8 power_seq[ILI9341_POWER_SEQ_LEN];
+ /* dtca: TODO: need comments for this register */
+ u8 dtca[ILI9341_DTCA_LEN];
+ /* dtcb: TODO: need comments for this register */
+ u8 dtcb[ILI9341_DTCB_LEN];
+ /* power_a: TODO: need comments for this register */
+ u8 power_a[ILI9341_POWER_A_LEN];
+ /* frc: Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
+ u8 frc[ILI9341_FRC_LEN];
+ /* prc: TODO: need comments for this register */
+ u8 prc;
+ /* dfc_1: B6h DISCTRL (Display Function Control) */
+ u8 dfc_1[ILI9341_DFC_1_LEN];
+ /* power_1: Power Control 1 (C0h) */
+ u8 power_1;
+ /* power_2: Power Control 2 (C1h) */
+ u8 power_2;
+ /* vcom_1: VCOM Control 1(C5h) */
+ u8 vcom_1[ILI9341_VCOM_1_LEN];
+ /* vcom_2: VCOM Control 2(C7h) */
+ u8 vcom_2;
+ /* address_mode: Memory Access Control (36h) */
+ u8 address_mode;
+ /* g3amma_en: TODO: need comments for this register */
+ u8 g3amma_en;
+ /* rgb_interface: RGB Interface Signal Control (B0h) */
+ u8 rgb_interface;
+ /* dfc_2: refer to dfc_1 */
+ u8 dfc_2[ILI9341_DFC_2_LEN];
+ /* column_addr: Column Address Set (2Ah) */
+ u8 column_addr[ILI9341_COLUMN_ADDR_LEN];
+ /* page_addr: Page Address Set (2Bh) */
+ u8 page_addr[ILI9341_PAGE_ADDR_LEN];
+ /* interface: Interface Control (F6h) */
+ u8 interface[ILI9341_INTERFACE_LEN];
+ /*
+ * pixel_format: This command sets the pixel format for the RGB
+ * image data used by
+ */
+ u8 pixel_format;
+ /*
+ * gamma_curve: This command is used to select the desired Gamma
+ * curve for the
+ */
+ u8 gamma_curve;
+ /* pgamma: Positive Gamma Correction (E0h) */
+ u8 pgamma[ILI9341_PGAMMA_LEN];
+ /* ngamma: Negative Gamma Correction (E1h) */
+ u8 ngamma[ILI9341_NGAMMA_LEN];
+};
+
+struct ili9341 {
+ struct device *dev;
+ struct vpl vpl;
+ const struct ili9341_config *conf;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *dc_gpio;
+ struct mipi_dbi *dbi;
+ u32 max_spi_speed;
+ struct regulator_bulk_data supplies[3];
+};
+
+/*
+ * The Stm32f429-disco board has a panel ili9341 connected to ltdc controller
+ */
+static const struct ili9341_config ili9341_stm32f429_disco_data = {
+ .max_spi_speed = 10000000,
+ .mode = {
+ .name = "240x320",
+ .xres = 240,
+ .yres = 320,
+ .pixclock = KHZ2PICOS(6100),
+ .left_margin = 10,
+ .hsync_len = 10,
+ .right_margin = 20,
+ .upper_margin = 4,
+ .lower_margin = 2,
+ .vsync_len = 2,
+ },
+ .ca = {0xc3, 0x08, 0x50},
+ .power_b = {0x00, 0xc1, 0x30},
+ .power_seq = {0x64, 0x03, 0x12, 0x81},
+ .dtca = {0x85, 0x00, 0x78},
+ .power_a = {0x39, 0x2c, 0x00, 0x34, 0x02},
+ .prc = 0x20,
+ .dtcb = {0x00, 0x00},
+ /* 0x00 fosc, 0x1b 70hz */
+ .frc = {0x00, 0x1b},
+ /*
+ * 0x0a Interval scan, AGND AGND AGND AGND
+ * 0xa2 Normally white, G1 -> G320, S720 -> S1,
+ * Scan Cycle 5 frames,85ms
+ */
+ .dfc_1 = {0x0a, 0xa2},
+ /* 0x10 3.65v */
+ .power_1 = 0x10,
+ /* 0x10 AVDD=vci*2, VGH=vci*7, VGL=-vci*4 */
+ .power_2 = 0x10,
+ /* 0x45 VCOMH 4.425v, 0x15 VCOML -1.975*/
+ .vcom_1 = {0x45, 0x15},
+ /* 0x90 offset voltage, VMH-48, VML-48 */
+ .vcom_2 = 0x90,
+ /*
+ * 0xc8 Row Address Order, Column Address Order
+ * BGR 1
+ */
+ .address_mode = 0xc8,
+ .g3amma_en = 0x00,
+ /*
+ * 0xc2
+ * Display Data Path: Memory
+ * RGB: DE mode
+ * DOTCLK polarity set (data fetched at the falling time)
+ */
+ .rgb_interface = ILI9341_RGB_DISP_PATH_MEM |
+ ILI9341_RGB_DE_MODE |
+ ILI9341_RGB_DPL,
+ /*
+ * 0x0a
+ * Gate outputs in non-display area: Interval scan
+ * Determine source/VCOM output in a non-display area in the partial
+ * display mode: AGND AGND AGND AGND
+ *
+ * 0xa7
+ * Scan Cycle: 15 frames
+ * fFLM = 60Hz: 255ms
+ * Liquid crystal type: Normally white
+ * Gate Output Scan Direction: G1 -> G320
+ * Source Output Scan Direction: S720 -> S1
+ *
+ * 0x27
+ * LCD Driver Line: 320 lines
+ *
+ * 0x04
+ * PCDIV: 4
+ */
+ .dfc_2 = {0x0a, 0xa7, 0x27, 0x04},
+ /* column address: 240 */
+ .column_addr = {0x00, 0x00, (ILI9341_COLUMN_ADDR >> 4) & 0xff,
+ ILI9341_COLUMN_ADDR & 0xff},
+ /* page address: 320 */
+ .page_addr = {0x00, 0x00, (ILI9341_PAGE_ADDR >> 4) & 0xff,
+ ILI9341_PAGE_ADDR & 0xff},
+ /*
+ * Memory write control: When the transfer number of data exceeds
+ * (EC-SC+1)*(EP-SP+1), the column and page number will be
+ * reset, and the exceeding data will be written into the following
+ * column and page.
+ * Display Operation Mode: RGB Interface Mode
+ * Interface for RAM Access: RGB interface
+ * 16- bit RGB interface (1 transfer/pixel)
+ */
+ .interface = {ILI9341_IF_WE_MODE, 0x00,
+ ILI9341_IF_DM_RGB | ILI9341_IF_RM_RGB},
+ /* DPI: 16 bits / pixel */
+ .pixel_format = ILI9341_PIXEL_DPI_16_BITS,
+ /* Curve Selected: Gamma curve 1 (G2.2) */
+ .gamma_curve = ILI9341_GAMMA_CURVE_1,
+ .pgamma = {0x0f, 0x29, 0x24, 0x0c, 0x0e,
+ 0x09, 0x4e, 0x78, 0x3c, 0x09,
+ 0x13, 0x05, 0x17, 0x11, 0x00},
+ .ngamma = {0x00, 0x16, 0x1b, 0x04, 0x11,
+ 0x07, 0x31, 0x33, 0x42, 0x05,
+ 0x0c, 0x0a, 0x28, 0x2f, 0x0f},
+};
+
+static inline struct ili9341 *vpl_to_ili9341(struct vpl *vpl)
+{
+ return container_of(vpl, struct ili9341, vpl);
+}
+
+static void ili9341_dpi_init(struct ili9341 *ili)
+{
+ struct device *dev = ili->dev;
+ struct mipi_dbi *dbi = ili->dbi;
+ struct ili9341_config *cfg = (struct ili9341_config *)ili->conf;
+
+ /* Power Control */
+ mipi_dbi_command_stackbuf(dbi, 0xca, cfg->ca, ILI9341_CA_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_POWERB, cfg->power_b,
+ ILI9341_POWER_B_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_POWER_SEQ, cfg->power_seq,
+ ILI9341_POWER_SEQ_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_DTCA, cfg->dtca,
+ ILI9341_DTCA_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_POWERA, cfg->power_a,
+ ILI9341_POWER_A_LEN);
+ mipi_dbi_command(ili->dbi, ILI9341_PRC, cfg->prc);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_DTCB, cfg->dtcb,
+ ILI9341_DTCB_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_FRC, cfg->frc, ILI9341_FRC_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_1,
+ ILI9341_DFC_1_LEN);
+ mipi_dbi_command(dbi, ILI9341_POWER1, cfg->power_1);
+ mipi_dbi_command(dbi, ILI9341_POWER2, cfg->power_2);
+
+ /* VCOM */
+ mipi_dbi_command_stackbuf(dbi, ILI9341_VCOM1, cfg->vcom_1,
+ ILI9341_VCOM_1_LEN);
+ mipi_dbi_command(dbi, ILI9341_VCOM2, cfg->vcom_2);
+ mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, cfg->address_mode);
+
+ /* Gamma */
+ mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, cfg->g3amma_en);
+ mipi_dbi_command(dbi, ILI9341_RGB_INTERFACE, cfg->rgb_interface);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_2,
+ ILI9341_DFC_2_LEN);
+
+ /* Colomn address set */
+ mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_COLUMN_ADDRESS,
+ cfg->column_addr, ILI9341_COLUMN_ADDR_LEN);
+
+ /* Page address set */
+ mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_PAGE_ADDRESS,
+ cfg->page_addr, ILI9341_PAGE_ADDR_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_INTERFACE, cfg->interface,
+ ILI9341_INTERFACE_LEN);
+
+ /* Format */
+ mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, cfg->pixel_format);
+ mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
+ mdelay(200);
+ mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, cfg->gamma_curve);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_PGAMMA, cfg->pgamma,
+ ILI9341_PGAMMA_LEN);
+ mipi_dbi_command_stackbuf(dbi, ILI9341_NGAMMA, cfg->ngamma,
+ ILI9341_NGAMMA_LEN);
+ mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
+ mdelay(200);
+ mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
+ mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
+
+ dev_info(dev, "Initialized display rgb interface\n");
+}
+
+static int ili9341_dpi_power_on(struct ili9341 *ili)
+{
+ struct device *dev = ili->dev;
+ int ret = 0;
+
+ /* Assert RESET */
+ gpiod_set_value(ili->reset_gpio, 1);
+
+ /* Enable power */
+ ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies),
+ ili->supplies);
+ if (ret < 0) {
+ dev_err(dev, "unable to enable vcc\n");
+ return ret;
+ }
+ mdelay(20);
+
+ /* De-assert RESET */
+ gpiod_set_value(ili->reset_gpio, 0);
+ mdelay(20);
+
+ return 0;
+}
+
+static int ili9341_dpi_power_off(struct ili9341 *ili)
+{
+ /* Assert RESET */
+ gpiod_set_value(ili->reset_gpio, 1);
+
+ /* Disable power */
+ return regulator_bulk_disable(ARRAY_SIZE(ili->supplies),
+ ili->supplies);
+}
+
+static void ili9341_dpi_disable(struct ili9341 *ili)
+{
+ mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_OFF);
+}
+
+static int ili9341_dpi_prepare(struct ili9341 *ili)
+{
+ int ret;
+
+ ret = ili9341_dpi_power_on(ili);
+ if (ret < 0)
+ return ret;
+
+ ili9341_dpi_init(ili);
+
+ return ret;
+}
+
+static void ili9341_dpi_enable(struct ili9341 *ili)
+{
+ mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_ON);
+}
+
+static int ili9341_dpi_get_modes(struct ili9341 *ili,
+ struct display_timings *timings)
+{
+ struct fb_videomode *mode;
+
+ mode = memdup(&ili->conf->mode, sizeof(*mode));
+ if (!mode)
+ return -ENOMEM;
+
+ /*
+ * These are from the PoV of the display controller, so
+ * DPL=1 => display samples at positive edge
+ * => controller drives at negative edge
+ */
+ if (ili->conf->rgb_interface & ILI9341_RGB_DPL)
+ mode->display_flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+ else
+ mode->display_flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+
+ if (ili->conf->rgb_interface & ILI9341_RGB_EPL)
+ mode->display_flags |= DISPLAY_FLAGS_DE_HIGH;
+ else
+ mode->display_flags |= DISPLAY_FLAGS_DE_LOW;
+
+ /* Set up the polarity */
+ if (ili->conf->rgb_interface & ILI9341_RGB_HSPL)
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ if (ili->conf->rgb_interface & ILI9341_RGB_VSPL)
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ timings->modes = mode;
+ timings->num_modes = 1;
+ return 0;
+}
+
+static int ili9341_ioctl(struct vpl *vpl, unsigned int port,
+ unsigned int cmd, void *ptr)
+{
+ struct ili9341 *ili = vpl_to_ili9341(vpl);
+
+ switch (cmd) {
+ case VPL_PREPARE:
+ return ili9341_dpi_prepare(ili);
+ case VPL_ENABLE:
+ ili9341_dpi_enable(ili);
+ return 0;
+ case VPL_DISABLE:
+ ili9341_dpi_disable(ili);
+ return 0;
+ case VPL_UNPREPARE:
+ return ili9341_dpi_power_off(ili);
+ case VPL_GET_VIDEOMODES:
+ return ili9341_dpi_get_modes(ili, ptr);
+ default:
+ return 0;
+ }
+}
+
+static int ili9341_dpi_probe(struct spi_device *spi,
+ struct gpio_desc *dc, struct gpio_desc *reset)
+{
+ struct device *dev = &spi->dev;
+ struct ili9341 *ili;
+ int ret;
+
+ ili = kzalloc(sizeof(struct ili9341), GFP_KERNEL);
+ if (!ili)
+ return -ENOMEM;
+
+ ili->dbi = kzalloc(sizeof(struct mipi_dbi), GFP_KERNEL);
+ if (!ili->dbi)
+ return -ENOMEM;
+
+ ili->supplies[0].supply = "vci";
+ ili->supplies[1].supply = "vddi";
+ ili->supplies[2].supply = "vddi-led";
+ ret = regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
+ ili->supplies);
+ if (ret < 0) {
+ dev_err(dev, "failed to get regulators: %d\n", ret);
+ return ret;
+ }
+
+ ret = mipi_dbi_spi_init(spi, ili->dbi, dc);
+ if (ret)
+ return ret;
+
+ ili->reset_gpio = reset;
+ /*
+ * Every new incarnation of this display must have a unique
+ * data entry for the system in this driver.
+ */
+ ili->conf = device_get_match_data(dev);
+ if (!ili->conf) {
+ dev_err(dev, "missing device configuration\n");
+ return -ENODEV;
+ }
+
+ ili->dev = dev;
+ ili->max_spi_speed = ili->conf->max_spi_speed;
+ ili->vpl.node = dev->of_node;
+ ili->vpl.ioctl = ili9341_ioctl;
+
+ return vpl_register(&ili->vpl);
+}
+
+static int ili9341_probe(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct gpio_desc *dc, *reset;
+
+ reset = gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset))
+ dev_err(dev, "Failed to get gpio 'reset'\n");
+
+ dc = gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+ if (IS_ERR(dc))
+ dev_err(dev, "Failed to get gpio 'dc'\n");
+
+ return ili9341_dpi_probe(spi, dc, reset);
+}
+
+static const struct of_device_id ili9341_of_match[] = {
+ {
+ .compatible = "st,sf-tc240t-9370-t",
+ .data = &ili9341_stm32f429_disco_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ili9341_of_match);
+
+static struct driver ili9341_driver = {
+ .name = "panel-ilitek-ili9341",
+ .of_compatible = ili9341_of_match,
+ .probe = ili9341_probe,
+};
+device_spi_driver(ili9341_driver);
+
+MODULE_AUTHOR("Dillon Min <dillon.minfei@gmail.com>");
+MODULE_DESCRIPTION("ILI9341 LCD panel driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/panel-mipi-dbi.c b/drivers/video/panel-mipi-dbi.c
new file mode 100644
index 0000000000..fecb232796
--- /dev/null
+++ b/drivers/video/panel-mipi-dbi.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DRM driver for MIPI DBI compatible display panels
+ *
+ * Copyright 2022 Noralf Trønnes
+ */
+
+#include <clock.h>
+#include <common.h>
+#include <fb.h>
+#include <firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/printk.h>
+#include <of.h>
+#include <regulator.h>
+#include <spi/spi.h>
+
+#include <video/backlight.h>
+#include <video/mipi_dbi.h>
+#include <video/mipi_display.h>
+
+static const u8 panel_mipi_dbi_magic[15] = { 'M', 'I', 'P', 'I', ' ', 'D', 'B', 'I',
+ 0, 0, 0, 0, 0, 0, 0 };
+
+/*
+ * The display controller configuration is stored in a firmware file.
+ * The Device Tree 'compatible' property value with a '.bin' suffix is passed
+ * to request_firmware() to fetch this file.
+ */
+struct panel_mipi_dbi_config {
+ /* Magic string: panel_mipi_dbi_magic */
+ u8 magic[15];
+
+ /* Config file format version */
+ u8 file_format_version;
+
+ /*
+ * MIPI commands to execute when the display pipeline is enabled.
+ * This is used to configure the display controller.
+ *
+ * The commands are stored in a byte array with the format:
+ * command, num_parameters, [ parameter, ...], command, ...
+ *
+ * Some commands require a pause before the next command can be received.
+ * Inserting a delay in the command sequence is done by using the NOP command with one
+ * parameter: delay in miliseconds (the No Operation command is part of the MIPI Display
+ * Command Set where it has no parameters).
+ *
+ * Example:
+ * command 0x11
+ * sleep 120ms
+ * command 0xb1 parameters 0x01, 0x2c, 0x2d
+ * command 0x29
+ *
+ * Byte sequence:
+ * 0x11 0x00
+ * 0x00 0x01 0x78
+ * 0xb1 0x03 0x01 0x2c 0x2d
+ * 0x29 0x00
+ */
+ u8 commands[];
+};
+
+struct panel_mipi_dbi_commands {
+ const u8 *buf;
+ size_t len;
+};
+
+static struct panel_mipi_dbi_commands *
+panel_mipi_dbi_check_commands(struct device *dev, const struct firmware *fw)
+{
+ const struct panel_mipi_dbi_config *config = (struct panel_mipi_dbi_config *)fw->data;
+ struct panel_mipi_dbi_commands *commands;
+ size_t size = fw->size, commands_len;
+ unsigned int i = 0;
+
+ if (size < sizeof(*config) + 2) { /* At least 1 command */
+ dev_err(dev, "config: file size=%zu is too small\n", size);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (memcmp(config->magic, panel_mipi_dbi_magic, sizeof(config->magic))) {
+ dev_err(dev, "config: Bad magic: %15ph\n", config->magic);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (config->file_format_version != 1) {
+ dev_err(dev, "config: version=%u is not supported\n", config->file_format_version);
+ return ERR_PTR(-EINVAL);
+ }
+
+ dev_dbg(dev, "size=%zu version=%u\n", size, config->file_format_version);
+
+ commands_len = size - sizeof(*config);
+
+ while ((i + 1) < commands_len) {
+ u8 command = config->commands[i++];
+ u8 num_parameters = config->commands[i++];
+ const u8 *parameters = &config->commands[i];
+
+ i += num_parameters;
+ if (i > commands_len) {
+ dev_err(dev, "config: command=0x%02x num_parameters=%u overflows\n",
+ command, num_parameters);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (command == 0x00 && num_parameters == 1)
+ dev_dbg(dev, "sleep %ums\n", parameters[0]);
+ else
+ dev_dbg(dev, "command %02x %*ph\n",
+ command, num_parameters, parameters);
+ }
+
+ if (i != commands_len) {
+ dev_err(dev, "config: malformed command array\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ commands = kzalloc(sizeof(*commands), GFP_KERNEL);
+ if (!commands)
+ return ERR_PTR(-ENOMEM);
+
+ commands->len = commands_len;
+ commands->buf = kmemdup(config->commands, commands->len, GFP_KERNEL);
+ if (!commands->buf)
+ return ERR_PTR(-ENOMEM);
+
+ return commands;
+}
+
+static struct panel_mipi_dbi_commands *panel_mipi_dbi_commands_from_fw(struct device *dev)
+{
+ struct panel_mipi_dbi_commands *commands;
+ const struct firmware *fw;
+ const char *compatible;
+ char fw_name[40];
+ int ret;
+
+ ret = of_property_read_string_index(dev->of_node, "compatible", 0, &compatible);
+ if (ret)
+ return ERR_PTR(ret);
+
+ snprintf(fw_name, sizeof(fw_name), "%s.bin", compatible);
+ ret = request_firmware(&fw, fw_name, dev);
+ if (ret) {
+ dev_err(dev, "No config file found for compatible '%s' (error=%d)\n",
+ compatible, ret);
+
+ return ERR_PTR(ret);
+ }
+
+ commands = panel_mipi_dbi_check_commands(dev, fw);
+ release_firmware(fw);
+
+ return commands;
+}
+
+static void panel_mipi_dbi_commands_execute(struct mipi_dbi *dbi,
+ struct panel_mipi_dbi_commands *commands)
+{
+ unsigned int i = 0;
+
+ if (!commands)
+ return;
+
+ while (i < commands->len) {
+ u8 command = commands->buf[i++];
+ u8 num_parameters = commands->buf[i++];
+ const u8 *parameters = &commands->buf[i];
+
+ if (command == 0x00 && num_parameters == 1)
+ mdelay(parameters[0]);
+ else if (num_parameters)
+ mipi_dbi_command_stackbuf(dbi, command, parameters, num_parameters);
+ else
+ mipi_dbi_command(dbi, command);
+
+ i += num_parameters;
+ }
+}
+
+static void panel_mipi_dbi_enable(struct fb_info *info)
+{
+ struct mipi_dbi_dev *dbidev = container_of(info, struct mipi_dbi_dev, info);
+ struct mipi_dbi *dbi = &dbidev->dbi;
+ int ret;
+
+ if (!info->mode) {
+ dev_err(dbidev->dev, "No valid mode found\n");
+ return;
+ }
+
+ if (dbidev->backlight_node && !dbidev->backlight) {
+ dbidev->backlight = of_backlight_find(dbidev->backlight_node);
+ if (!dbidev->backlight)
+ dev_err(dbidev->dev, "No backlight found\n");
+ }
+
+ if (!dbidev->driver_private) {
+ dbidev->driver_private = panel_mipi_dbi_commands_from_fw(dbidev->dev);
+ if (IS_ERR(dbidev->driver_private)) {
+ dbidev->driver_private = NULL;
+ return;
+ }
+ }
+
+ ret = mipi_dbi_poweron_conditional_reset(dbidev);
+ if (ret < 0)
+ return;
+ if (!ret)
+ panel_mipi_dbi_commands_execute(dbi, dbidev->driver_private);
+
+ mipi_dbi_enable_flush(dbidev, info);
+}
+
+
+static struct fb_ops panel_mipi_dbi_ops = {
+ .fb_enable = panel_mipi_dbi_enable,
+ .fb_disable = mipi_dbi_fb_disable,
+ .fb_damage = mipi_dbi_fb_damage,
+ .fb_flush = mipi_dbi_fb_flush,
+};
+
+
+static int panel_mipi_dbi_get_mode(struct mipi_dbi_dev *dbidev, struct fb_videomode *mode)
+{
+ struct device *dev = dbidev->dev;
+ int ret;
+
+ ret = of_get_display_timing(dev->of_node, "panel-timing", mode);
+ if (ret) {
+ dev_err(dev, "%pOF: failed to get panel-timing (error=%d)\n", dev->of_node, ret);
+ return ret;
+ }
+
+ /*
+ * Make sure width and height are set and that only back porch and
+ * pixelclock are set in the other timing values. Also check that
+ * width and height don't exceed the 16-bit value specified by MIPI DCS.
+ */
+ if (!mode->xres || !mode->yres || mode->display_flags ||
+ mode->right_margin || mode->hsync_len || (mode->left_margin + mode->xres) > 0xffff ||
+ mode->lower_margin || mode->vsync_len || (mode->upper_margin + mode->yres) > 0xffff) {
+ dev_err(dev, "%pOF: panel-timing out of bounds\n", dev->of_node);
+ return -EINVAL;
+ }
+
+ /* The driver doesn't use the pixel clock but it is mandatory so fake one if not set */
+ if (!mode->pixclock) {
+ mode->pixclock =
+ (mode->left_margin + mode->xres + mode->right_margin + mode->hsync_len) *
+ (mode->upper_margin + mode->yres + mode->lower_margin + mode->vsync_len) *
+ 60 / 1000;
+ }
+
+ return 0;
+}
+
+static int panel_mipi_dbi_spi_probe(struct device *dev)
+{
+ struct mipi_dbi_dev *dbidev;
+ struct spi_device *spi = to_spi_device(dev);
+ struct mipi_dbi *dbi;
+ struct fb_info *info;
+ struct gpio_desc *dc;
+ int ret;
+
+ dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL);
+ if (!dbidev)
+ return -ENOMEM;
+
+ dbidev->dev = dev;
+ dbi = &dbidev->dbi;
+ info = &dbidev->info;
+
+ ret = panel_mipi_dbi_get_mode(dbidev, &dbidev->mode);
+ if (ret)
+ return ret;
+
+ dbidev->regulator = regulator_get(dev, "power");
+ if (IS_ERR(dbidev->regulator))
+ return dev_err_probe(dev, PTR_ERR(dbidev->regulator),
+ "Failed to get regulator 'power'\n");
+
+ dbidev->io_regulator = regulator_get(dev, "io");
+ if (IS_ERR(dbidev->io_regulator))
+ return dev_err_probe(dev, PTR_ERR(dbidev->io_regulator),
+ "Failed to get regulator 'io'\n");
+
+ dbidev->backlight_node = of_parse_phandle(dev->of_node, "backlight", 0);
+
+ dbi->reset = gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(dbi->reset))
+ return dev_errp_probe(dev, dbi->reset,
+ "Failed to get GPIO 'reset'\n");
+
+ dc = gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
+ if (IS_ERR(dc))
+ return dev_errp_probe(dev, dc, "Failed to get GPIO 'dc'\n");
+
+ ret = mipi_dbi_spi_init(spi, dbi, dc);
+ if (ret)
+ return ret;
+
+ ret = mipi_dbi_dev_init(dbidev, &panel_mipi_dbi_ops, &dbidev->mode);
+ if (ret)
+ return ret;
+
+ ret = register_framebuffer(info);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to register framebuffer\n");
+
+ return 0;
+}
+
+static const struct of_device_id panel_mipi_dbi_spi_of_match[] = {
+ { .compatible = "panel-mipi-dbi-spi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, panel_mipi_dbi_spi_of_match);
+
+static struct driver panel_mipi_dbi_spi_driver = {
+ .name = "panel-mipi-dbi-spi",
+ .probe = panel_mipi_dbi_spi_probe,
+ .of_compatible = DRV_OF_COMPAT(panel_mipi_dbi_spi_of_match),
+};
+device_spi_driver(panel_mipi_dbi_spi_driver);
+
+MODULE_DESCRIPTION("MIPI DBI compatible display panel driver");
+MODULE_AUTHOR("Noralf Trønnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pxa.c b/drivers/video/pxa.c
index d444e0981f..561a73fb32 100644
--- a/drivers/video/pxa.c
+++ b/drivers/video/pxa.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2010 Marc Kleine-Budde, Pengutronix
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
* Derived from the linux-2.6 pxa framebuffer driver:
*
* Copyright (C) 1999 Eric A. Thomas.
@@ -32,13 +23,13 @@
#include <malloc.h>
#include <linux/err.h>
-#include <mach/clock.h>
-#include <mach/pxa-regs.h>
-#include <mach/regs-lcd.h>
-#include <mach/pxafb.h>
+#include <mach/pxa/clock.h>
+#include <mach/pxa/pxa-regs.h>
+#include <mach/pxa/regs-lcd.h>
+#include <mach/pxa/pxafb.h>
#include <asm/io.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
/* PXA LCD DMA descriptor */
struct pxafb_dma_descriptor {
@@ -83,7 +74,7 @@ struct pxafb_info {
struct pxafb_videomode *mode;
struct fb_info info;
- struct device_d *dev;
+ struct device *dev;
void (*lcd_power)(int);
void (*backlight_power)(int);
@@ -485,7 +476,7 @@ static struct fb_ops pxafb_ops = {
.fb_disable = pxafb_disable_controller,
};
-static int pxafb_probe(struct device_d *dev)
+static int pxafb_probe(struct device *dev)
{
struct resource *iores;
struct pxafb_platform_data *pdata = dev->platform_data;
@@ -533,6 +524,7 @@ static int pxafb_probe(struct device_d *dev)
pxafb_activate_var(fbi);
+ fbi->info.dev.parent = dev;
ret = register_framebuffer(&fbi->info);
if (ret < 0) {
dev_err(dev, "failed to register framebuffer\n");
@@ -542,7 +534,7 @@ static int pxafb_probe(struct device_d *dev)
return 0;
}
-static struct driver_d pxafb_driver = {
+static struct driver pxafb_driver = {
.name = "pxafb",
.probe = pxafb_probe,
};
diff --git a/drivers/video/ramfb.c b/drivers/video/ramfb.c
new file mode 100644
index 0000000000..3442e81b9e
--- /dev/null
+++ b/drivers/video/ramfb.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: (C) 2022 Adrian Negreanu
+
+#define pr_fmt(fmt) "ramfb: " fmt
+
+#include <common.h>
+#include <fb.h>
+#include <fcntl.h>
+#include <dma.h>
+#include <init.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fs.h>
+#include <linux/qemu_fw_cfg.h>
+#include <video/fourcc.h>
+
+struct ramfb {
+ int fd;
+ struct fb_info info;
+ dma_addr_t screen_dma;
+ struct fb_videomode mode;
+ u16 etcfb_select;
+};
+
+struct fw_cfg_etc_ramfb {
+ u64 addr;
+ u32 fourcc;
+ u32 flags;
+ u32 width;
+ u32 height;
+ u32 stride;
+} __packed;
+
+static int fw_cfg_find_file(struct device *dev, int fd, const char *filename)
+{
+ size_t filename_len = strlen(filename);
+ ssize_t ret;
+ __be32 count;
+ int i;
+
+ ioctl(fd, FW_CFG_SELECT, &(u16) { FW_CFG_FILE_DIR });
+
+ lseek(fd, 0, SEEK_SET);
+
+ ret = read(fd, &count, sizeof(count));
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < be32_to_cpu(count); i++) {
+ struct fw_cfg_file qfile;
+
+ read(fd, &qfile, sizeof(qfile));
+
+ dev_dbg(dev, "enumerating file %s\n", qfile.name);
+
+ if (memcmp(qfile.name, filename, filename_len))
+ continue;
+
+ return be16_to_cpu(qfile.select);
+ }
+
+ return -ENOENT;
+}
+
+static void ramfb_populate_modes(struct ramfb *ramfb)
+{
+ struct fb_info *info = &ramfb->info;
+
+ ramfb->mode.name = "x8r8g8b8";
+ info->xres = ramfb->mode.xres = 640;
+ info->yres = ramfb->mode.yres = 480;
+
+ info->mode = &ramfb->mode;
+ info->bits_per_pixel = 32;
+ info->red = (struct fb_bitfield) {16, 8};
+ info->green = (struct fb_bitfield) {8, 8};
+ info->blue = (struct fb_bitfield) {0, 8};
+ info->transp = (struct fb_bitfield) {0, 0};
+}
+
+static int ramfb_activate_var(struct fb_info *fbi)
+{
+ struct ramfb *ramfb = fbi->priv;
+
+ if (fbi->screen_base)
+ dma_free_coherent(fbi->screen_base, ramfb->screen_dma, fbi->screen_size);
+
+ fbi->screen_size = fbi->xres * fbi->yres * fbi->bits_per_pixel;
+ fbi->screen_base = dma_alloc_coherent(fbi->screen_size, &ramfb->screen_dma);
+
+ return 0;
+}
+
+static void ramfb_enable(struct fb_info *fbi)
+{
+ struct ramfb *ramfb = fbi->priv;
+ struct fw_cfg_etc_ramfb *etc_ramfb;
+
+ etc_ramfb = dma_alloc(sizeof(*etc_ramfb));
+
+ etc_ramfb->addr = cpu_to_be64(ramfb->screen_dma);
+ etc_ramfb->fourcc = cpu_to_be32(DRM_FORMAT_XRGB8888);
+ etc_ramfb->flags = cpu_to_be32(0);
+ etc_ramfb->width = cpu_to_be32(fbi->xres);
+ etc_ramfb->height = cpu_to_be32(fbi->yres);
+ etc_ramfb->stride = cpu_to_be32(fbi->line_length);
+
+ ioctl(ramfb->fd, FW_CFG_SELECT, &ramfb->etcfb_select);
+
+ pwrite(ramfb->fd, etc_ramfb, sizeof(*etc_ramfb), 0);
+
+ dma_free(etc_ramfb);
+}
+
+static struct fb_ops ramfb_ops = {
+ .fb_activate_var = ramfb_activate_var,
+ .fb_enable = ramfb_enable,
+};
+
+static int ramfb_probe(struct device *parent_dev, int fd)
+{
+ int ret;
+ struct ramfb *ramfb;
+ struct fb_info *fbi;
+
+ ret = -ENODEV;
+
+ ramfb = xzalloc(sizeof(*ramfb));
+
+ ramfb->fd = fd;
+
+ ret = fw_cfg_find_file(parent_dev, fd, "etc/ramfb");
+ if (ret < 0) {
+ dev_dbg(parent_dev, "ramfb: fw_cfg (etc/ramfb) file not found\n");
+ return -ENODEV;
+ }
+
+ ramfb->etcfb_select = ret;
+ dev_dbg(parent_dev, "etc/ramfb file at slot 0x%x\n", ramfb->etcfb_select);
+
+ fbi = &ramfb->info;
+ fbi->priv = ramfb;
+ fbi->fbops = &ramfb_ops;
+ fbi->dev.parent = parent_dev;
+
+ ramfb_populate_modes(ramfb);
+
+ ret = register_framebuffer(fbi);
+ if (ret < 0) {
+ dev_err(parent_dev, "Unable to register ramfb: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(parent_dev, "ramfb registered\n");
+
+ return 0;
+}
+
+static int ramfb_driver_init(void)
+{
+ struct cdev *cdev;
+ int err = 0;
+
+ for_each_cdev(cdev) {
+ int fd, ret;
+
+ if (!strstarts(cdev->name, "fw_cfg"))
+ continue;
+
+ fd = cdev_fdopen(cdev, O_RDWR);
+ if (fd < 0) {
+ err = fd;
+ continue;
+ }
+
+ ret = ramfb_probe(cdev->dev, fd);
+ if (ret == 0)
+ continue;
+ if (ret != -ENODEV && ret != -ENXIO)
+ err = ret;
+
+ close(fd);
+ }
+
+ return err;
+}
+device_initcall(ramfb_driver_init);
+
+MODULE_AUTHOR("Adrian Negreanu <adrian.negreanu@nxp.com>");
+MODULE_DESCRIPTION("QEMU RamFB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/rave-sp-backlight.c b/drivers/video/rave-sp-backlight.c
index 877a5feeb6..360b27eebb 100644
--- a/drivers/video/rave-sp-backlight.c
+++ b/drivers/video/rave-sp-backlight.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LCD Backlight driver for RAVE SP
*
* Copyright (C) 2018 Zodiac Inflight Innovations
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <common.h>
@@ -39,7 +27,7 @@ static int rave_sp_backlight_set(struct backlight_device *bd, int brightness)
return rave_sp_exec(sp, cmd, sizeof(cmd), NULL, 0);
}
-static int rave_sp_backlight_probe(struct device_d *dev)
+static int rave_sp_backlight_probe(struct device *dev)
{
struct backlight_device *bd;
int ret;
@@ -64,8 +52,9 @@ static const struct of_device_id rave_sp_backlight_of_match[] = {
{ .compatible = "zii,rave-sp-backlight" },
{}
};
+MODULE_DEVICE_TABLE(of, rave_sp_backlight_of_match);
-static struct driver_d rave_sp_backlight_driver = {
+static struct driver rave_sp_backlight_driver = {
.name = "rave-sp-backlight",
.probe = rave_sp_backlight_probe,
.of_compatible = DRV_OF_COMPAT(rave_sp_backlight_of_match),
diff --git a/drivers/video/s3c24xx.c b/drivers/video/s3c24xx.c
deleted file mode 100644
index 84ed0aee39..0000000000
--- a/drivers/video/s3c24xx.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright (C) 2010 Juergen Beisert
- * Copyright (C) 2011 Alexey Galakhov
- *
- * This driver is based on a patch found in the web:
- * (C) Copyright 2006 by OpenMoko, Inc.
- * Author: Harald Welte <laforge at openmoko.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- */
-
-#include <common.h>
-#include <init.h>
-#include <fb.h>
-#include <driver.h>
-#include <malloc.h>
-#include <errno.h>
-#include <io.h>
-#include <mach/s3c-generic.h>
-#include <mach/s3c24xx-fb.h>
-
-#define LCDCON1 0x00
-# define PNRMODE(x) (((x) & 3) << 5)
-# define BPPMODE(x) (((x) & 0xf) << 1)
-# define SET_CLKVAL(x) (((x) & 0x3ff) << 8)
-# define GET_CLKVAL(x) (((x) >> 8) & 0x3ff)
-# define ENVID (1 << 0)
-
-#define LCDCON2 0x04
-# define SET_VBPD(x) (((x) & 0xff) << 24)
-# define SET_LINEVAL(x) (((x) & 0x3ff) << 14)
-# define SET_VFPD(x) (((x) & 0xff) << 6)
-# define SET_VSPW(x) ((x) & 0x3f)
-
-#define LCDCON3 0x08
-# define SET_HBPD(x) (((x) & 0x7f) << 19)
-# define SET_HOZVAL(x) (((x) & 0x7ff) << 8)
-# define SET_HFPD(x) ((x) & 0xff)
-
-#define LCDCON4 0x0c
-# define SET_HSPW(x) ((x) & 0xff)
-
-#define LCDCON5 0x10
-# define BPP24BL (1 << 12)
-# define FRM565 (1 << 11)
-# define INV_CLK (1 << 10)
-# define INV_HS (1 << 9)
-# define INV_VS (1 << 8)
-# define INV_DTA (1 << 7)
-# define INV_DE (1 << 6)
-# define INV_PWREN (1 << 5)
-# define INV_LEND (1 << 4)
-# define ENA_PWREN (1 << 3)
-# define ENA_LEND (1 << 2)
-# define BSWP (1 << 1)
-# define HWSWP (1 << 0)
-
-#define LCDSADDR1 0x14
-# define SET_LCDBANK(x) (((x) & 0x1ff) << 21)
-# define GET_LCDBANK(x) (((x) >> 21) & 0x1ff)
-# define SET_LCDBASEU(x) ((x) & 0x1fffff)
-# define GET_LCDBASEU(x) ((x) & 0x1fffff)
-
-#define LCDSADDR2 0x18
-# define SET_LCDBASEL(x) ((x) & 0x1fffff)
-# define GET_LCDBASEL(x) ((x) & 0x1fffff)
-
-#define LCDSADDR3 0x1c
-# define SET_OFFSIZE(x) (((x) & 0x7ff) << 11)
-# define GET_OFFSIZE(x) (((x) >> 11) & 0x7ff)
-# define SET_PAGE_WIDTH(x) ((x) & 0x3ff)
-# define GET_PAGE_WIDTH(x) ((x) & 0x3ff)
-
-#define RED_LUT 0x20
-#define GREEN_LUT 0x24
-#define BLUE_LUT 0x28
-
-#define DITHMODE 0x4c
-
-#define TPAL 0x50
-
-#define LCDINTPND 0x54
-#define LCDSRCPND 0x58
-#define LCDINTMSK 0x5c
-# define FIWSEL (1 << 2)
-# define INT_FrSyn (1 << 1)
-# define INT_FiCnt (1 << 0)
-
-#define TCONSEL 0x60
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define TRANSP 3
-
-struct s3cfb_info {
- void __iomem *base;
- unsigned memory_size;
- struct fb_info info;
- struct device_d *hw_dev;
- int passive_display;
- void (*enable)(int enable);
-};
-
-/* the RGB565 true colour mode */
-static const struct fb_bitfield def_rgb565[] = {
- [RED] = {
- .offset = 11,
- .length = 5,
- },
- [GREEN] = {
- .offset = 5,
- .length = 6,
- },
- [BLUE] = {
- .offset = 0,
- .length = 5,
- },
- [TRANSP] = { /* no support for transparency */
- .length = 0,
- }
-};
-
-/* the RGB888 true colour mode */
-static const struct fb_bitfield def_rgb888[] = {
- [RED] = {
- .offset = 16,
- .length = 8,
- },
- [GREEN] = {
- .offset = 8,
- .length = 8,
- },
- [BLUE] = {
- .offset = 0,
- .length = 8,
- },
- [TRANSP] = { /* no support for transparency */
- .length = 0,
- }
-};
-
-/**
- * @param fb_info Framebuffer information
- */
-static void s3cfb_enable_controller(struct fb_info *fb_info)
-{
- struct s3cfb_info *fbi = fb_info->priv;
- uint32_t con1;
-
- con1 = readl(fbi->base + LCDCON1);
-
- con1 |= ENVID;
-
- writel(con1, fbi->base + LCDCON1);
-
- if (fbi->enable)
- fbi->enable(1);
-}
-
-/**
- * @param fb_info Framebuffer information
- */
-static void s3cfb_disable_controller(struct fb_info *fb_info)
-{
- struct s3cfb_info *fbi = fb_info->priv;
- uint32_t con1;
-
- if (fbi->enable)
- fbi->enable(0);
-
- con1 = readl(fbi->base + LCDCON1);
-
- con1 &= ~ENVID;
-
- writel(con1, fbi->base + LCDCON1);
-}
-
-/**
- * Prepare the video hardware for a specified video mode
- * @param fb_info Framebuffer information
- * @return 0 on success
- */
-static int s3cfb_activate_var(struct fb_info *fb_info)
-{
- struct s3cfb_info *fbi = fb_info->priv;
- struct fb_videomode *mode = fb_info->mode;
- unsigned size, hclk, div;
- uint32_t con1, con2, con3, con4, con5 = 0;
-
- if (fbi->passive_display != 0) {
- dev_err(fbi->hw_dev, "Passive displays are currently not supported\n");
- return -EINVAL;
- }
-
- /*
- * we need at least this amount of memory for the framebuffer
- */
- size = mode->xres * mode->yres * (fb_info->bits_per_pixel >> 3);
- if (fbi->memory_size != size || fb_info->screen_base == NULL) {
- if (fb_info->screen_base)
- free(fb_info->screen_base);
- fbi->memory_size = 0;
- fb_info->screen_base = malloc(size);
- if (! fb_info->screen_base)
- return -ENOMEM;
- memset(fb_info->screen_base, 0, size);
- fbi->memory_size = size;
- }
-
- /* ensure video output is _off_ */
- writel(0x00000000, fbi->base + LCDCON1);
-
- hclk = s3c_get_hclk() / 1000U; /* hclk in kHz */
- div = hclk / PICOS2KHZ(mode->pixclock);
- if (div < 3)
- div = 3;
- /* pixel clock is: (hclk) / ((div + 1) * 2) */
- div += 1;
- div >>= 1;
- div -= 1;
-
- con1 = PNRMODE(3) | SET_CLKVAL(div); /* PNRMODE=3 is TFT */
-
- switch (fb_info->bits_per_pixel) {
- case 16:
- con1 |= BPPMODE(12);
- con5 |= FRM565;
- con5 |= HWSWP;
- fb_info->red = def_rgb565[RED];
- fb_info->green = def_rgb565[GREEN];
- fb_info->blue = def_rgb565[BLUE];
- fb_info->transp = def_rgb565[TRANSP];
- break;
- case 24:
- con1 |= BPPMODE(13);
- /* con5 |= BPP24BL; */ /* FIXME maybe needed, check alignment */
- fb_info->red = def_rgb888[RED];
- fb_info->green = def_rgb888[GREEN];
- fb_info->blue = def_rgb888[BLUE];
- fb_info->transp = def_rgb888[TRANSP];
- break;
- default:
- dev_err(fbi->hw_dev, "Invalid bits per pixel value: %u\n", fb_info->bits_per_pixel);
- return -EINVAL;
- }
-
- /* 'normal' in register description means positive logic */
- if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
- con5 |= INV_HS;
- if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
- con5 |= INV_VS;
- if (!(mode->sync & FB_SYNC_DE_HIGH_ACT))
- con5 |= INV_DE;
- if (mode->sync & FB_SYNC_CLK_INVERT)
- con5 |= INV_CLK; /* display should latch at the rising edge */
- if (mode->sync & FB_SYNC_DATA_INVERT)
- con5 |= INV_DTA;
- if (mode->sync & FB_SYNC_INVERT_PWREN)
- con5 |= INV_PWREN;
- if (mode->sync & FB_SYNC_INVERT_LEND)
- con5 |= INV_LEND;
- if (mode->sync & FB_SYNC_USE_PWREN)
- con5 |= ENA_PWREN; /* FIXME should this be done conditionally/later? */
- if (mode->sync & FB_SYNC_USE_LEND)
- con5 |= ENA_LEND;
- if (mode->sync & FB_SYNC_SWAP_BYTES)
- con5 ^= BSWP;
- if (mode->sync & FB_SYNC_SWAP_HW)
- con5 ^= HWSWP;
-
- /* vertical timing */
- con2 = SET_VBPD(mode->upper_margin - 1) |
- SET_LINEVAL(mode->yres - 1) |
- SET_VFPD(mode->lower_margin - 1) |
- SET_VSPW(mode->vsync_len - 1);
-
- /* horizontal timing */
- con3 = SET_HBPD(mode->left_margin - 1) |
- SET_HOZVAL(mode->xres - 1) |
- SET_HFPD(mode->right_margin - 1);
- con4 = SET_HSPW(mode->hsync_len - 1);
-
- /* basic timing setup */
- writel(con1, fbi->base + LCDCON1);
- dev_dbg(fbi->hw_dev, "writing %08X into %p (con1)\n", con1, fbi->base + LCDCON1);
- writel(con2, fbi->base + LCDCON2);
- dev_dbg(fbi->hw_dev, "writing %08X into %p (con2)\n", con2, fbi->base + LCDCON2);
- writel(con3, fbi->base + LCDCON3);
- dev_dbg(fbi->hw_dev, "writing %08X into %p (con3)\n", con3, fbi->base + LCDCON3);
- writel(con4, fbi->base + LCDCON4);
- dev_dbg(fbi->hw_dev, "writing %08X into %p (con4)\n", con4, fbi->base + LCDCON4);
- writel(con5, fbi->base + LCDCON5);
- dev_dbg(fbi->hw_dev, "writing %08X into %p (con5)\n", con5, fbi->base + LCDCON5);
-
- dev_dbg(fbi->hw_dev, "setting up the fb baseadress to %p\n", fb_info->screen_base);
-
- /* framebuffer memory setup */
- writel((unsigned)fb_info->screen_base >> 1, fbi->base + LCDSADDR1);
- size = mode->xres * (fb_info->bits_per_pixel >> 3) * (mode->yres);
- writel(SET_LCDBASEL(((unsigned)fb_info->screen_base + size) >> 1), fbi->base + LCDSADDR2);
- writel(SET_OFFSIZE(0) |
- SET_PAGE_WIDTH((mode->xres * fb_info->bits_per_pixel) >> 4),
- fbi->base + LCDSADDR3);
- writel(FIWSEL | INT_FrSyn | INT_FiCnt, fbi->base + LCDINTMSK);
-
- return 0;
-}
-
-/**
- * Print some information about the current hardware state
- * @param hw_dev S3C video device
- */
-static void s3cfb_info(struct device_d *hw_dev)
-{
- uint32_t con1, addr1, addr2, addr3;
- struct s3cfb_info *fbi = hw_dev->priv;
-
- con1 = readl(fbi->base + LCDCON1);
- addr1 = readl(fbi->base + LCDSADDR1);
- addr2 = readl(fbi->base + LCDSADDR2);
- addr3 = readl(fbi->base + LCDSADDR3);
-
- printf(" Video hardware info:\n");
- printf(" Video clock is running at %u Hz\n", s3c_get_hclk() / ((GET_CLKVAL(con1) + 1) * 2));
- printf(" Video memory bank starts at 0x%08X\n", GET_LCDBANK(addr1) << 22);
- printf(" Video memory bank offset: 0x%08X\n", GET_LCDBASEU(addr1));
- printf(" Video memory end: 0x%08X\n", GET_LCDBASEU(addr2));
- printf(" Virtual screen offset size: %u half words\n", GET_OFFSIZE(addr3));
- printf(" Virtual screen page width: %u half words\n", GET_PAGE_WIDTH(addr3));
-}
-
-/*
- * There is only one video hardware instance available.
- * It makes no sense to dynamically allocate this data
- */
-static struct fb_ops s3cfb_ops = {
- .fb_activate_var = s3cfb_activate_var,
- .fb_enable = s3cfb_enable_controller,
- .fb_disable = s3cfb_disable_controller,
-};
-
-static struct s3cfb_info fbi = {
- .info = {
- .fbops = &s3cfb_ops,
- },
-};
-
-static int s3cfb_probe(struct device_d *hw_dev)
-{
- struct resource *iores;
- struct s3c_fb_platform_data *pdata = hw_dev->platform_data;
- int ret;
-
- if (! pdata)
- return -ENODEV;
-
- iores = dev_request_mem_resource(hw_dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- fbi.base = IOMEM(iores->start);
- writel(0, fbi.base + LCDCON1);
- writel(0, fbi.base + LCDCON5); /* FIXME not 0 for some displays */
-
- /* just init */
- fbi.info.priv = &fbi;
-
- /* add runtime hardware info */
- fbi.hw_dev = hw_dev;
- hw_dev->priv = &fbi;
-
- /* add runtime video info */
- fbi.info.modes.modes = pdata->mode_list;
- fbi.info.modes.num_modes = pdata->mode_cnt;
- fbi.info.mode = &fbi.info.modes.modes[0];
- fbi.info.xres = fbi.info.mode->xres;
- fbi.info.yres = fbi.info.mode->yres;
- if (pdata->bits_per_pixel)
- fbi.info.bits_per_pixel = pdata->bits_per_pixel;
- else
- fbi.info.bits_per_pixel = 16;
- fbi.passive_display = pdata->passive_display;
- fbi.enable = pdata->enable;
-
- if (IS_ENABLED(CONFIG_DRIVER_VIDEO_S3C_VERBOSE))
- hw_dev->info = s3cfb_info;
-
- ret = register_framebuffer(&fbi.info);
- if (ret != 0) {
- dev_err(hw_dev, "Failed to register framebuffer\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static struct driver_d s3cfb_driver = {
- .name = "s3c_fb",
- .probe = s3cfb_probe,
-};
-device_platform_driver(s3cfb_driver);
-
-/**
- * The S3C244x LCD controller supports passive (CSTN/STN) and active (TFT) LC displays
- *
- * The driver itself currently supports only active TFT LC displays in the follwing manner:
- *
- * * True colours
- * - 16 bpp
- * - 24 bpp (untested)
- */
diff --git a/drivers/video/sdl.c b/drivers/video/sdl.c
index 8f5b409efb..06e13b7735 100644
--- a/drivers/video/sdl.c
+++ b/drivers/video/sdl.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * GPL v2
*/
#include <common.h>
@@ -13,23 +12,25 @@
#include <errno.h>
#include <gui/graphic_utils.h>
+#define to_mask(color) GENMASK(color.length - 1, color.offset)
+
static void sdlfb_enable(struct fb_info *info)
{
- int ret;
-
- ret = sdl_open(info->xres, info->yres, info->bits_per_pixel,
- info->screen_base);
- if (ret)
- return;
- sdl_get_bitfield_rgba(&info->red, &info->green, &info->blue, &info->transp);
-
- sdl_start_timer();
+ struct sdl_fb_info sdl_info = {
+ .screen_base = info->screen_base,
+ .xres = info->xres, .yres = info->yres, .bpp = info->bits_per_pixel,
+ .rmask = to_mask(info->red),
+ .gmask = to_mask(info->green),
+ .bmask = to_mask(info->blue),
+ .amask = to_mask(info->transp),
+ };
+
+ sdl_video_open(&sdl_info);
}
static void sdlfb_disable(struct fb_info *info)
{
- sdl_stop_timer();
- sdl_close();
+ sdl_video_close();
}
static struct fb_ops sdlfb_ops = {
@@ -37,7 +38,7 @@ static struct fb_ops sdlfb_ops = {
.fb_disable = sdlfb_disable,
};
-static int sdlfb_probe(struct device_d *dev)
+static int sdlfb_probe(struct device *dev)
{
struct fb_info *fb;
int ret = -EIO;
@@ -48,10 +49,19 @@ static int sdlfb_probe(struct device_d *dev)
fb = xzalloc(sizeof(*fb));
fb->modes.modes = fb->mode = dev->platform_data;
fb->modes.num_modes = 1;
- fb->bits_per_pixel = 4 << 3;
fb->xres = fb->mode->xres;
fb->yres = fb->mode->yres;
+ fb->bits_per_pixel = 32;
+ fb->transp.length = 8;
+ fb->red.length = 8;
+ fb->green.length = 8;
+ fb->blue.length = 8;
+ fb->transp.offset = 24;
+ fb->red.offset = 16;
+ fb->green.offset = 8;
+ fb->blue.offset = 0;
+
fb->priv = fb;
fb->fbops = &sdlfb_ops;
@@ -59,15 +69,6 @@ static int sdlfb_probe(struct device_d *dev)
fb->screen_base = xzalloc(fb->xres * fb->yres *
fb->bits_per_pixel >> 3);
- dev_dbg(dev, "red: length = %d, offset = %d\n",
- fb->red.length, fb->red.offset);
- dev_dbg(dev, "green: length = %d, offset = %d\n",
- fb->green.length, fb->green.offset);
- dev_dbg(dev, "blue: length = %d, offset = %d\n",
- fb->blue.length, fb->blue.offset);
- dev_dbg(dev, "transp: length = %d, offset = %d\n",
- fb->transp.length, fb->transp.offset);
-
/* add runtime hardware info */
dev->priv = fb;
@@ -77,20 +78,18 @@ static int sdlfb_probe(struct device_d *dev)
kfree(fb->screen_base);
kfree(fb);
- sdl_close();
return ret;
}
-static void sdlfb_remove(struct device_d *dev)
+static void sdlfb_remove(struct device *dev)
{
struct fb_info *fb = dev->priv;
kfree(fb->screen_base);
kfree(fb);
- sdl_close();
}
-static struct driver_d sdlfb_driver = {
+static struct driver sdlfb_driver = {
.name = "sdlfb",
.probe = sdlfb_probe,
.remove = sdlfb_remove,
diff --git a/drivers/video/simple-panel.c b/drivers/video/simple-panel.c
index be39ff0e94..7048e2f51b 100644
--- a/drivers/video/simple-panel.c
+++ b/drivers/video/simple-panel.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* simple panel support for barebox
*
* (C) Copyright 2014 Sascha Hauer, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <malloc.h>
@@ -30,7 +17,7 @@
#include <i2c/i2c.h>
struct simple_panel {
- struct device_d *dev;
+ struct device *dev;
struct vpl vpl;
int enable_gpio;
int enable_active_high;
@@ -112,7 +99,7 @@ static int simple_panel_get_modes(struct simple_panel *panel, struct display_tim
}
}
- modes = of_get_display_timings(panel->dev->device_node);
+ modes = of_get_display_timings(panel->dev->of_node);
if (modes) {
timings->modes = modes->modes;
timings->num_modes = modes->num_modes;
@@ -138,14 +125,14 @@ static int simple_panel_ioctl(struct vpl *vpl, unsigned int port,
case VPL_GET_VIDEOMODES:
return simple_panel_get_modes(panel, ptr);
default:
- return -ENOSYS;
+ return 0;
}
}
-static int simple_panel_probe(struct device_d *dev)
+static int simple_panel_probe(struct device *dev)
{
struct simple_panel *panel;
- struct device_node *node = dev->device_node;
+ struct device_node *node = dev->of_node;
enum of_gpio_flags flags;
int ret;
@@ -178,8 +165,9 @@ static struct of_device_id simple_panel_of_ids[] = {
{ .compatible = "simple-panel", },
{ }
};
+MODULE_DEVICE_TABLE(of, simple_panel_of_ids);
-static struct driver_d simple_panel_driver = {
+static struct driver simple_panel_driver = {
.name = "simple-panel",
.probe = simple_panel_probe,
.of_compatible = DRV_OF_COMPAT(simple_panel_of_ids),
diff --git a/drivers/video/simplefb-client.c b/drivers/video/simplefb-client.c
new file mode 100644
index 0000000000..dafec6178f
--- /dev/null
+++ b/drivers/video/simplefb-client.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Simplest possible simple frame-buffer driver, as a platform device
+ *
+ * Copyright (c) 2013, Stephen Warren
+ *
+ * Based on q40fb.c, which was:
+ * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org>
+ *
+ * Also based on offb.c, which was:
+ * Copyright (C) 1997 Geert Uytterhoeven
+ * Copyright (C) 1996 Paul Mackerras
+ */
+
+#include <common.h>
+#include <fb.h>
+#include <io.h>
+#include <linux/platform_data/simplefb.h>
+#include <driver.h>
+#include <of.h>
+
+static struct fb_ops simplefb_ops;
+
+static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
+
+struct simplefb_params {
+ u32 width;
+ u32 height;
+ u32 stride;
+ struct simplefb_format *format;
+};
+
+struct simplefb {
+ struct fb_info info;
+ struct fb_videomode mode;
+};
+
+static int simplefb_parse_dt(struct device *dev,
+ struct simplefb_params *params)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+ const char *format;
+ int i;
+
+ ret = of_property_read_u32(np, "width", &params->width);
+ if (ret) {
+ dev_err(dev, "Can't parse width property\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "height", &params->height);
+ if (ret) {
+ dev_err(dev, "Can't parse height property\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "stride", &params->stride);
+ if (ret) {
+ dev_err(dev, "Can't parse stride property\n");
+ return ret;
+ }
+
+ ret = of_property_read_string(np, "format", &format);
+ if (ret) {
+ dev_err(dev, "Can't parse format property\n");
+ return ret;
+ }
+ params->format = NULL;
+ for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
+ if (strcmp(format, simplefb_formats[i].name))
+ continue;
+ params->format = &simplefb_formats[i];
+ break;
+ }
+ if (!params->format) {
+ dev_err(dev, "Invalid format value\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int simplefb_probe(struct device *dev)
+{
+ int ret;
+ struct simplefb_params params;
+ struct simplefb *simplefb;
+ struct fb_info *info;
+ struct resource *mem;
+
+ ret = -ENODEV;
+ if (dev->of_node)
+ ret = simplefb_parse_dt(dev, &params);
+
+ if (ret)
+ return ret;
+
+ mem = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(mem)) {
+ dev_err(dev, "No memory resource\n");
+ return PTR_ERR(mem);
+ }
+
+ simplefb = xzalloc(sizeof(*simplefb));
+
+ simplefb->mode.name = params.format->name;
+ simplefb->mode.xres = params.width;
+ simplefb->mode.yres = params.height;
+
+ info = &simplefb->info;
+ info->mode = &simplefb->mode;
+ info->bits_per_pixel = params.format->bits_per_pixel;
+ info->red = params.format->red;
+ info->green = params.format->green;
+ info->blue = params.format->blue;
+ info->transp = params.format->transp;
+
+ info->screen_base = (void *)mem->start;
+ info->screen_size = resource_size(mem);
+
+
+ info->fbops = &simplefb_ops;
+
+ info->dev.parent = dev;
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(dev, "Unable to register simplefb: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "size %s registered\n", size_human_readable(info->screen_size));
+
+ return 0;
+}
+
+static const struct of_device_id simplefb_of_match[] = {
+ { .compatible = "simple-framebuffer", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, simplefb_of_match);
+
+static struct driver simplefb_driver = {
+ .name = "simple-framebuffer",
+ .of_compatible = simplefb_of_match,
+ .probe = simplefb_probe,
+};
+device_platform_driver(simplefb_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
+MODULE_DESCRIPTION("Simple framebuffer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb-fixup.c
index a2c59de364..65e0281a18 100644
--- a/drivers/video/simplefb.c
+++ b/drivers/video/simplefb-fixup.c
@@ -90,6 +90,7 @@ static int simplefb_create_node(struct device_node *root,
const struct fb_info *fbi, const char *format)
{
struct device_node *node;
+ phys_addr_t screen_base;
u32 cells[2];
int ret;
@@ -105,7 +106,11 @@ static int simplefb_create_node(struct device_node *root,
if (ret)
return ret;
- cells[0] = cpu_to_be32((u32)fbi->screen_base);
+ screen_base = virt_to_phys(fbi->screen_base);
+ if (upper_32_bits(screen_base))
+ return -ENOSYS;
+
+ cells[0] = cpu_to_be32(lower_32_bits(screen_base));
cells[1] = cpu_to_be32(fbi->line_length * fbi->yres);
ret = of_set_property(node, "reg", cells, sizeof(cells[0]) * 2, 1);
if (ret < 0)
@@ -130,8 +135,7 @@ static int simplefb_create_node(struct device_node *root,
if (ret < 0)
return ret;
- of_add_reserve_entry((u32)fbi->screen_base,
- (u32)fbi->screen_base + fbi->screen_size);
+ of_add_reserve_entry(screen_base, screen_base + fbi->screen_size);
return of_property_write_string(node, "status", "okay");
}
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
index 835814bf53..fb50e895c5 100644
--- a/drivers/video/ssd1307fb.c
+++ b/drivers/video/ssd1307fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for the Solomon SSD1307 OLED controller family
*
@@ -13,8 +14,6 @@
*
* Ported to barebox from linux v4.10
* Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de>
- *
- * Licensed under the GPLv2 or later.
*/
#include <common.h>
@@ -24,6 +23,7 @@
#include <gpio.h>
#include <of_gpio.h>
#include <regulator.h>
+#include <spi/spi.h>
#define SSD1307FB_DATA 0x40
#define SSD1307FB_COMMAND 0x80
@@ -54,6 +54,16 @@ struct ssd1307fb_deviceinfo {
int need_chargepump;
};
+struct ssd1307fb_array {
+ u8 type;
+ u8 data[0];
+};
+
+struct ssd1307fb_par;
+
+typedef int (*ssd1307fb_write_array)(struct ssd1307fb_par *par,
+ struct ssd1307fb_array *array, u32 len);
+
struct ssd1307fb_par {
u32 com_invdir;
u32 com_lrremap;
@@ -64,21 +74,20 @@ struct ssd1307fb_par {
u32 dclk_frq;
const struct ssd1307fb_deviceinfo *device_info;
struct i2c_client *client;
+ struct spi_device *spi;
u32 height;
struct fb_info *info;
u32 page_offset;
u32 prechargep1;
u32 prechargep2;
int reset;
+ int dc;
struct regulator *vbat;
u32 seg_remap;
u32 vcomh;
u32 width;
-};
-struct ssd1307fb_array {
- u8 type;
- u8 data[0];
+ ssd1307fb_write_array write_array;
};
static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
@@ -94,9 +103,31 @@ static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
return array;
}
-static int ssd1307fb_write_array(struct i2c_client *client,
- struct ssd1307fb_array *array, u32 len)
+static int ssd1307fb_spi_write_array(struct ssd1307fb_par *par,
+ struct ssd1307fb_array *array, u32 len)
+{
+ struct spi_device *spi = par->spi;
+ int ret;
+
+ if (array->type == SSD1307FB_COMMAND)
+ gpio_direction_output(par->dc, 0);
+ else
+ gpio_direction_output(par->dc, 1);
+
+ ret = spi_write(spi, array->data, len);
+ if (ret)
+ dev_err(&spi->dev, "Couldn't send SPI command.\n");
+
+ /* Ensure that we remain in data mode. */
+ gpio_direction_output(par->dc, 1);
+
+ return ret;
+}
+
+static int ssd1307fb_i2c_write_array(struct ssd1307fb_par *par,
+ struct ssd1307fb_array *array, u32 len)
{
+ struct i2c_client *client = par->client;
int ret;
len += sizeof(struct ssd1307fb_array);
@@ -110,7 +141,7 @@ static int ssd1307fb_write_array(struct i2c_client *client,
return 0;
}
-static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
+static inline int ssd1307fb_write_cmd(struct ssd1307fb_par *par, u8 cmd)
{
struct ssd1307fb_array *array;
int ret;
@@ -121,7 +152,7 @@ static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
array->data[0] = cmd;
- ret = ssd1307fb_write_array(client, array, 1);
+ ret = par->write_array(par, array, 1);
kfree(array);
return ret;
@@ -182,20 +213,20 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par)
}
}
- ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
+ par->write_array(par, array, par->width * par->height / 8);
kfree(array);
}
static void ssd1307fb_enable(struct fb_info *info)
{
struct ssd1307fb_par *par = info->priv;
- ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
+ ssd1307fb_write_cmd(par, SSD1307FB_DISPLAY_ON);
}
static void ssd1307fb_disable(struct fb_info *info)
{
struct ssd1307fb_par *par = info->priv;
- ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
+ ssd1307fb_write_cmd(par, SSD1307FB_DISPLAY_OFF);
}
static void ssd1307fb_flush(struct fb_info *info)
@@ -216,134 +247,134 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
u32 precharge, dclk, com_invdir, compins;
/* Set initial contrast */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_CONTRAST);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, par->contrast);
+ ret = ssd1307fb_write_cmd(par, par->contrast);
if (ret < 0)
return ret;
/* Set segment re-map */
if (par->seg_remap) {
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SEG_REMAP_ON);
if (ret < 0)
return ret;
};
/* Set COM direction */
com_invdir = 0xc0 | (par->com_invdir & 0x1) << 3;
- ret = ssd1307fb_write_cmd(par->client, com_invdir);
+ ret = ssd1307fb_write_cmd(par, com_invdir);
if (ret < 0)
return ret;
/* Set multiplex ratio value */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_MULTIPLEX_RATIO);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, par->height - 1);
+ ret = ssd1307fb_write_cmd(par, par->height - 1);
if (ret < 0)
return ret;
/* set display offset value */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_DISPLAY_OFFSET);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, par->com_offset);
+ ret = ssd1307fb_write_cmd(par, par->com_offset);
if (ret < 0)
return ret;
/* Set clock frequency */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_CLOCK_FREQ);
if (ret < 0)
return ret;
dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4;
- ret = ssd1307fb_write_cmd(par->client, dclk);
+ ret = ssd1307fb_write_cmd(par, dclk);
if (ret < 0)
return ret;
/* Set precharge period in number of ticks from the internal clock */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_PRECHARGE_PERIOD);
if (ret < 0)
return ret;
precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
- ret = ssd1307fb_write_cmd(par->client, precharge);
+ ret = ssd1307fb_write_cmd(par, precharge);
if (ret < 0)
return ret;
/* Set COM pins configuration */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_COM_PINS_CONFIG);
if (ret < 0)
return ret;
compins = 0x02 | !(par->com_seq & 0x1) << 4
| (par->com_lrremap & 0x1) << 5;
- ret = ssd1307fb_write_cmd(par->client, compins);
+ ret = ssd1307fb_write_cmd(par, compins);
if (ret < 0)
return ret;
/* Set VCOMH */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_VCOMH);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, par->vcomh);
+ ret = ssd1307fb_write_cmd(par, par->vcomh);
if (ret < 0)
return ret;
/* Turn on the DC-DC Charge Pump */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_CHARGE_PUMP);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client,
+ ret = ssd1307fb_write_cmd(par,
BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0));
if (ret < 0)
return ret;
/* Switch to horizontal addressing mode */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_ADDRESS_MODE);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client,
+ ret = ssd1307fb_write_cmd(par,
SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
if (ret < 0)
return ret;
/* Set column range */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_COL_RANGE);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x0);
+ ret = ssd1307fb_write_cmd(par, 0x0);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, par->width - 1);
+ ret = ssd1307fb_write_cmd(par, par->width - 1);
if (ret < 0)
return ret;
/* Set page range */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_SET_PAGE_RANGE);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x0);
+ ret = ssd1307fb_write_cmd(par, 0x0);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client,
+ ret = ssd1307fb_write_cmd(par,
par->page_offset + (par->height / 8) - 1);
if (ret < 0)
return ret;
/* Turn on the display */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
+ ret = ssd1307fb_write_cmd(par, SSD1307FB_DISPLAY_ON);
if (ret < 0)
return ret;
@@ -379,28 +410,37 @@ static const struct of_device_id ssd1307fb_of_match[] = {
.data = (void *)&ssd1307fb_ssd1306_deviceinfo,
},
{
+ /*
+ * The compatible of the SPI connected ssd1306 is not
+ * documented as device tree binding.
+ */
+ .compatible = "solomon,ssd1306",
+ .data = (void *)&ssd1307fb_ssd1306_deviceinfo,
+ },
+ {
.compatible = "solomon,ssd1309fb-i2c",
.data = (void *)&ssd1307fb_ssd1309_deviceinfo,
},
{},
};
+MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
-static int ssd1307fb_probe(struct device_d *dev)
+static int ssd1307fb_probe(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
struct fb_info *info;
- struct device_node *node = dev->device_node;
+ struct device_node *node = dev->of_node;
const struct of_device_id *match =
- of_match_node(ssd1307fb_of_match, dev->device_node);
+ of_match_node(ssd1307fb_of_match, dev->of_node);
u32 vmem_size;
struct ssd1307fb_par *par;
struct ssd1307fb_array *array;
- u8 *vmem;
+ u8 *vmem = NULL;
+ enum of_gpio_flags of_flags;
int ret;
int i, j;
if (!node) {
- dev_err(&client->dev, "No device tree data found!\n");
+ dev_err(dev, "No device tree data found!\n");
return -EINVAL;
}
@@ -409,33 +449,47 @@ static int ssd1307fb_probe(struct device_d *dev)
info->priv = par;
par->info = info;
- par->client = client;
par->device_info = (struct ssd1307fb_deviceinfo *)match->data;
- par->reset = of_get_named_gpio(node,
- "reset-gpios", 0);
+ if (dev_bus_is_i2c(dev)) {
+ par->client = to_i2c_client(dev);
+ i2c_set_clientdata(par->client, par);
+ par->write_array = ssd1307fb_i2c_write_array;
+ }
+ if (dev_bus_is_spi(dev)) {
+ par->spi = to_spi_device(dev);
+ par->dc = of_get_named_gpio(node, "dc-gpios", 0);
+ if (!gpio_is_valid(par->dc)) {
+ ret = par->dc;
+ goto fb_alloc_error;
+ }
+ par->write_array = ssd1307fb_spi_write_array;
+ }
+
+ par->reset = of_get_named_gpio_flags(node,
+ "reset-gpios", 0, &of_flags);
if (!gpio_is_valid(par->reset) && par->reset == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto fb_alloc_error;
}
- par->vbat = regulator_get(&client->dev, "vbat-supply");
+ par->vbat = regulator_get(dev, "vbat");
if (IS_ERR(par->vbat)) {
- dev_info(&client->dev, "Will not use VBAT");
+ dev_info(dev, "Will not use VBAT");
par->vbat = NULL;
}
ret = of_property_read_u32(node, "solomon,width", &par->width);
if (ret) {
- dev_err(&client->dev,
+ dev_err(dev,
"Couldn't find 'solomon,width' in device tree.\n");
goto panel_init_error;
}
ret = of_property_read_u32(node, "solomon,height", &par->height);
if (ret) {
- dev_err(&client->dev,
+ dev_err(dev,
"Couldn't find 'solomon,height' in device tree.\n");
goto panel_init_error;
}
@@ -443,7 +497,7 @@ static int ssd1307fb_probe(struct device_d *dev)
ret = of_property_read_u32(node, "solomon,page-offset",
&par->page_offset);
if (ret) {
- dev_err(&client->dev,
+ dev_err(dev,
"Couldn't find 'solomon,page_offset' in device tree.\n");
goto panel_init_error;
}
@@ -476,7 +530,7 @@ static int ssd1307fb_probe(struct device_d *dev)
vmem = malloc(vmem_size);
if (!vmem) {
- dev_err(&client->dev, "Couldn't allocate graphical memory.\n");
+ dev_err(dev, "Couldn't allocate graphical memory.\n");
ret = -ENOMEM;
goto fb_alloc_error;
}
@@ -500,11 +554,14 @@ static int ssd1307fb_probe(struct device_d *dev)
info->screen_base = (u8 __force __iomem *)vmem;
if (par->reset >= 0) {
- ret = gpio_request_one(par->reset,
- GPIOF_OUT_INIT_HIGH,
- "oled-reset");
+ unsigned long flags = GPIOF_OUT_INIT_ACTIVE;
+
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ ret = gpio_request_one(par->reset, flags, "oled-reset");
if (ret) {
- dev_err(&client->dev,
+ dev_err(dev,
"failed to request gpio %d: %d\n",
par->reset, ret);
goto reset_oled_error;
@@ -515,11 +572,9 @@ static int ssd1307fb_probe(struct device_d *dev)
if (ret < 0)
goto reset_oled_error;
- i2c_set_clientdata(client, info);
-
if (par->reset > 0) {
/* Reset the screen */
- gpio_set_value(par->reset, 0);
+ gpio_set_active(par->reset, 1);
udelay(4);
}
@@ -531,7 +586,7 @@ static int ssd1307fb_probe(struct device_d *dev)
mdelay(100);
if (par->reset > 0) {
- gpio_set_value(par->reset, 1);
+ gpio_set_active(par->reset, 0);
udelay(4);
}
@@ -539,9 +594,10 @@ static int ssd1307fb_probe(struct device_d *dev)
if (ret)
goto reset_oled_error;
+ info->dev.parent = dev;
ret = register_framebuffer(info);
if (ret) {
- dev_err(&client->dev, "Couldn't register the framebuffer\n");
+ dev_err(dev, "Couldn't register the framebuffer\n");
goto panel_init_error;
}
@@ -560,10 +616,10 @@ static int ssd1307fb_probe(struct device_d *dev)
}
}
- ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
+ par->write_array(par, array, par->width * par->height / 8);
kfree(array);
- dev_info(&client->dev,
+ dev_info(dev,
"ssd1307 framebuffer device registered, using %d bytes of video memory\n",
vmem_size);
@@ -579,9 +635,16 @@ fb_alloc_error:
return ret;
}
-static struct driver_d ssd1307fb_driver = {
- .name = "ssd1307fb",
+static __maybe_unused struct driver ssd1307fb_i2c_driver = {
+ .name = "ssd1307fb-i2c",
+ .probe = ssd1307fb_probe,
+ .of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match),
+};
+device_i2c_driver(ssd1307fb_i2c_driver);
+
+static __maybe_unused struct driver ssd1307fb_spi_driver = {
+ .name = "ssd1307fb-spi",
.probe = ssd1307fb_probe,
.of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match),
};
-device_i2c_driver(ssd1307fb_driver);
+device_spi_driver(ssd1307fb_spi_driver);
diff --git a/drivers/video/stm.c b/drivers/video/stm.c
index d4a618fe50..917405ea80 100644
--- a/drivers/video/stm.c
+++ b/drivers/video/stm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2010 Juergen Beisert, Pengutronix <jbe@pengutronix.de>
*
@@ -6,16 +7,6 @@
*
* Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <common.h>
#include <init.h>
@@ -29,7 +20,7 @@
#include <stmp-device.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <mach/fb.h>
+#include <mach/mxs/fb.h>
#define HW_LCDIF_CTRL 0x00
# define CTRL_SFTRST (1 << 31)
@@ -148,7 +139,7 @@ struct imxfb_info {
void __iomem *base;
unsigned memory_size;
struct fb_info info;
- struct device_d *hw_dev;
+ struct device *hw_dev;
struct clk *clk;
void *fixed_screen;
unsigned fixed_screen_size;
@@ -503,7 +494,7 @@ static struct imxfb_info fbi = {
},
};
-static int stmfb_probe(struct device_d *hw_dev)
+static int stmfb_probe(struct device *hw_dev)
{
struct resource *iores;
struct imx_fb_platformdata *pdata = hw_dev->platform_data;
@@ -541,10 +532,10 @@ static int stmfb_probe(struct device_d *hw_dev)
struct display_timings *modes;
struct device_node *display;
- if (!IS_ENABLED(CONFIG_OFDEVICE) || !hw_dev->device_node)
+ if (!IS_ENABLED(CONFIG_OFDEVICE) || !hw_dev->of_node)
return -EINVAL;
- display = of_parse_phandle(hw_dev->device_node, "display", 0);
+ display = of_parse_phandle(hw_dev->of_node, "display", 0);
if (!display) {
dev_err(hw_dev, "no display phandle\n");
return -EINVAL;
@@ -571,6 +562,7 @@ static int stmfb_probe(struct device_d *hw_dev)
fb_of_reserve_add_fixup(&fbi.info);
+ fbi.info.dev.parent = hw_dev;
ret = register_framebuffer(&fbi.info);
if (ret != 0) {
dev_err(hw_dev, "Failed to register framebuffer\n");
@@ -589,8 +581,9 @@ static __maybe_unused struct of_device_id stmfb_compatible[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, stmfb_compatible);
-static struct driver_d stmfb_driver = {
+static struct driver stmfb_driver = {
.name = "stmfb",
.probe = stmfb_probe,
.of_compatible = DRV_OF_COMPAT(stmfb_compatible),
diff --git a/drivers/video/stm32_ltdc.c b/drivers/video/stm32_ltdc.c
new file mode 100644
index 0000000000..d1c36b1f45
--- /dev/null
+++ b/drivers/video/stm32_ltdc.c
@@ -0,0 +1,337 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017-2018 STMicroelectronics - All Rights Reserved
+ * Author(s): Philippe Cornu <philippe.cornu@st.com> for STMicroelectronics.
+ * Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
+ * Ahmad Fatoum <a.fatoum@pengutronix.de>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <io.h>
+#include <fb.h>
+#include <dma.h>
+#include <video/media-bus-format.h>
+#include <video/vpl.h>
+#include <of_graph.h>
+
+#include "stm32_ltdc.h"
+
+struct ltdc_hw {
+ void __iomem *regs;
+ struct device *dev;
+ struct clk *pclk;
+ bool claimed;
+};
+
+struct ltdc_fb {
+ int id;
+ struct fb_info info;
+ u32 bg_col_argb;
+ u32 alpha;
+ u32 bus_format;
+ enum stm32_ltdc_pixfmt pixfmt;
+ struct vpl vpl;
+ struct ltdc_hw *hw;
+};
+
+static bool has_alpha(enum stm32_ltdc_pixfmt pixfmt)
+{
+ switch (pixfmt) {
+ case PF_ARGB8888:
+ case PF_ARGB1555:
+ case PF_ARGB4444:
+ case PF_AL44:
+ case PF_AL88:
+ return true;
+ case PF_RGB888:
+ case PF_RGB565:
+ case PF_L8:
+ default:
+ return false;
+ }
+}
+
+static void ltdc_set_mode(struct ltdc_fb *priv,
+ struct fb_videomode *mode)
+{
+ void __iomem *regs = priv->hw->regs;
+ u32 hsync, vsync, acc_hbp, acc_vbp, acc_act_w, acc_act_h;
+ u32 total_w, total_h;
+ u32 val;
+
+ /* Convert video timings to ltdc timings */
+ hsync = mode->hsync_len - 1;
+ vsync = mode->vsync_len - 1;
+ acc_hbp = hsync + mode->left_margin;
+ acc_vbp = vsync + mode->upper_margin;
+ acc_act_w = acc_hbp + mode->xres;
+ acc_act_h = acc_vbp + mode->yres;
+ total_w = acc_act_w + mode->right_margin;
+ total_h = acc_act_h + mode->lower_margin;
+
+ /* Synchronization sizes */
+ val = (hsync << 16) | vsync;
+ clrsetbits_le32(regs + LTDC_SSCR, SSCR_VSH | SSCR_HSW, val);
+
+ /* Accumulated back porch */
+ val = (acc_hbp << 16) | acc_vbp;
+ clrsetbits_le32(regs + LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val);
+
+ /* Accumulated active width */
+ val = (acc_act_w << 16) | acc_act_h;
+ clrsetbits_le32(regs + LTDC_AWCR, AWCR_AAW | AWCR_AAH, val);
+
+ /* Total width & height */
+ val = (total_w << 16) | total_h;
+ clrsetbits_le32(regs + LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val);
+
+ setbits_le32(regs + LTDC_LIPCR, acc_act_h + 1);
+
+ /* Signal polarities */
+ val = 0;
+ dev_dbg(priv->hw->dev, "mode->display_flags 0x%x mode->sync 0x%x\n",
+ mode->display_flags, mode->sync);
+ if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+ val |= GCR_HSPOL;
+ if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+ val |= GCR_VSPOL;
+ if (mode->display_flags & DISPLAY_FLAGS_DE_LOW)
+ val |= GCR_DEPOL;
+ if (mode->display_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ val |= GCR_PCPOL;
+
+ clrsetbits_le32(regs + LTDC_GCR,
+ GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val);
+
+ /* Overall background color */
+ writel(priv->bg_col_argb, regs + LTDC_BCCR);
+}
+
+static void ltdc_set_layer1(struct ltdc_fb *priv)
+{
+ void __iomem *regs = priv->hw->regs;
+ u32 x0, x1, y0, y1;
+ u32 pitch_in_bytes;
+ u32 line_length;
+ u32 bus_width;
+ u32 val, tmp, bpp;
+ struct fb_videomode *mode = priv->info.mode;
+
+ x0 = y0 = 0;
+ x1 = mode->xres - 1;
+ y1 = mode->yres - 1;
+
+ /* Horizontal start and stop position */
+ tmp = (readl(regs + LTDC_BPCR) & BPCR_AHBP) >> 16;
+ val = ((x1 + 1 + tmp) << 16) + (x0 + 1 + tmp);
+ clrsetbits_le32(regs + LTDC_L1WHPCR, LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS,
+ val);
+
+ /* Vertical start & stop position */
+ tmp = readl(regs + LTDC_BPCR) & BPCR_AVBP;
+ val = ((y1 + 1 + tmp) << 16) + (y0 + 1 + tmp);
+ clrsetbits_le32(regs + LTDC_L1WVPCR, LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS,
+ val);
+
+ /* Layer background color */
+ writel(priv->bg_col_argb, regs + LTDC_L1DCCR);
+
+ /* Color frame buffer pitch in bytes & line length */
+ bpp = priv->info.bits_per_pixel;
+ pitch_in_bytes = mode->xres * (bpp >> 3);
+ bus_width = 8 << ((readl(regs + LTDC_GC2R) & GC2R_BW) >> 4);
+ line_length = ((bpp >> 3) * mode->xres) + (bus_width >> 3) - 1;
+ val = (pitch_in_bytes << 16) | line_length;
+ clrsetbits_le32(regs + LTDC_L1CFBLR, LXCFBLR_CFBLL | LXCFBLR_CFBP, val);
+
+ /* Pixel format */
+ clrsetbits_le32(regs + LTDC_L1PFCR, LXPFCR_PF, priv->pixfmt);
+
+ /* Constant alpha value */
+ clrsetbits_le32(regs + LTDC_L1CACR, LXCACR_CONSTA, priv->alpha);
+
+ /* Specifies the blending factors : with or without pixel alpha */
+ /* Manage hw-specific capabilities */
+ val = has_alpha(priv->pixfmt) ? BF1_PAXCA | BF2_1PAXCA : BF1_CA | BF2_1CA;
+
+ /* Blending factors */
+ clrsetbits_le32(regs + LTDC_L1BFCR, LXBFCR_BF2 | LXBFCR_BF1, val);
+
+ /* Frame buffer line number */
+ clrsetbits_le32(regs + LTDC_L1CFBLNR, LXCFBLNR_CFBLN, mode->yres);
+
+ /* Frame buffer address */
+ writel((unsigned long)priv->info.screen_base, regs + LTDC_L1CFBAR);
+
+ /* Enable layer 1 */
+ setbits_le32(regs + LTDC_L1CR, LXCR_LEN);
+}
+
+static int ltdc_activate_var(struct fb_info *info)
+{
+ info->line_length = info->xres * (info->bits_per_pixel >> 3);
+
+ info->screen_base = dma_alloc_writecombine(info->line_length * info->yres,
+ DMA_ADDRESS_BROKEN);
+ if (!info->screen_base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void ltdc_enable(struct fb_info *info)
+{
+ struct fb_videomode *mode = info->mode;
+ struct ltdc_fb *priv = info->priv;
+ struct ltdc_hw *hw = priv->hw;
+ u32 pixclock;
+ int ret;
+
+ if (hw->claimed) {
+ dev_warn(hw->dev, "CRTC currently claimed by other frame buffer!\n");
+ return;
+ }
+
+ vpl_ioctl_prepare(&priv->vpl, priv->id, mode);
+
+ pixclock = PICOS2KHZ(mode->pixclock) * 1000;
+
+ ret = clk_enable(hw->pclk);
+ if (ret) {
+ dev_err(hw->dev, "peripheral clock enable error %d\n", ret);
+ return;
+ }
+
+ clk_set_rate(clk_get_parent(hw->pclk), pixclock);
+ if (!ret)
+ ret = clk_set_rate(hw->pclk, pixclock);
+ if (ret < 0) {
+ dev_err(hw->dev, "fail to set pixel clock %d hz: %d\n",
+ pixclock, ret);
+ return;
+ }
+
+ ret = device_reset_us(hw->dev, 100000);
+ if (ret) {
+ dev_err(hw->dev, "error resetting controller %d\n", ret);
+ return;
+ }
+
+ /* Configure & start LTDC */
+ ltdc_set_mode(priv, mode);
+ ltdc_set_layer1(priv);
+
+ /* Reload configuration immediately & enable LTDC */
+ setbits_le32(hw->regs + LTDC_SRCR, SRCR_IMR);
+ setbits_le32(hw->regs + LTDC_GCR, GCR_LTDCEN);
+
+ vpl_ioctl_enable(&priv->vpl, priv->id);
+
+ hw->claimed = true;
+}
+
+static void ltdc_disable(struct fb_info *info)
+{
+ struct ltdc_fb *priv = info->priv;
+
+ vpl_ioctl_disable(&priv->vpl, priv->id);
+
+ clrbits_le32(priv->hw->regs + LTDC_GCR, GCR_LTDCEN);
+ clk_disable(priv->hw->pclk);
+ priv->hw->claimed = false;
+
+ vpl_ioctl_unprepare(&priv->vpl, priv->id);
+}
+
+static struct fb_ops ltdc_ops = {
+ .fb_activate_var = ltdc_activate_var,
+ .fb_enable = ltdc_enable,
+ .fb_disable = ltdc_disable,
+};
+
+static int ltdc_probe(struct device *dev)
+{
+ struct device_node *np;
+ struct resource *iores;
+ struct ltdc_hw *hw;
+ int ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ hw = xzalloc(sizeof *hw);
+ hw->dev = dev;
+ hw->regs = IOMEM(iores->start);
+
+ hw->pclk = clk_get(dev, NULL);
+ if (IS_ERR(hw->pclk)) {
+ dev_err(dev, "peripheral clock get error %d\n", ret);
+ return PTR_ERR(hw->pclk);
+ }
+
+ for_each_available_child_of_node(dev->of_node, np) {
+ struct ltdc_fb *priv;
+ struct of_endpoint ep;
+ struct fb_info *info;
+
+ if (!of_graph_port_is_available(np))
+ continue;
+
+ ret = of_graph_parse_endpoint(np, &ep);
+ if (ret)
+ return ret;
+
+ dev_dbg(hw->dev, "register vpl for %pOF\n", np);
+
+ priv = xzalloc(sizeof(*priv));
+ priv->hw = hw;
+ priv->id = ep.id;
+ priv->vpl.node = dev->of_node;
+
+ ret = vpl_register(&priv->vpl);
+ if (ret)
+ return ret;
+
+ info = &priv->info;
+ info->priv = priv;
+ info->fbops = &ltdc_ops;
+
+ info->red = (struct fb_bitfield){ .offset = 11, .length = 5, };
+ info->green = (struct fb_bitfield){ .offset = 5, .length = 6, };
+ info->blue = (struct fb_bitfield){ .offset = 0, .length = 5, };
+ info->bits_per_pixel = 16,
+ priv->pixfmt = PF_RGB565;
+ /* TODO Below parameters are hard-coded for the moment... */
+ priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */
+ priv->alpha = 0xFF;
+
+ ret = vpl_ioctl(&priv->vpl, priv->id, VPL_GET_VIDEOMODES, &info->modes);
+ if (ret)
+ dev_dbg(dev, "failed to get modes: %s\n", strerror(-ret));
+
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(dev, "failed to register framebuffer\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id ltdc_ids[] = {
+ { .compatible = "st,stm32-ltdc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ltdc_ids);
+
+static struct driver ltdc_driver = {
+ .name = "stm32-ltdc",
+ .probe = ltdc_probe,
+ .of_compatible = DRV_OF_COMPAT(ltdc_ids),
+};
+device_platform_driver(ltdc_driver);
diff --git a/drivers/video/stm32_ltdc.h b/drivers/video/stm32_ltdc.h
new file mode 100644
index 0000000000..6481f2613b
--- /dev/null
+++ b/drivers/video/stm32_ltdc.h
@@ -0,0 +1,130 @@
+#ifndef STM32_LTDC_H__
+#define STM32_LTDC_H__
+
+/* LTDC main registers */
+#define LTDC_IDR 0x00 /* IDentification */
+#define LTDC_LCR 0x04 /* Layer Count */
+#define LTDC_SSCR 0x08 /* Synchronization Size Configuration */
+#define LTDC_BPCR 0x0C /* Back Porch Configuration */
+#define LTDC_AWCR 0x10 /* Active Width Configuration */
+#define LTDC_TWCR 0x14 /* Total Width Configuration */
+#define LTDC_GCR 0x18 /* Global Control */
+#define LTDC_GC1R 0x1C /* Global Configuration 1 */
+#define LTDC_GC2R 0x20 /* Global Configuration 2 */
+#define LTDC_SRCR 0x24 /* Shadow Reload Configuration */
+#define LTDC_GACR 0x28 /* GAmma Correction */
+#define LTDC_BCCR 0x2C /* Background Color Configuration */
+#define LTDC_IER 0x34 /* Interrupt Enable */
+#define LTDC_ISR 0x38 /* Interrupt Status */
+#define LTDC_ICR 0x3C /* Interrupt Clear */
+#define LTDC_LIPCR 0x40 /* Line Interrupt Position Conf. */
+#define LTDC_CPSR 0x44 /* Current Position Status */
+#define LTDC_CDSR 0x48 /* Current Display Status */
+
+/* LTDC layer 1 registers */
+#define LTDC_L1LC1R 0x80 /* L1 Layer Configuration 1 */
+#define LTDC_L1LC2R 0x84 /* L1 Layer Configuration 2 */
+#define LTDC_L1CR 0x84 /* L1 Control */
+#define LTDC_L1WHPCR 0x88 /* L1 Window Hor Position Config */
+#define LTDC_L1WVPCR 0x8C /* L1 Window Vert Position Config */
+#define LTDC_L1CKCR 0x90 /* L1 Color Keying Configuration */
+#define LTDC_L1PFCR 0x94 /* L1 Pixel Format Configuration */
+#define LTDC_L1CACR 0x98 /* L1 Constant Alpha Config */
+#define LTDC_L1DCCR 0x9C /* L1 Default Color Configuration */
+#define LTDC_L1BFCR 0xA0 /* L1 Blend Factors Configuration */
+#define LTDC_L1FBBCR 0xA4 /* L1 FrameBuffer Bus Control */
+#define LTDC_L1AFBCR 0xA8 /* L1 AuxFB Control */
+#define LTDC_L1CFBAR 0xAC /* L1 Color FrameBuffer Address */
+#define LTDC_L1CFBLR 0xB0 /* L1 Color FrameBuffer Length */
+#define LTDC_L1CFBLNR 0xB4 /* L1 Color FrameBuffer Line Nb */
+#define LTDC_L1AFBAR 0xB8 /* L1 AuxFB Address */
+#define LTDC_L1AFBLR 0xBC /* L1 AuxFB Length */
+#define LTDC_L1AFBLNR 0xC0 /* L1 AuxFB Line Number */
+#define LTDC_L1CLUTWR 0xC4 /* L1 CLUT Write */
+
+/* Bit definitions */
+#define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */
+#define SSCR_HSW GENMASK(27, 16) /* Horizontal Synchronization Width */
+
+#define BPCR_AVBP GENMASK(10, 0) /* Accumulated Vertical Back Porch */
+#define BPCR_AHBP GENMASK(27, 16) /* Accumulated Horizontal Back Porch */
+
+#define AWCR_AAH GENMASK(10, 0) /* Accumulated Active Height */
+#define AWCR_AAW GENMASK(27, 16) /* Accumulated Active Width */
+
+#define TWCR_TOTALH GENMASK(10, 0) /* TOTAL Height */
+#define TWCR_TOTALW GENMASK(27, 16) /* TOTAL Width */
+
+#define GCR_LTDCEN BIT(0) /* LTDC ENable */
+#define GCR_DEN BIT(16) /* Dither ENable */
+#define GCR_PCPOL BIT(28) /* Pixel Clock POLarity-Inverted */
+#define GCR_DEPOL BIT(29) /* Data Enable POLarity-High */
+#define GCR_VSPOL BIT(30) /* Vertical Synchro POLarity-High */
+#define GCR_HSPOL BIT(31) /* Horizontal Synchro POLarity-High */
+
+#define GC1R_WBCH GENMASK(3, 0) /* Width of Blue CHannel output */
+#define GC1R_WGCH GENMASK(7, 4) /* Width of Green Channel output */
+#define GC1R_WRCH GENMASK(11, 8) /* Width of Red Channel output */
+#define GC1R_PBEN BIT(12) /* Precise Blending ENable */
+#define GC1R_DT GENMASK(15, 14) /* Dithering Technique */
+#define GC1R_GCT GENMASK(19, 17) /* Gamma Correction Technique */
+#define GC1R_SHREN BIT(21) /* SHadow Registers ENabled */
+#define GC1R_BCP BIT(22) /* Background Colour Programmable */
+#define GC1R_BBEN BIT(23) /* Background Blending ENabled */
+#define GC1R_LNIP BIT(24) /* Line Number IRQ Position */
+#define GC1R_TP BIT(25) /* Timing Programmable */
+#define GC1R_IPP BIT(26) /* IRQ Polarity Programmable */
+#define GC1R_SPP BIT(27) /* Sync Polarity Programmable */
+#define GC1R_DWP BIT(28) /* Dither Width Programmable */
+#define GC1R_STREN BIT(29) /* STatus Registers ENabled */
+#define GC1R_BMEN BIT(31) /* Blind Mode ENabled */
+
+#define GC2R_EDCA BIT(0) /* External Display Control Ability */
+#define GC2R_STSAEN BIT(1) /* Slave Timing Sync Ability ENabled */
+#define GC2R_DVAEN BIT(2) /* Dual-View Ability ENabled */
+#define GC2R_DPAEN BIT(3) /* Dual-Port Ability ENabled */
+#define GC2R_BW GENMASK(6, 4) /* Bus Width (log2 of nb of bytes) */
+#define GC2R_EDCEN BIT(7) /* External Display Control ENabled */
+
+#define SRCR_IMR BIT(0) /* IMmediate Reload */
+#define SRCR_VBR BIT(1) /* Vertical Blanking Reload */
+
+#define LXCR_LEN BIT(0) /* Layer ENable */
+#define LXCR_COLKEN BIT(1) /* Color Keying Enable */
+#define LXCR_CLUTEN BIT(4) /* Color Look-Up Table ENable */
+
+#define LXWHPCR_WHSTPOS GENMASK(11, 0) /* Window Horizontal StarT POSition */
+#define LXWHPCR_WHSPPOS GENMASK(27, 16) /* Window Horizontal StoP POSition */
+
+#define LXWVPCR_WVSTPOS GENMASK(10, 0) /* Window Vertical StarT POSition */
+#define LXWVPCR_WVSPPOS GENMASK(26, 16) /* Window Vertical StoP POSition */
+
+#define LXPFCR_PF GENMASK(2, 0) /* Pixel Format */
+
+#define LXCACR_CONSTA GENMASK(7, 0) /* CONSTant Alpha */
+
+#define LXBFCR_BF2 GENMASK(2, 0) /* Blending Factor 2 */
+#define LXBFCR_BF1 GENMASK(10, 8) /* Blending Factor 1 */
+
+#define LXCFBLR_CFBLL GENMASK(12, 0) /* Color Frame Buffer Line Length */
+#define LXCFBLR_CFBP GENMASK(28, 16) /* Color Frame Buffer Pitch in bytes */
+
+#define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */
+
+#define BF1_PAXCA 0x600 /* Pixel Alpha x Constant Alpha */
+#define BF1_CA 0x400 /* Constant Alpha */
+#define BF2_1PAXCA 0x007 /* 1 - (Pixel Alpha x Constant Alpha) */
+#define BF2_1CA 0x005 /* 1 - Constant Alpha */
+
+enum stm32_ltdc_pixfmt {
+ PF_ARGB8888 = 0,
+ PF_RGB888,
+ PF_RGB565,
+ PF_ARGB1555,
+ PF_ARGB4444,
+ PF_L8,
+ PF_AL44,
+ PF_AL88
+};
+
+#endif
diff --git a/drivers/video/tc358767.c b/drivers/video/tc358767.c
index e64dde1ddf..da106496fc 100644
--- a/drivers/video/tc358767.c
+++ b/drivers/video/tc358767.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* tc358767 eDP encoder driver
*
@@ -7,16 +8,6 @@
* Copyright (C) 2016 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
*
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <common.h>
@@ -31,7 +22,7 @@
#include <of_gpio.h>
#include <video/media-bus-format.h>
#include <video/vpl.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
#define DP_LINK_BW_SET 0x100
#define DP_ENHANCED_FRAME_EN (1 << 7)
@@ -213,7 +204,7 @@ struct tc_edp_link {
struct tc_data {
struct i2c_client *client;
- struct device_d *dev;
+ struct device *dev;
/* DP AUX channel */
struct i2c_adapter adapter;
struct vpl vpl;
@@ -889,7 +880,7 @@ err:
static int tc_main_link_setup(struct tc_data *tc)
{
- struct device_d *dev = tc->dev;
+ struct device *dev = tc->dev;
unsigned int rate;
u32 dp_phy_ctrl;
int timeout;
@@ -1191,8 +1182,7 @@ static int tc_read_edid(struct tc_data *tc)
#ifdef DEBUG
printk(KERN_DEBUG "eDP display EDID:\n");
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, tc->edid,
- EDID_LENGTH, true);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, tc->edid, EDID_LENGTH);
#endif
return 0;
@@ -1344,7 +1334,7 @@ static int tc_ioctl(struct vpl *vpl, unsigned int port,
return ret;
}
-static int tc_probe(struct device_d *dev)
+static int tc_probe(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct tc_data *tc;
@@ -1357,16 +1347,16 @@ static int tc_probe(struct device_d *dev)
tc->dev = dev;
/* Shut down GPIO is optional */
- tc->sd_gpio = of_get_named_gpio_flags(dev->device_node,
- "shutdown-gpios", 0, &flags);
+ tc->sd_gpio = of_get_named_gpio_flags(dev->of_node,
+ "shutdown-gpios", 0, &flags);
if (gpio_is_valid(tc->sd_gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
tc->sd_active_high = 1;
}
/* Reset GPIO is optional */
- tc->reset_gpio = of_get_named_gpio_flags(dev->device_node,
- "reset-gpios", 0, &flags);
+ tc->reset_gpio = of_get_named_gpio_flags(dev->of_node,
+ "reset-gpios", 0, &flags);
if (gpio_is_valid(tc->reset_gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
tc->reset_active_high = 1;
@@ -1381,7 +1371,7 @@ static int tc_probe(struct device_d *dev)
gpio_direction_output(tc->sd_gpio, 0);
}
- tc->refclk = of_clk_get_by_name(dev->device_node, "ref");
+ tc->refclk = of_clk_get_by_name(dev->of_node, "ref");
if (IS_ERR(tc->refclk)) {
ret = PTR_ERR(tc->refclk);
dev_err(dev, "Failed to get refclk: %d\n", ret);
@@ -1420,7 +1410,7 @@ static int tc_probe(struct device_d *dev)
}
/* add vlp */
- tc->vpl.node = dev->device_node;
+ tc->vpl.node = dev->of_node;
tc->vpl.ioctl = tc_ioctl;
return vpl_register(&tc->vpl);
@@ -1429,7 +1419,7 @@ err:
return ret;
}
-static struct driver_d tc_driver = {
+static struct driver tc_driver = {
.name = "tc358767",
.probe = tc_probe,
};
diff --git a/drivers/video/vpl.c b/drivers/video/vpl.c
index 82ceeebada..f8c2159cd9 100644
--- a/drivers/video/vpl.c
+++ b/drivers/video/vpl.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Video pipeline (VPL) support for barebox
*
* (C) Copyright 2014 Sascha Hauer, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#define pr_fmt(fmt) "VPL: " fmt
@@ -31,7 +18,7 @@ int vpl_register(struct vpl *vpl)
{
list_add_tail(&vpl->list, &vpls);
- pr_debug("%s: %s\n", __func__, vpl->node->full_name);
+ pr_debug("%s: %pOF\n", __func__, vpl->node);
return 0;
}
@@ -53,13 +40,13 @@ struct vpl *of_vpl_get(struct device_node *node, int port)
if (!node)
return NULL;
- pr_debug("%s: port: %s\n", __func__, node->full_name);
+ pr_debug("%s: port: %pOF\n", __func__, node);
node = of_graph_get_remote_port_parent(node);
if (!node)
return NULL;
- pr_debug("%s: remote port parent: %s\n", __func__, node->full_name);
+ pr_debug("%s: remote port parent: %pOF\n", __func__, node);
return of_find_vpl(node);
}
@@ -70,11 +57,11 @@ int vpl_ioctl(struct vpl *vpl, unsigned int port,
struct device_node *node, *endpoint;
int ret;
- pr_debug("%s: %s port %d\n", __func__, vpl->node->full_name, port);
+ pr_debug("%s: %pOF port %d\n", __func__, vpl->node, port);
node = of_graph_get_port_by_id(vpl->node, port);
if (!node) {
- pr_err("%s: no port %d on %s\n", __func__, port, vpl->node->full_name);
+ pr_err("%s: no port %d on %pOF\n", __func__, port, vpl->node);
return -ENODEV;
}
@@ -85,7 +72,7 @@ int vpl_ioctl(struct vpl *vpl, unsigned int port,
remote = of_graph_get_remote_port(endpoint);
if (!remote) {
- pr_debug("%s: no remote for endpoint %s\n", __func__, endpoint->full_name);
+ pr_debug("%s: no remote for endpoint %pOF\n", __func__, endpoint);
continue;
}
@@ -102,10 +89,11 @@ int vpl_ioctl(struct vpl *vpl, unsigned int port,
remote_vpl = of_find_vpl(remote_parent);
if (!remote_vpl) {
- pr_debug("%s: cannot find remote vpl %s\n", __func__, remote->full_name);
+ pr_debug("%s: cannot find remote vpl %pOF\n", __func__, remote);
continue;
}
+ pr_debug("%s: looked up %pOF: %pS\n", __func__, remote, remote_vpl->ioctl);
ret = remote_vpl->ioctl(remote_vpl, remote_port_id, cmd, ptr);
if (ret)
return ret;